[PATCH v4 07/11] power: supply: max17042_battery: Program MAX17055 EZ Config values
From: Vincent Cloutier
Date: Sun Jul 26 2026 - 21:16:18 EST
From: Vincent Cloutier <vincent@xxxxxxxxxxx>
MAX17055 EZ Config requires DesignCap, dQAcc, IChgTerm, and dPAcc to
be programmed coherently. Write each supplied stable register once, wait
1 ms, and verify its read-back instead of relying on the unchecked generic
POR override path.
Derive dPAcc from the effective DesignCap, dQAcc, and ModelCfg values so
the accumulator matches the selected charge-voltage range. Propagate all
read, write, verification, and range errors to the retrying init worker.
Assisted-by: OpenCode:gpt-5.6-sol
Signed-off-by: Vincent Cloutier <vincent@xxxxxxxxxxx>
---
drivers/power/supply/max17042_battery.c | 99 ++++++++++++++++++++++++-
include/linux/power/max17042_battery.h | 1 +
2 files changed, 96 insertions(+), 4 deletions(-)
diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index 27d881d4324f..600b2689f316 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -62,6 +62,8 @@
#define MAX17042_RESISTANCE_LSB 1 / 4096 /* Ω */
#define MAX17042_TEMPERATURE_LSB 1 / 256 /* °C */
+#define MAX17055_DPACC_FACTOR 44138
+#define MAX17055_DPACC_VCHG_FACTOR 51200
#define MAX17055_INIT_RETRY_DELAY_MS 10000
struct max17042_chip {
@@ -568,6 +570,24 @@ static int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value)
return ret;
}
+static int max17055_write_verify_reg(struct regmap *map, u8 reg, u32 value)
+{
+ u32 read_value;
+ int ret;
+
+ ret = regmap_write(map, reg, value);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ ret = regmap_read(map, reg, &read_value);
+ if (ret)
+ return ret;
+
+ return read_value == value ? 0 : -EIO;
+}
+
static inline void max17042_override_por(struct regmap *map,
u8 reg, u16 value)
{
@@ -803,8 +823,12 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
max17042_override_por(map, MAX17042_CONFIG, config->config);
max17042_override_por(map, MAX17042_SHDNTIMER, config->shdntimer);
- max17042_override_por(map, MAX17042_DesignCap, config->design_cap);
- max17042_override_por(map, MAX17042_ICHGTerm, config->ichgt_term);
+ if (chip->chip_type != MAXIM_DEVICE_TYPE_MAX17055) {
+ max17042_override_por(map, MAX17042_DesignCap,
+ config->design_cap);
+ max17042_override_por(map, MAX17042_ICHGTerm,
+ config->ichgt_term);
+ }
max17042_override_por(map, MAX17042_AtRate, config->at_rate);
max17042_override_por(map, MAX17042_LearnCFG, config->learn_cfg);
@@ -814,8 +838,10 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
max17042_override_por(map, MAX17042_FullCAP, config->fullcap);
max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom);
- max17042_override_por(map, MAX17042_dQacc, config->dqacc);
- max17042_override_por(map, MAX17042_dPacc, config->dpacc);
+ if (chip->chip_type != MAXIM_DEVICE_TYPE_MAX17055) {
+ max17042_override_por(map, MAX17042_dQacc, config->dqacc);
+ max17042_override_por(map, MAX17042_dPacc, config->dpacc);
+ }
max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0);
max17042_override_por(map, MAX17042_TempCo, config->tcompc0);
@@ -849,10 +875,75 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
max17042_override_por(map, MAX17055_ModelCfg, config->model_cfg);
}
+static int max17055_override_battery_values(struct max17042_chip *chip)
+{
+ struct max17042_config_data *config = chip->config_data;
+ struct regmap *map = chip->regmap;
+ unsigned int design_cap;
+ unsigned int model_cfg;
+ unsigned int dqacc;
+ u64 dpacc;
+ int ret;
+
+ if (config->design_cap) {
+ ret = max17055_write_verify_reg(map, MAX17042_DesignCap,
+ config->design_cap);
+ if (ret)
+ return ret;
+ }
+
+ if (config->dqacc) {
+ ret = max17055_write_verify_reg(map, MAX17042_dQacc,
+ config->dqacc);
+ if (ret)
+ return ret;
+ }
+
+ if (config->ichgt_term) {
+ ret = max17055_write_verify_reg(map, MAX17042_ICHGTerm,
+ config->ichgt_term);
+ if (ret)
+ return ret;
+ }
+
+ if (!config->design_cap && !config->dqacc)
+ return 0;
+
+ ret = regmap_read(map, MAX17042_DesignCap, &design_cap);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(map, MAX17042_dQacc, &dqacc);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(map, MAX17055_ModelCfg, &model_cfg);
+ if (ret)
+ return ret;
+
+ if (!design_cap || !dqacc)
+ return -ERANGE;
+
+ dpacc = (u64)dqacc *
+ (model_cfg & MAX17055_MODELCFG_VCHG_BIT ?
+ MAX17055_DPACC_VCHG_FACTOR : MAX17055_DPACC_FACTOR);
+ do_div(dpacc, design_cap);
+ if (dpacc > U16_MAX)
+ return -ERANGE;
+
+ return max17055_write_verify_reg(map, MAX17042_dPacc, (u16)dpacc);
+}
+
static int max17055_init_chip(struct max17042_chip *chip)
{
+ int ret;
+
max17042_override_por_values(chip);
+ ret = max17055_override_battery_values(chip);
+ if (ret)
+ return ret;
+
return regmap_write_bits(chip->regmap, MAX17055_ModelCfg,
MAX17055_MODELCFG_REFRESH_BIT,
MAX17055_MODELCFG_REFRESH_BIT);
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
index 13aeab1597c6..61af6fe2f4fe 100644
--- a/include/linux/power/max17042_battery.h
+++ b/include/linux/power/max17042_battery.h
@@ -25,6 +25,7 @@
#define MAX17042_CHARACTERIZATION_DATA_SIZE 48
#define MAX17055_MODELCFG_REFRESH_BIT BIT(15)
+#define MAX17055_MODELCFG_VCHG_BIT BIT(10)
enum max17042_register {
MAX17042_STATUS = 0x00,
--
2.55.0