[PATCH v4 08/11] power: supply: max17042_battery: Follow MAX17055 POR sequence

From: Vincent Cloutier

Date: Sun Jul 26 2026 - 21:16:52 EST


From: Vincent Cloutier <vincent@xxxxxxxxxxx>

Wait until the MAX17055 is ready, leave hibernate around EZ Config,
and wait for ModelCfg.Refresh to clear as required by the power-on reset
initialization flow.

Restore HibCfg on every exit path. Keep failed restoration state so a
retry restores hibernate before starting a new initialization transaction.

Assisted-by: OpenCode:gpt-5.6-sol
Signed-off-by: Vincent Cloutier <vincent@xxxxxxxxxxx>
---
drivers/power/supply/max17042_battery.c | 91 ++++++++++++++++++++++---
include/linux/power/max17042_battery.h | 1 +
2 files changed, 81 insertions(+), 11 deletions(-)

diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index 600b2689f316..33a2cc378b46 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -64,7 +64,12 @@

#define MAX17055_DPACC_FACTOR 44138
#define MAX17055_DPACC_VCHG_FACTOR 51200
+#define MAX17055_FSTAT_DNR_BIT BIT(0)
+#define MAX17055_DNR_POLL_US 10000
+#define MAX17055_DNR_TIMEOUT_US 2000000
#define MAX17055_INIT_RETRY_DELAY_MS 10000
+#define MAX17055_REFRESH_POLL_US 10000
+#define MAX17055_REFRESH_TIMEOUT_US 1000000

struct max17042_chip {
struct device *dev;
@@ -78,6 +83,8 @@ struct max17042_chip {
bool enable_current_sense;
bool enable_por_init;
bool init_complete;
+ bool hib_restore_pending;
+ u16 hib_cfg;
unsigned int r_sns;
int vmin; /* in millivolts */
int vmax; /* in millivolts */
@@ -934,19 +941,86 @@ static int max17055_override_battery_values(struct max17042_chip *chip)
return max17055_write_verify_reg(map, MAX17042_dPacc, (u16)dpacc);
}

+static int max17055_restore_hibernate(struct max17042_chip *chip)
+{
+ int restore_hib_ret;
+ int soft_wakeup_ret;
+
+ soft_wakeup_ret = regmap_write(chip->regmap, MAX17055_SoftWakeup, 0);
+ restore_hib_ret = max17055_write_verify_reg(chip->regmap,
+ MAX17055_HibCfg,
+ chip->hib_cfg);
+ if (!soft_wakeup_ret && !restore_hib_ret)
+ chip->hib_restore_pending = false;
+
+ return soft_wakeup_ret ?: restore_hib_ret;
+}
+
static int max17055_init_chip(struct max17042_chip *chip)
{
+ struct regmap *map = chip->regmap;
+ unsigned int hib_cfg;
+ unsigned int model_cfg;
+ unsigned int fstat;
+ int restore_ret;
int ret;

+ if (chip->hib_restore_pending) {
+ ret = max17055_restore_hibernate(chip);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_read_poll_timeout(map, MAX17042_FSTAT, fstat,
+ !(fstat & MAX17055_FSTAT_DNR_BIT),
+ MAX17055_DNR_POLL_US,
+ MAX17055_DNR_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(map, MAX17055_HibCfg, &hib_cfg);
+ if (ret)
+ return ret;
+
+ chip->hib_cfg = hib_cfg;
+ chip->hib_restore_pending = true;
+
+ ret = regmap_write(map, MAX17055_SoftWakeup, 0x0090);
+ if (ret)
+ goto restore_hibernate;
+
+ ret = max17055_write_verify_reg(map, MAX17055_HibCfg, 0);
+ if (ret)
+ goto restore_hibernate;
+
+ ret = regmap_write(map, MAX17055_SoftWakeup, 0);
+ if (ret)
+ goto restore_hibernate;
+
max17042_override_por_values(chip);

ret = max17055_override_battery_values(chip);
if (ret)
- return ret;
+ goto restore_hibernate;

- return regmap_write_bits(chip->regmap, MAX17055_ModelCfg,
- MAX17055_MODELCFG_REFRESH_BIT,
- MAX17055_MODELCFG_REFRESH_BIT);
+ ret = regmap_write_bits(map, MAX17055_ModelCfg,
+ MAX17055_MODELCFG_REFRESH_BIT,
+ MAX17055_MODELCFG_REFRESH_BIT);
+ if (ret)
+ goto restore_hibernate;
+
+ ret = regmap_read_poll_timeout(map, MAX17055_ModelCfg, model_cfg,
+ !(model_cfg &
+ MAX17055_MODELCFG_REFRESH_BIT),
+ MAX17055_REFRESH_POLL_US,
+ MAX17055_REFRESH_TIMEOUT_US);
+
+restore_hibernate:
+ restore_ret = max17055_restore_hibernate(chip);
+ if (restore_ret)
+ return restore_ret;
+
+ return ret;
}

static int max17042_init_chip(struct max17042_chip *chip)
@@ -960,15 +1034,10 @@ static int max17042_init_chip(struct max17042_chip *chip)
return ret;
} else {
max17042_override_por_values(chip);
- }

- /* After Power up, the MAX17042 requires 500mS in order
- * to perform signal debouncing and initial SOC reporting
- */
- msleep(500);
+ /* Allow signal debouncing and initial SOC reporting. */
+ msleep(500);

- if (chip->chip_type != MAXIM_DEVICE_TYPE_MAX17055) {
- /* Initialize configuration */
max17042_write_config_regs(chip);

/* write cell characterization data */
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
index 61af6fe2f4fe..810e068eafd2 100644
--- a/include/linux/power/max17042_battery.h
+++ b/include/linux/power/max17042_battery.h
@@ -125,6 +125,7 @@ enum max17055_register {

MAX17055_ConvgCfg = 0x49,
MAX17055_VFRemCap = 0x4A,
+ MAX17055_SoftWakeup = 0x60,

MAX17055_STATUS2 = 0xB0,
MAX17055_POWER = 0xB1,
--
2.55.0