Skip to content

Commit baba131

Browse files
macromorgansre
authored andcommitted
power: supply: rk817: Fix low SOC bugs
When the SOC approaches zero, an integer overflows in the columb counter causing the driver to react poorly. This makes the driver think it's at (above) the fully charged capacity when in fact it's zero. It would then write this full capacity to NVRAM which would be used on boot if the device remained off for less than 5 hours and not plugged in. This can be fixed and guarded against by doing the following: - Changing the type of tmp in rk817_read_or_set_full_charge_on_boot() to be an int instead of a u32. That way we can account for negative numbers. - Guard against negative values for the full charge on boot by setting the charge to 0 if the system charge reports less than 0. - Catch scenarios where the battery voltage is below the design minimum voltage and set the system SOC to 0 at that time and update the columb counter with a charge level of 0. - Change the off time value from 5 hours to 30 minutes before we recalculate the current capacity based on the OCV tables. These changes allow the driver to operate better at low voltage/low capacity conditions. Fixes: 3268a4d ("power: supply: rk817: Fix unsigned comparison with less than zero") Fixes: 11cb8da ("power: supply: Add charger driver for Rockchip RK817") Signed-off-by: Chris Morgan <macromorgan@hotmail.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
1 parent 528bd42 commit baba131

File tree

1 file changed

+26
-7
lines changed

1 file changed

+26
-7
lines changed

drivers/power/supply/rk817_charger.c

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,20 @@ static int rk817_bat_calib_cap(struct rk817_charger *charger)
335335
charger->fcc_mah * 1000);
336336
}
337337

338+
/*
339+
* Set the SOC to 0 if we are below the minimum system voltage.
340+
*/
341+
if (volt_avg <= charger->bat_voltage_min_design_uv) {
342+
charger->soc = 0;
343+
charge_now_adc = CHARGE_TO_ADC(0, charger->res_div);
344+
put_unaligned_be32(charge_now_adc, bulk_reg);
345+
regmap_bulk_write(rk808->regmap,
346+
RK817_GAS_GAUGE_Q_INIT_H3, bulk_reg, 4);
347+
dev_warn(charger->dev,
348+
"Battery voltage %d below minimum voltage %d\n",
349+
volt_avg, charger->bat_voltage_min_design_uv);
350+
}
351+
338352
rk817_record_battery_nvram_values(charger);
339353

340354
return 0;
@@ -710,9 +724,10 @@ static int rk817_read_battery_nvram_values(struct rk817_charger *charger)
710724

711725
/*
712726
* Read the nvram for state of charge. Sanity check for values greater
713-
* than 100 (10000). If the value is off it should get corrected
714-
* automatically when the voltage drops to the min (soc is 0) or when
715-
* the battery is full (soc is 100).
727+
* than 100 (10000) or less than 0, because other things (BSP kernels,
728+
* U-Boot, or even i2cset) can write to this register. If the value is
729+
* off it should get corrected automatically when the voltage drops to
730+
* the min (soc is 0) or when the battery is full (soc is 100).
716731
*/
717732
ret = regmap_bulk_read(charger->rk808->regmap,
718733
RK817_GAS_GAUGE_BAT_R1, bulk_reg, 3);
@@ -721,6 +736,8 @@ static int rk817_read_battery_nvram_values(struct rk817_charger *charger)
721736
charger->soc = get_unaligned_le24(bulk_reg);
722737
if (charger->soc > 10000)
723738
charger->soc = 10000;
739+
if (charger->soc < 0)
740+
charger->soc = 0;
724741

725742
return 0;
726743
}
@@ -731,8 +748,8 @@ rk817_read_or_set_full_charge_on_boot(struct rk817_charger *charger,
731748
{
732749
struct rk808 *rk808 = charger->rk808;
733750
u8 bulk_reg[4];
734-
u32 boot_voltage, boot_charge_mah, tmp;
735-
int ret, reg, off_time;
751+
u32 boot_voltage, boot_charge_mah;
752+
int ret, reg, off_time, tmp;
736753
bool first_boot;
737754

738755
/*
@@ -785,10 +802,12 @@ rk817_read_or_set_full_charge_on_boot(struct rk817_charger *charger,
785802
regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3,
786803
bulk_reg, 4);
787804
tmp = get_unaligned_be32(bulk_reg);
805+
if (tmp < 0)
806+
tmp = 0;
788807
boot_charge_mah = ADC_TO_CHARGE_UAH(tmp,
789808
charger->res_div) / 1000;
790809
/*
791-
* Check if the columb counter has been off for more than 300
810+
* Check if the columb counter has been off for more than 30
792811
* minutes as it tends to drift downward. If so, re-init soc
793812
* with the boot voltage instead. Note the unit values for the
794813
* OFF_CNT register appear to be in decaminutes and stops
@@ -799,7 +818,7 @@ rk817_read_or_set_full_charge_on_boot(struct rk817_charger *charger,
799818
* than 0 on a reboot anyway.
800819
*/
801820
regmap_read(rk808->regmap, RK817_GAS_GAUGE_OFF_CNT, &off_time);
802-
if (off_time >= 30) {
821+
if (off_time >= 3) {
803822
regmap_bulk_read(rk808->regmap,
804823
RK817_GAS_GAUGE_PWRON_VOL_H,
805824
bulk_reg, 2);

0 commit comments

Comments
 (0)