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

Vincent Cloutier <[email protected]>
Newsgroups org.kernel.vger.linux-pm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Vincent Cloutier <[email protected]>

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 <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.