[PATCH v4 10/11] power: supply: max17042_battery: Honor MAX17055 charge voltage

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]>

MAX17055 ModelCfg.VChg selects the charge-voltage range used by EZ Config.
Consume voltage-max-design-microvolt from monitored-battery and set VChg
only when the value is strictly greater than 4.275 V. Reject an explicit
zero voltage and preserve the register when the property is absent.

Update only the VChg bit and verify its read-back so unrelated ModelCfg
fields remain intact. Treat a VChg-only override as an accumulator change:
read effective DesignCap and dQAcc, derive and verify the matching dPAcc,
then request model refresh. This keeps voltage-only firmware descriptions
coherent with the selected charge-voltage range.

Assisted-by: OpenCode:gpt-5.6-sol
Signed-off-by: Vincent Cloutier <[email protected]>
---
 drivers/power/supply/max17042_battery.c | 42 +++++++++++++++++++++++--
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c
index db3b1bc5388f..6278e7c89bdd 100644
--- a/drivers/power/supply/max17042_battery.c
+++ b/drivers/power/supply/max17042_battery.c
@@ -66,6 +66,7 @@
 #define MAX17055_DPACC_FACTOR		44138
 #define MAX17055_DPACC_VCHG_FACTOR	51200
 #define MAX17055_FSTAT_DNR_BIT		BIT(0)
+#define MAX17055_VCHG_THRESHOLD_UV	4275000
 #define MAX17055_DNR_POLL_US		10000
 #define MAX17055_DNR_TIMEOUT_US		2000000
 #define MAX17055_INIT_RETRY_DELAY_MS	10000
@@ -83,6 +84,7 @@ struct max17042_chip {
 	int    task_period;
 	bool   enable_current_sense;
 	bool   enable_por_init;
+	bool   enable_vchg_override;
 	bool   init_complete;
 	bool   hib_restore_pending;
 	u16    hib_cfg;
@@ -879,7 +881,8 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
 		max17042_override_por(map, MAX17047_V_empty, config->vempty);
 	}
 
-	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)
+	if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055 &&
+	    !chip->enable_vchg_override)
 		max17042_override_por(map, MAX17055_ModelCfg, config->model_cfg);
 }
 
@@ -914,7 +917,19 @@ static int max17055_override_battery_values(struct max17042_chip *chip)
 			return ret;
 	}
 
-	if (!config->design_cap && !config->dqacc)
+	if (chip->enable_vchg_override) {
+		ret = regmap_update_bits(map, MAX17055_ModelCfg,
+					 MAX17055_MODELCFG_VCHG_BIT,
+					 config->model_cfg &
+					 MAX17055_MODELCFG_VCHG_BIT);
+		if (ret)
+			return ret;
+
+		usleep_range(1000, 2000);
+	}
+
+	if (!config->design_cap && !config->dqacc &&
+	    !chip->enable_vchg_override)
 		return 0;
 
 	ret = regmap_read(map, MAX17042_DesignCap, &design_cap);
@@ -928,6 +943,10 @@ static int max17055_override_battery_values(struct max17042_chip *chip)
 	ret = regmap_read(map, MAX17055_ModelCfg, &model_cfg);
 	if (ret)
 		return ret;
+	if (chip->enable_vchg_override &&
+	    (model_cfg & MAX17055_MODELCFG_VCHG_BIT) !=
+	    (config->model_cfg & MAX17055_MODELCFG_VCHG_BIT))
+		return -EIO;
 
 	if (!design_cap || !dqacc)
 		return -ERANGE;
@@ -1248,9 +1267,11 @@ static int max17042_apply_battery_properties(struct max17042_chip *chip,
 	struct device *dev = chip->dev;
 	bool have_design_cap;
 	bool have_ichgt_term;
+	bool have_vchg;
 	u16 design_cap = 0;
 	u16 ichgt_term = 0;
 	u16 dqacc = 0;
+	u16 model_cfg = 0;
 	u64 data64;
 
 	if (!info || chip->chip_type != MAXIM_DEVICE_TYPE_MAX17055)
@@ -1260,7 +1281,8 @@ static int max17042_apply_battery_properties(struct max17042_chip *chip,
 		info->charge_full_design_uah > 0;
 	have_ichgt_term = chip->enable_current_sense &&
 		info->charge_term_current_ua > 0;
-	if (!have_design_cap && !have_ichgt_term)
+	have_vchg = info->voltage_max_design_uv >= 0;
+	if (!have_design_cap && !have_ichgt_term && !have_vchg)
 		return 0;
 
 	if (have_design_cap) {
@@ -1293,6 +1315,15 @@ static int max17042_apply_battery_properties(struct max17042_chip *chip,
 		ichgt_term = (u16)data64;
 	}
 
+	if (have_vchg) {
+		if (!info->voltage_max_design_uv)
+			return dev_err_probe(dev, -EINVAL,
+					     "battery design voltage must be positive\n");
+
+		if (info->voltage_max_design_uv > MAX17055_VCHG_THRESHOLD_UV)
+			model_cfg = MAX17055_MODELCFG_VCHG_BIT;
+	}
+
 	config = chip->config_data;
 	if (!config) {
 		config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL);
@@ -1306,6 +1337,11 @@ static int max17042_apply_battery_properties(struct max17042_chip *chip,
 	}
 	if (have_ichgt_term)
 		config->ichgt_term = ichgt_term;
+	if (have_vchg) {
+		config->model_cfg &= ~MAX17055_MODELCFG_VCHG_BIT;
+		config->model_cfg |= model_cfg;
+		chip->enable_vchg_override = true;
+	}
 
 	chip->config_data = config;
 	chip->enable_por_init = true;
-- 
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.