AXP209 proper driver?

Recommended Posts

I found relatively little information concerning AXP209 support on mainline.


My targets : 

- set the battery as 4.35V instead of 4.2V. Datasheet say it's set in REG 33H. Defaut value for register : 0xCX, X being the charge current. if 1200mAh then default value is 0xC9. To change from 4.2 to 4.35V, use EXh (so E9h if you'r using 1200mA) 11001001 to 11101001.)
- Remove boot when AC plugged in and boot only when PEK is pressed. Datasheet say it's possible is not clear about how to do it. It may be reg40 bit6. I could not test yet as REG40 strangely reads 0x00 with i2cget.
- Set GPIO0 and GPIO1 as ADC. GPIO0 function is REG 90H (see page 40 datasheet). GPIO1 function is REG 92H.
Defaut value for both registers : 0x07 (=0000 0111 bin) where bit 0-2 (111) are the function. We need replace with 100 bin for ADC function so 04h
Also need to enable GPIO ADC in REG 83H bit 2-3 too ! Default value 80H 1000 0000 replace with 8C 1000 1100.


First look

There are several topics about AXP209 management. However there are different different things and some look deprecated...

- Some people have been changing the REG values directly with i2Cset. 

- A Sysfs interface have been developped. But it's not clear whether it's deprecated or not.

- Apparantly there are "proper drivers" that have been added. But no mention of them anywhere. Nor how to use them to change things or get battery% or anything.


In this topic for example : 

Where @zador.blood.stained you say : 


Main purpose of this patch is creating a sysfs interface to get information from AXP202/209 PMU until proper power driver is implemented in mainline kernel.

At the time it was created it was the simplest way to get data from the PMIC or change some settings without using userspace tools like i2cget/i2cset or a custom code based on i2c libraries.

Newer kernels have received proper drivers - starting with 4.12 there is even a battery driver and an ADC IIO driver, but this patch still can be useful i.e. to enable/disable RTC battery changing on some boards.


Are you talking about this patch ? 


(Which is the one from your github? )


If so this patch is deprecated right? If yes then where are the proper drivers you are talking about and how to use them to get current battery voltage, capacity%...?





Link to post
Share on other sites
Donate and support the project!

I have been trying to do my own scrip to read/write directly reg values with i2C. But changing parameters with i2Cset are overwriten after reboot, probably by the current driver...



i2cset -y -f 0 0x34 0x33 0xE9 

This should change to 4.36V. This setting get reseted to 0xC9 but only when the unit boot on AC connection. Booting on PEK press does not reset it. Very strange.


i2cset -y -f 0 0x34 0x83 0x8C

This setting does not get reset!


i2cset -y -f 0 0x34 0x90 0x04
i2cset -y -f 0 0x34 0x92 0x04

Those two should set the GPIO 0 and 1 functions as ADC. Those don't work they keep reseting to 0x02 after any reboot (AC plugged in boot or PEK press boot)...


i2cget -y -f 0 0x34 0x40

This REG 40 should be a list of IRQ enabled. Someone suggested bit 6 to be the boot when AC plugged-in parameter. But very strangely the reg40 reads 0x00 instead of normal default value of 0xD8... Same for other IRQ REGs 41 and 42.


So this means the AXP209 driver is messing things up for us..!

Link to post
Share on other sites

I found several files about AXP on the torvalds github. Note: Megeous github (torvalds fork which is used for Armbian build if I am not mistaken) files are slightly different...


So the main driver seems to be this one:


Then there are several complementary-drivers :

Not 100% sure if these last c and txt files are related as there is no gpio-axp209.c nor pinctrl-axp209.txt so I think it's just naming issue.


Then on top of that you have a armbian patch of the main axp20X.c :






Or this one seems related but not sure it's included:

Link to post
Share on other sites

I found a problem with either armbian patch for AXP20X.c driver or with i2Cset too.



sudo i2cset -y -f 0 0x34 0x33 0xe9      #0x33 is AXP20X_CHRG_CTRL1. Value read with i2cget before is 0xc9
sudo i2cset -y -f 0 0x34 0x90 0x04      #0x90 is AXP20X_GPIO0_CTRL. Value read with i2cget before is is 0x02
sudo i2cset -y -f 0 0x34 0x92 0x04      #0x92 is AXP20X_GPIO1_CTRL. Value read with i2cget before is is 0x02

Change the register values correctly.

Then on reboot we have : 

sudo i2cget -y -f 0 0x34 0x33
sudo i2cget -y -f 0 0x34 0x90
sudo i2cget -y -f 0 0x34 0x92

0x90 and 0x92 reseted (0x33 reset only when booting when AC-plugged in power. Not when PEK pressed...). I check Dmesg and find one difference compared to normal boot without modifications: 

axp20x-i2c 0-0034: Battery detection is disabled, enabling

So I check the armbian patch of AXP20X.c and find this error message in this part of the code :

+	/* Enable battery detection */
+	ret = regmap_read(axp->regmap, AXP20X_OFF_CTRL, &res);
+	if (ret == 0) {
+		if ((res & 0x40) != 0x40) {
+			dev_info(axp->dev, "Battery detection is disabled, enabling");
+			ret = regmap_update_bits(axp->regmap, AXP20X_OFF_CTRL, 0x40, 0x40);
+			if (ret)
+				dev_warn(axp->dev, "Unable to enable battery detection: %d", ret);
+		}
+	} else
+		dev_warn(axp->dev, "Unable to read register AXP20X_OFF_CTRL: %d", ret);

interestingly the error is triggered after reading AXP20X_OFF_CTRL ( Reg 0x32)... Which is not one that I have been modifying??


I am not sure to understand what is going on there:

- Either the i2Cset/I2Cget tool is not working properly.

- Either something is wrong in the patch. But it looks correct as it uses AXP20X_OFF_CTRL which is 0x32 and change only bit 6 to 1.

- Either something is wrong with regmap?


Link to post
Share on other sites


Ok there's a page in bindings about this driver

There's even a armbian patch about this driver binding text :


but the driver itself cannot be found on github... 


maybe it's name changed to this one

if so why is there still a gpio-axp209.txt and a patch for this.

Link to post
Share on other sites

I found the reason why IRQ REG show 00 and why GPIO keep reseting... It's the u-boot driver for AXP209:


This files is giving me 2/3 of my troubles : 

	/* Mask all interrupts */
	for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
		rc = pmic_bus_write(i, 0);
		if (rc)
			return rc;

This is why REG 40 is 00...


	 * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
	 * from android these are sometimes on.
	rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
	if (rc)
		return rc;

	rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
	if (rc)
		return rc;

	rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
	if (rc)
		return rc;

Reset the 3 GPIO status...



Only the battery voltage error does not come from this. I think it probably comes from :

However I am not sure how the driver is getting executed. What is the calling sequence of it.

Link to post
Share on other sites

Also the uboot driver has a problem I think : 

int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
	pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);

	/* infinite loop during shutdown */
	while (1) {}

	/* not reached */
	return 0;
#define AXP209_POWEROFF			BIT(7)
AXP209_SHUTDOWN = 0x32

So actually on every power off, uboot write BIT(7) to REG 32. Now I understand why at boot the kernel AXP20x driver triggers to set battery detection ON as it's also on REG32.

It does not use mask to write only bit 7, so I guess it writes 1000 0000 to the REG...


I think it should use "pmic_bus_setbits" instead of "pmic_bus_write" what do you think? If someone can confirm this.



Link to post
Share on other sites
1 hour ago, PaddleStroke said:

Btw do you know how to make a bug report to u-boot?

Proper way is to send e-mail directly to all parties involved - author of that piece of the code, patch committer (these two can be found in signed-off tags), maintainer(s) of that subsystem and U-Boot mailing list ("scripts/ drivers/power/axp209.c" for last two).


While you can send patches to U-Boot ML (the one that Martin mentioned), you should register. Otherwise it will be moderated and delayed.

Link to post
Share on other sites

Regarding the uboot error I discussed before. Actually the kernel driver is doing exactly the same thing :


static void axp20x_power_off(void)
	if (axp20x_pm_power_off->variant == AXP288_ID)

	regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,

	/* Give capacitors etc. time to drain to avoid kernel panic msg. */

AXP20X_OFF = bit(7)

So it does the same thing. On shutdown it writes bit(7) on reg32.


The problem is when you boot after on PEK press, the AXP regs are not reset. So the reg32 is not set back to default value but keep instead bit(7). Which makes that battery detection is disabled.


Should be replaced by 


static void axp20x_power_off(void)
	if (axp20x_pm_power_off->variant == AXP288_ID)

	regmap_update_bits(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
		     AXP20X_OFF, AXP20X_OFF);

	/* Give capacitors etc. time to drain to avoid kernel panic msg. */

What do you think?

Link to post
Share on other sites
This topic is now closed to further replies.