From fc0ccc5ca73bffa9053c015866770546352369d1 Mon Sep 17 00:00:00 2001 From: Douglas Teles Date: Thu, 2 Apr 2026 15:20:26 -0300 Subject: [PATCH] Battery patch hotfix --- .../patches/linux/004-input-drivers.patch | 13 -- .../linux/010-rk817-battery-calibration.patch | 193 ++++++++++++++++++ 2 files changed, 193 insertions(+), 13 deletions(-) create mode 100644 projects/ArchR/devices/RK3326/patches/linux/010-rk817-battery-calibration.patch diff --git a/projects/ArchR/devices/RK3326/patches/linux/004-input-drivers.patch b/projects/ArchR/devices/RK3326/patches/linux/004-input-drivers.patch index 0cf37d73a6..341f7a4457 100644 --- a/projects/ArchR/devices/RK3326/patches/linux/004-input-drivers.patch +++ b/projects/ArchR/devices/RK3326/patches/linux/004-input-drivers.patch @@ -6814,16 +6814,3 @@ index 000000000000..f7832a8158d4 +MODULE_ALIAS("platform:" DRV_NAME); + +/*----------------------------------------------------------------------------*/ -diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c -index 7ca91739c6cc..a2a6d8093206 100644 ---- a/drivers/power/supply/rk817_charger.c -+++ b/drivers/power/supply/rk817_charger.c -@@ -679,7 +679,7 @@ static enum power_supply_usb_type rk817_usb_type[] = { - }; - - static const struct power_supply_desc rk817_bat_desc = { -- .name = "rk817-battery", -+ .name = "battery", - .type = POWER_SUPPLY_TYPE_BATTERY, - .properties = rk817_bat_props, - .num_properties = ARRAY_SIZE(rk817_bat_props), diff --git a/projects/ArchR/devices/RK3326/patches/linux/010-rk817-battery-calibration.patch b/projects/ArchR/devices/RK3326/patches/linux/010-rk817-battery-calibration.patch new file mode 100644 index 0000000000..f00cb6c328 --- /dev/null +++ b/projects/ArchR/devices/RK3326/patches/linux/010-rk817-battery-calibration.patch @@ -0,0 +1,193 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Morgan +Date: Thu, 26 Sep 2024 09:43:45 -0500 +Subject: [PATCH] power: supply: rk817: fix battery calibration and suspend + +Backport of two upstream patches from kernel 6.13: + - bded860c3110 ("power: supply: rk817: stop updating info in suspend") + - 1e5335d00707 ("power: supply: rk817: Update battery capacity calibration") + +The battery monitoring thread reads incorrect voltage values during +suspend, causing the calibration function to erroneously recalibrate +the full charge capacity or set SOC to 0. This results in the battery +percentage rapidly dropping to 0% even when the battery is still +charged. + +Fix 1: Cancel the monitoring thread during suspend so stale readings +are not collected while the system sleeps. + +Fix 2: Add voltage sanity checks (2.7V-4.45V) to the calibration +function, guard against no-battery-present, remove the problematic +automatic FCC recalibration on empty battery, and make CHARGE_FULL +writable from userspace for degraded battery support. + +Signed-off-by: Chris Morgan +--- + drivers/power/supply/rk817_charger.c | 112 ++++++++++++++++++--------- + 1 file changed, 74 insertions(+), 38 deletions(-) + +diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c +--- a/drivers/power/supply/rk817_charger.c ++++ b/drivers/power/supply/rk817_charger.c +@@ -240,9 +240,32 @@ static int rk817_record_battery_nvram_values(struct rk817_charger *charger) + static int rk817_bat_calib_cap(struct rk817_charger *charger) + { + struct rk808 *rk808 = charger->rk808; +- int tmp, charge_now, charge_now_adc, volt_avg; ++ int charge_now, charge_now_adc; + u8 bulk_reg[4]; + ++ /* Don't do anything if there's no battery. */ ++ if (!charger->battery_present) ++ return 0; ++ ++ /* ++ * When resuming from suspend, sometimes the voltage value would be ++ * incorrect. BSP would simply wait two seconds and try reading the ++ * values again. Do not do any sort of calibration activity when the ++ * reported value is incorrect. The next scheduled update of battery ++ * values should then return valid data and the driver can continue. ++ * Use 2.7v as the sanity value because per the datasheet the PMIC ++ * can in no way support a battery voltage lower than this. BSP only ++ * checked for values too low, but adding a check for values ++ * too high just in case; the PMIC can in no way support ++ * voltages above 4.45v. ++ */ ++ if ((charger->volt_avg_uv < 2700000) || (charger->volt_avg_uv > 4450000)) { ++ dev_dbg(charger->dev, ++ "Battery voltage of %d is invalid, ignoring.\n", ++ charger->volt_avg_uv); ++ return -EINVAL; ++ } ++ + /* Calibrate the soc and fcc on a fully charged battery */ + + if (charger->charge_status == CHARGE_FINISH && (!charger->soc_cal)) { +@@ -304,51 +327,6 @@ static int rk817_bat_calib_cap(struct rk817_charger *charger) + } + } + +- /* +- * Calibrate the fully charged capacity when we previously had a full +- * battery (soc_cal = 1) and are now empty (at or below minimum design +- * voltage). If our columb counter is still positive, subtract that +- * from our fcc value to get a calibrated fcc, and if our columb +- * counter is negative add that to our fcc (but not to exceed our +- * design capacity). +- */ +- regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_BAT_VOL_H, +- bulk_reg, 2); +- tmp = get_unaligned_be16(bulk_reg); +- volt_avg = (charger->voltage_k * tmp) + 1000 * charger->voltage_b; +- if (volt_avg <= charger->bat_voltage_min_design_uv && +- charger->soc_cal) { +- regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3, +- bulk_reg, 4); +- charge_now_adc = get_unaligned_be32(bulk_reg); +- charge_now = ADC_TO_CHARGE_UAH(charge_now_adc, +- charger->res_div); +- /* +- * Note, if charge_now is negative this will add it (what we +- * want) and if it's positive this will subtract (also what +- * we want). +- */ +- charger->fcc_mah = charger->fcc_mah - (charge_now / 1000); +- +- dev_dbg(charger->dev, +- "Recalibrating full charge capacity to %d uah\n", +- charger->fcc_mah * 1000); +- } +- +- /* +- * Set the SOC to 0 if we are below the minimum system voltage. +- */ +- if (volt_avg <= charger->bat_voltage_min_design_uv) { +- charger->soc = 0; +- charge_now_adc = CHARGE_TO_ADC(0, charger->res_div); +- put_unaligned_be32(charge_now_adc, bulk_reg); +- regmap_bulk_write(rk808->regmap, +- RK817_GAS_GAUGE_Q_INIT_H3, bulk_reg, 4); +- dev_warn(charger->dev, +- "Battery voltage %d below minimum voltage %d\n", +- volt_avg, charger->bat_voltage_min_design_uv); +- } +- + rk817_record_battery_nvram_values(charger); + + return 0; +@@ -648,6 +626,24 @@ static irqreturn_t rk817_plug_out_isr(int irq, void *cg) + return IRQ_HANDLED; + } + ++static int rk817_bat_set_prop(struct power_supply *ps, ++ enum power_supply_property prop, ++ const union power_supply_propval *val) ++{ ++ struct rk817_charger *charger = power_supply_get_drvdata(ps); ++ ++ switch (prop) { ++ case POWER_SUPPLY_PROP_CHARGE_FULL: ++ if ((val->intval < 500000) || ++ (val->intval > charger->bat_charge_full_design_uah)) ++ return -EINVAL; ++ charger->fcc_mah = val->intval / 1000; ++ return rk817_bat_calib_cap(charger); ++ default: ++ return -EINVAL; ++ } ++} ++ + static enum power_supply_property rk817_bat_props[] = { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_STATUS, +@@ -673,12 +669,25 @@ static enum power_supply_property rk817_chg_props[] = { + POWER_SUPPLY_PROP_VOLTAGE_AVG, + }; + ++static int rk817_bat_prop_writeable(struct power_supply *psy, ++ enum power_supply_property psp) ++{ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_CHARGE_FULL: ++ return 1; ++ default: ++ return 0; ++ } ++} ++ + static const struct power_supply_desc rk817_bat_desc = { + .name = "battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = rk817_bat_props, ++ .property_is_writeable = rk817_bat_prop_writeable, + .num_properties = ARRAY_SIZE(rk817_bat_props), + .get_property = rk817_bat_get_prop, ++ .set_property = rk817_bat_set_prop, + }; + + static const struct power_supply_desc rk817_chg_desc = { +@@ -1202,6 +1211,15 @@ static int rk817_charger_probe(struct platform_device *pdev) + return 0; + } + ++static int __maybe_unused rk817_suspend(struct device *dev) ++{ ++ struct rk817_charger *charger = dev_get_drvdata(dev); ++ ++ cancel_delayed_work_sync(&charger->work); ++ ++ return 0; ++} ++ + static int __maybe_unused rk817_resume(struct device *dev) + { + +@@ -1213,7 +1231,7 @@ static int __maybe_unused rk817_resume(struct device *dev) + return 0; + } + +-static SIMPLE_DEV_PM_OPS(rk817_charger_pm, NULL, rk817_resume); ++static SIMPLE_DEV_PM_OPS(rk817_charger_pm, rk817_suspend, rk817_resume); + + static struct platform_driver rk817_charger_driver = { + .probe = rk817_charger_probe,