[Letux-kernel] bq2429x automatic charging cycle

H. Nikolaus Schaller hns at goldelico.com
Sun Mar 28 18:14:06 CEST 2021

I always wondered if and how the bq2429x decides to start a new charging cycle.

Obviously it does if we plug in an USB power supply.

Alternatively the processor could start charging.

But isn't there an automatic mode to alternate battery charging and discharging cycles?

Yes, it is. The rules are a little strange (but understandable from how the chip works).

The first (and only) hint is this sentence in the data sheet:

	"Later on, when the battery voltage falls below the recharge threshold, the charger automatically starts another charging cycle. "

But what is the "recharge threshold"?

It is indirectly defined in the description of the bits of REG04.

	"Battery Recharge Threshold (below battery regulation voltage)" 

But there is only one bit:

	"Bit 0 VRECHG 0 – 100 mV, 1 – 300 mV Default: 100 mV (0)".

What is "battery regulation voltage"?

	"Bit2..7 VREG[0]..VREG[5] Default: 4.208 V (101100)"

So I did

	cat /sys/bus/i2c/drivers/bq2429x_charger/1-006b/registers

and found:

	field VREG value 22
	field BATLOWV value 01
	field VRECHG value 00 

Which translates into:

	VREG = 3.504V + 0.512V + 0.032V = 4.048V - this is where charging stops
	VRECHG = VREG - 0.1V = 3.948V

Looks good and means the charger should restart if battery drops below 3.9V.
And stop again at 4.1V.

So the battery should stay between these levels.

But it appears as if it sometimes does not.

What I could imagine is that the input current limit is lost in between.
Even if the Pyra stays connected to the USB power supply.

Or if the processor/battery gets too warm it won't start charging even
if battery voltage falls below 3.9V.

A first indication is that I have seen this while charging the battery
from 1% to 2%:

[ 1656.303805] bq2429x_charger 1-006b: bq2429x_usb_detect: state changed: state->[ HOST FCHG INDPM PWRGOOD] fault->[]
[ 1656.315432] bq2429x_charger 1-006b: bq2429x: VBUS became available
root at letux:~#

This means that somehow the charging state changed. And indeed:

	root at letux:~# cat /sys/class/power_supply/bq24297/input_current_limit
	root at letux:~#

Which means that the input current limit has been completely lost (it should still be

Digging more into that shows that unplugging the USB cable for a moment
may (not always) set field

	EN_HIZ value 01

This not only reports the input_current_limit as 0mA instead of 100mA but
also appears to disable USB plugin detection afterwards!

So a spurious disconnect from USB might move the charger chip into a state
where it is no longer charging. Even on replugging the cable. And even by
powering off the OMAP and removing all cables. It will only come out of
this state by removing all cables and the battery! Because this resets
the bq2429x.

This is at least a hint why charging may completely stop in some situations.
It does not explain the situations and how to avoid them but their effect.

A possible workaround is to repeatedly write e.g.

	echo 20000000 >/sys/class/power_supply/bq24297/input_current_limit 
	[ 2512.001741] bq2429x_charger 1-006b: bq2429x_usb_detect: state changed: state->[ PWRGOOD] fault->[]
	[ 2513.040865] bq2429x_charger 1-006b: bq2429x_usb_detect: state changed: state->[ HOST FCHG INDPM PWRGOOD VSYSMIN] fault->[]
	[ 2513.052644] bq2429x_charger 1-006b: bq2429x: VBUS became available
	[ 2514.079974] bq2429x_charger 1-006b: bq2429x_usb_detect: state changed: state->[ HOST PWRGOOD] fault->[]

where you can see that this makes the driver detect VBUS again.

Next question is why EN_HIZ is being set. Who is doing that? The chip
autonomously or our driver? The data sheet gives no hint on an automatic
change. So it is likely our driver.

Adding some debugging code shows that ...

	[  680.829385] bq2429x_charger 1-006b: bq2429x_usb_detect: state changed: state->[ HOST FCHG INDPM PWRGOOD VSYSMIN] fault->[]
	[  680.841195] bq2429x_charger 1-006b: bq2429x: VBUS became available
	[  680.848031] bq2429x_charger 1-006b: bq2429x_set_input_current_limit_uA(0)

So detecting VBUS explicitly cancels the input_current_limit. That is not
as planned, i.e. a bug in the driver.

Digging into the code shows that writing 

	echo 20000000 >/sys/class/power_supply/bq24297/device/max_current

does update the variable


while writing

	echo 20000000 >/sys/class/power_supply/bq24297/input_current_limit

did not. Both should do the same...

And there is a 0 default for this variable. This explains why the
current_limit may be reset to 0.

The driver basically did do the right thing (max_current), but not in the
case it is typically used (input_current_limit).

So we have likely found some bug. I have prepared the attached patch for
further testing. It will also be included in the upcoming letux-5.12-rc5.
Comments welcome.

Note that with this patch it is also possible to define the default
input charging limit by device tree, e.g. in pyra-mainboard-common.dtsi:

	ti,usb-input-current-microamp = <500000>;

But it is not recommended because it may be outside the USB2 specs.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-bq2429x-fix-a-long-lasting-charging-issue.patch
Type: application/octet-stream
Size: 4144 bytes
Desc: not available
URL: <http://lists.goldelico.com/pipermail/letux-kernel/attachments/20210328/c3c40086/attachment.obj>

More information about the Letux-kernel mailing list