uzbek-plus/b10/b10b3/lbc-v1-to-v2.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

176 lines
6.8 KiB
Diff

--- v1
+++ v2
@@ -99,14 +99,12 @@
int state;
int fault_reason;
unsigned int recharge_uv; /* production threshold from monitored-battery */
- u32 test_recharge_uv; /* debugfs test-only override, 0 = off */
unsigned int timeout_min;
int vbat_uv;
int done_polls;
int low_polls;
unsigned int n_terminated;
unsigned int n_recharge;
- unsigned int n_forced;
struct {
time64_t t;
int from, to, vbat;
@@ -279,9 +277,12 @@
/*
* Aurora B10B-3 recharge supervisor.
- * The LBC ends a charge cycle in hardware (iterm comparator) and then stays off until software gives CHG_EN a
- * 0 -> 1 edge (downstream qpnp-linear-charger did this from BMS SOC / VBAT_DET IRQ). This supervisor polls the
- * VADC VBAT every 30 s and restarts charging when VBAT stays below the monitored-battery
+ * The LBC ends a charge cycle in hardware (end-of-charge latch: CHG_STATUS 00, USB path 01, USB input ~0) and then
+ * stays off until software gives CHG_EN a 0 -> 1 edge (downstream qpnp-linear-charger did this from BMS SOC /
+ * VBAT_DET IRQ). Verified on Aurora (B10B-3 ram1): CHG_CTRL 0x21 -> 0xa0 releases the latch.
+ * Also verified: writing CHG_EN = 0 does NOT stop the charger (USB input stays ~0.36 A), so the supervisor never
+ * uses CHG_CTRL to "turn charging off"; TERMINATED is only the hardware latch, observed after CHARGING.
+ * The supervisor polls the VADC VBAT every 30 s and restarts charging when VBAT stays below the monitored-battery
* re-charge-voltage-microvolt for 3 consecutive polls.
*/
static void lbc_supv_log(struct pm8916_lbc_charger *chg, int to, const char *why)
@@ -306,7 +307,7 @@
en ? PM8916_LBC_CHGR_CHG_EN : PM8916_LBC_CHGR_FORCE_BATT_ON);
}
-/* explicit CHG_EN 0 -> 1 edge; on (re)insert also clear a latched CHG_FAILED */
+/* the verified restart: CHG_CTRL 0x21 (CHG_EN 0) -> 20 ms -> 0xa0 (CHG_EN 1); on (re)insert also clear CHG_FAILED */
static int lbc_charge_restart(struct pm8916_lbc_charger *chg, bool clear_failed)
{
int ret;
@@ -324,11 +325,6 @@
return lbc_charge_enable(chg, true);
}
-static unsigned int lbc_recharge_uv(struct pm8916_lbc_charger *chg)
-{
- return chg->test_recharge_uv ? chg->test_recharge_uv : chg->recharge_uv;
-}
-
static void lbc_supv_work(struct work_struct *work)
{
struct pm8916_lbc_charger *chg = container_of(work, struct pm8916_lbc_charger, supv_work.work);
@@ -351,8 +347,8 @@
chg->vbat_uv = -1;
if (!(usb_rt & PM8916_LBC_USB_USBIN_VALID)) {
+ /* CHG_CTRL untouched; the next insert restarts with the verified edge */
if (chg->state != LBC_ST_NO_USB) {
- lbc_charge_enable(chg, false);
chg->fault_reason = LBC_FAULT_NONE;
lbc_supv_log(chg, LBC_ST_NO_USB, "usb removed");
}
@@ -372,24 +368,27 @@
break;
case LBC_ST_CHARGING:
- if (chg->vbat_uv > PM8916_LBC_SUPV_OVP_UV) {
- lbc_charge_enable(chg, false);
- chg->fault_reason = LBC_FAULT_OVP;
- lbc_supv_log(chg, LBC_ST_FAULT, "vbat > 4.25 V");
- break;
- }
+ /*
+ * Safety timer expiry: the hardware stops and sets CHG_FAILED. Latch FAULT so the supervisor never
+ * restarts; no register write (CHG_EN = 0 is not a verified way to stop the charger).
+ */
if (failed & PM8916_LBC_CHGR_CHG_FAILED_BIT) {
- lbc_charge_enable(chg, false);
chg->fault_reason = LBC_FAULT_TIMER;
lbc_supv_log(chg, LBC_ST_FAULT, "CHG_FAILED (safety timer)");
break;
}
+ if (chg->vbat_uv > PM8916_LBC_SUPV_OVP_UV) {
+ /* defence only: VDD_MAX regulates in hardware; latch FAULT = no further restarts */
+ chg->fault_reason = LBC_FAULT_OVP;
+ lbc_supv_log(chg, LBC_ST_FAULT, "vbat > 4.25 V");
+ break;
+ }
+ /* TERMINATED = hardware end-of-charge latch only; CHG_CTRL is not changed */
if (sts == 0 && !(path & PM8916_LBC_USB_PATH_ON))
chg->done_polls++;
else
chg->done_polls = 0;
if (chg->done_polls >= PM8916_LBC_SUPV_DONE_POLLS) {
- lbc_charge_enable(chg, false);
chg->n_terminated++;
chg->low_polls = 0;
lbc_supv_log(chg, LBC_ST_TERMINATED, "hardware end of charge");
@@ -397,18 +396,18 @@
break;
case LBC_ST_TERMINATED:
- if (!lbc_recharge_uv(chg) || chg->vbat_uv < 0)
+ if (!chg->recharge_uv || chg->vbat_uv < 0)
break;
- if ((unsigned int)chg->vbat_uv < lbc_recharge_uv(chg))
+ if ((unsigned int)chg->vbat_uv < chg->recharge_uv)
chg->low_polls++;
else
chg->low_polls = 0;
if (chg->low_polls >= PM8916_LBC_SUPV_LOW_POLLS) {
chg->done_polls = 0;
- if (!lbc_charge_enable(chg, true)) {
+ chg->low_polls = 0;
+ if (!lbc_charge_restart(chg, false)) {
chg->n_recharge++;
- lbc_supv_log(chg, LBC_ST_CHARGING,
- chg->test_recharge_uv ? "recharge (TEST threshold)" : "recharge");
+ lbc_supv_log(chg, LBC_ST_CHARGING, "recharge");
}
}
break;
@@ -446,11 +445,9 @@
mutex_lock(&chg->supv_lock);
seq_printf(s, "state %s fault %s vbat_uv %d\n", lbc_state_name[chg->state],
lbc_fault_name[chg->fault_reason], chg->vbat_uv);
- seq_printf(s, "recharge_uv %u (production %u, test %u) done_polls %d low_polls %d timeout_min %u\n",
- lbc_recharge_uv(chg), chg->recharge_uv, chg->test_recharge_uv, chg->done_polls,
- chg->low_polls, chg->timeout_min);
- seq_printf(s, "n_terminated %u n_recharge %u n_forced %u\n", chg->n_terminated,
- chg->n_recharge, chg->n_forced);
+ seq_printf(s, "recharge_uv %u done_polls %d low_polls %d timeout_min %u\n",
+ chg->recharge_uv, chg->done_polls, chg->low_polls, chg->timeout_min);
+ seq_printf(s, "n_terminated %u n_recharge %u\n", chg->n_terminated, chg->n_recharge);
for (i = 0; i < ARRAY_SIZE(regs); i++) {
if (regmap_read(chg->regmap, chg->reg[regs[i].blk] + regs[i].off, &v))
v = 0xffff;
@@ -468,27 +465,6 @@
}
DEFINE_SHOW_ATTRIBUTE(lbc_state);
-/* TEST ONLY (RAM test images): the supervisor performs its normal TERMINATED action now. */
-static ssize_t lbc_force_terminate_write(struct file *file, const char __user *buf, size_t len,
- loff_t *ppos)
-{
- struct pm8916_lbc_charger *chg = file->private_data;
-
- mutex_lock(&chg->supv_lock);
- if (chg->state == LBC_ST_CHARGING && !lbc_charge_enable(chg, false)) {
- chg->n_forced++;
- chg->low_polls = 0;
- lbc_supv_log(chg, LBC_ST_TERMINATED, "FORCED by test hook");
- }
- mutex_unlock(&chg->supv_lock);
- return len;
-}
-
-static const struct file_operations lbc_force_terminate_fops = {
- .open = simple_open,
- .write = lbc_force_terminate_write,
-};
-
static void lbc_debugfs_remove(void *data)
{
debugfs_remove_recursive(data);
@@ -716,8 +692,6 @@
chg->debugfs = debugfs_create_dir("pm8916_lbc", NULL);
debugfs_create_file("state", 0444, chg->debugfs, chg, &lbc_state_fops);
- debugfs_create_file("force_terminate", 0200, chg->debugfs, chg, &lbc_force_terminate_fops);
- debugfs_create_u32("test_recharge_uv", 0600, chg->debugfs, &chg->test_recharge_uv);
ret = devm_add_action_or_reset(dev, lbc_debugfs_remove, chg->debugfs);
if (ret)
return ret;