uzbek-plus/b10/b10b3/lbc-v3-to-v4-fault-clamp.diff
q 58dcb3d121 B10: battery charging — PM8916 LBC supervisor v4 (CHARGE/HOLD, FAULT safe clamp to 4.00 V) and persistent B10B-5 cache
- LBC supervisor v1..v4 (linux/patches/b10b3-lbc-supervisor-v3.patch + b10/b10b3/lbc-v3-to-v4-fault-clamp.diff):
  CHARGING 4.20 V/450 mA -> HOLD 4.05 V after 60 min CV -> battery -> new cycle on USB insert; FAULT = VDD_MAX 4.00 V clamp
- RAM tests C/B/D/D2/D3/D4 (safety timer only ends fast charge), B10B-4 actuator audit (VDD_MAX works, USB_SUSP does not),
  B10B-5 FAULT clamp regression, production run, warm reboot via PON reboot reason
- cache = B10B-5 c3732515 (HW EDL write, readback + full partition verify), class-A persistent validation
- test-only hooks/images are not part of the production kernel; images with the AP PSK are not published
2026-10-04 19:00:27 +03:00

79 lines
3.8 KiB
Diff

--- src-b10b3/drivers/power/supply/pm8916_lbc.c 2026-10-03 21:11:03.584000000 +0600
+++ src-b10b5/drivers/power/supply/pm8916_lbc.c 2026-10-04 20:07:45.456000000 +0600
@@ -298,7 +298,7 @@
/*
- * Aurora B10B-3 v3 charger supervisor: CHARGE -> HOLD -> (battery) -> CHARGE.
+ * Aurora B10B-3 v4 charger supervisor: CHARGE -> HOLD -> (battery) -> CHARGE (v4 = v3 + FAULT safe clamp, B10B-5).
* Facts it relies on (B10A/B10B-2/B10B-3 tests): CHG_STATUS 00 + USB path 01 is a latch, not an end-of-charge;
* no hardware EOC was seen with BOOT_DONE set; CHG_EN = 0 does not stop the charger; verified levers are VDD_MAX,
* IBAT_MAX and the CHG_CTRL 0x21 -> 0xa0 edge (releases the latch). All decisions use the calibrated VADC VBAT.
@@ -306,7 +306,10 @@
* CHARGING: entered on USB insert/probe: BOOT_DONE, VDD_MAX = charge level, IBAT_MAX, restart edge.
* -> HOLD after the CV loop with VBAT >= full-min lasted cv-hold-minutes; 00/01 latch -> restart, stay.
* HOLD: only VDD_MAX = hold level; 00/01 latch -> restart edge, VDD_MAX stays at the hold level.
- * FAULT: logical only (VBAT > 4.25 V or CHG_FAILED): no restarts. There is no verified software stop.
+ * FAULT: entered on VBAT > 4.25 V or CHG_FAILED; on entry only VDD_MAX = 0x00 (FAULT safe clamp to 4.00 V, B10B-4) +
+ * readback; no further charger writes, no restarts; left only by USB removal (-> NO_USB) or reboot.
+ * The clamp is NOT a guaranteed charge disconnect: with VBAT > 4.00 V charging stops and the board runs
+ * from the battery; with VBAT < 4.00 V the charger may still charge up to 4.00 V.
*/
static void lbc_supv_log(struct pm8916_lbc_charger *chg, int to, const char *why)
{
@@ -318,7 +321,7 @@
chg->log[i].vbat = chg->vbat_uv;
chg->log[i].why = why;
if (to == LBC_ST_FAULT)
- dev_crit(chg->dev, "supervisor %s -> FAULT (%s), vbat %d uV: restarts blocked, NO software stop available\n",
+ dev_crit(chg->dev, "supervisor %s -> FAULT (%s), vbat %d uV: restarts blocked, FAULT safe clamp to 4.00 V\n",
lbc_state_name[chg->state], why, chg->vbat_uv);
else
dev_info(chg->dev, "supervisor %s -> %s (%s), vbat %d uV\n", lbc_state_name[chg->state],
@@ -394,18 +397,36 @@
return true;
}
+/*
+ * FAULT safe clamp to 4.00 V (B10B-4): the only charger write on FAULT entry is VDD_MAX = 0x00 (lowest LBC step).
+ * Not a guaranteed charge disconnect - below 4.00 V the charger may still charge up to 4.00 V.
+ */
+static void lbc_fault_clamp(struct pm8916_lbc_charger *chg, const char *why)
+{
+ unsigned int old = 0xff, rb = 0xff;
+ int ret;
+
+ ret = regmap_read(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_VDD_MAX, &old);
+ ret = ret ?: regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_VDD_MAX, 0x00);
+ ret = ret ?: regmap_read(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_VDD_MAX, &rb);
+ dev_crit(chg->dev, "FAULT safe clamp to 4.00 V: cause %s, vbat %d uV, VDD_MAX old 0x%02x -> readback 0x%02x (ret %d)\n",
+ why, chg->vbat_uv, old, rb, ret);
+}
+
+static bool lbc_enter_fault(struct pm8916_lbc_charger *chg, int reason, const char *why)
+{
+ chg->fault_reason = reason;
+ lbc_fault_clamp(chg, why);
+ lbc_supv_log(chg, LBC_ST_FAULT, why);
+ return true;
+}
+
static bool lbc_check_fault(struct pm8916_lbc_charger *chg, unsigned int failed)
{
- if (failed & PM8916_LBC_CHGR_CHG_FAILED_BIT) {
- chg->fault_reason = LBC_FAULT_TIMER;
- lbc_supv_log(chg, LBC_ST_FAULT, "CHG_FAILED (safety timer)");
- return true;
- }
- if (chg->vbat_uv > PM8916_LBC_SUPV_OVP_UV) {
- chg->fault_reason = LBC_FAULT_OVP;
- lbc_supv_log(chg, LBC_ST_FAULT, "vbat > 4.25 V");
- return true;
- }
+ if (failed & PM8916_LBC_CHGR_CHG_FAILED_BIT)
+ return lbc_enter_fault(chg, LBC_FAULT_TIMER, "CHG_FAILED (safety timer)");
+ if (chg->vbat_uv > PM8916_LBC_SUPV_OVP_UV)
+ return lbc_enter_fault(chg, LBC_FAULT_OVP, "vbat > 4.25 V");
return false;
}