* [PATCH 1/9] power: supply: max77705_charger: move active discharge setting to mfd parent
2025-08-30 20:45 [PATCH 0/9] power: supply: fixes and improvements for max77(705,976) chargers Dzmitry Sankouski
@ 2025-08-30 20:45 ` Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 2/9] power: supply: max77705_charger: refactoring: rename charger to chg Dzmitry Sankouski
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Dzmitry Sankouski @ 2025-08-30 20:45 UTC (permalink / raw)
To: Chanwoo Choi, Krzysztof Kozlowski, Lee Jones, Sebastian Reichel,
Luca Ceresoli
Cc: Krzysztof Kozlowski, Sebastian Reichel, linux-kernel, linux-pm,
Dzmitry Sankouski
Active discharge setting is a part of MFD top level i2c device, hence
cannot be controlled by charger. Writing to MAX77705_PMIC_REG_MAINCTRL1
register from charger driver is a mistake.
Move active discharge setting to MFD parent driver.
Fixes: a6a494c8e3ce ("power: supply: max77705: Add charger driver for Maxim 77705")
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
drivers/mfd/max77705.c | 3 +++
drivers/power/supply/max77705_charger.c | 3 ---
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/mfd/max77705.c b/drivers/mfd/max77705.c
index 6b263bacb8c2..ff07d0e0d5f8 100644
--- a/drivers/mfd/max77705.c
+++ b/drivers/mfd/max77705.c
@@ -108,6 +108,9 @@ static int max77705_i2c_probe(struct i2c_client *i2c)
if (pmic_rev != MAX77705_PASS3)
return dev_err_probe(dev, -ENODEV, "Rev.0x%x is not tested\n", pmic_rev);
+ /* Active Discharge Enable */
+ regmap_update_bits(max77705->regmap, MAX77705_PMIC_REG_MAINCTRL1, 1, 1);
+
ret = devm_regmap_add_irq_chip(dev, max77705->regmap,
i2c->irq,
IRQF_ONESHOT | IRQF_SHARED, 0,
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
index 329b430d0e50..3b75c82b9b9e 100644
--- a/drivers/power/supply/max77705_charger.c
+++ b/drivers/power/supply/max77705_charger.c
@@ -487,9 +487,6 @@ static void max77705_charger_initialize(struct max77705_charger_data *chg)
regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_00,
MAX77705_WDTEN_MASK, 0);
- /* Active Discharge Enable */
- regmap_update_bits(regmap, MAX77705_PMIC_REG_MAINCTRL1, 1, 1);
-
/* VBYPSET=5.0V */
regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_11, MAX77705_VBYPSET_MASK, 0);
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/9] power: supply: max77705_charger: refactoring: rename charger to chg
2025-08-30 20:45 [PATCH 0/9] power: supply: fixes and improvements for max77(705,976) chargers Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 1/9] power: supply: max77705_charger: move active discharge setting to mfd parent Dzmitry Sankouski
@ 2025-08-30 20:45 ` Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 3/9] power: supply: max77705_charger: use regfields for config registers Dzmitry Sankouski
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Dzmitry Sankouski @ 2025-08-30 20:45 UTC (permalink / raw)
To: Chanwoo Choi, Krzysztof Kozlowski, Lee Jones, Sebastian Reichel,
Luca Ceresoli
Cc: Krzysztof Kozlowski, Sebastian Reichel, linux-kernel, linux-pm,
Dzmitry Sankouski
Rename struct max77705_charger_data variable to chg for consistency.
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
drivers/power/supply/max77705_charger.c | 80 ++++++++++++++++-----------------
1 file changed, 40 insertions(+), 40 deletions(-)
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
index 3b75c82b9b9e..7855f890e0a9 100644
--- a/drivers/power/supply/max77705_charger.c
+++ b/drivers/power/supply/max77705_charger.c
@@ -42,9 +42,9 @@ static enum power_supply_property max77705_charger_props[] = {
static int max77705_chgin_irq(void *irq_drv_data)
{
- struct max77705_charger_data *charger = irq_drv_data;
+ struct max77705_charger_data *chg = irq_drv_data;
- queue_work(charger->wqueue, &charger->chgin_work);
+ queue_work(chg->wqueue, &chg->chgin_work);
return 0;
}
@@ -109,19 +109,19 @@ static int max77705_get_online(struct regmap *regmap, int *val)
return 0;
}
-static int max77705_check_battery(struct max77705_charger_data *charger, int *val)
+static int max77705_check_battery(struct max77705_charger_data *chg, int *val)
{
unsigned int reg_data;
unsigned int reg_data2;
- struct regmap *regmap = charger->regmap;
+ struct regmap *regmap = chg->regmap;
regmap_read(regmap, MAX77705_CHG_REG_INT_OK, ®_data);
- dev_dbg(charger->dev, "CHG_INT_OK(0x%x)\n", reg_data);
+ dev_dbg(chg->dev, "CHG_INT_OK(0x%x)\n", reg_data);
regmap_read(regmap, MAX77705_CHG_REG_DETAILS_00, ®_data2);
- dev_dbg(charger->dev, "CHG_DETAILS00(0x%x)\n", reg_data2);
+ dev_dbg(chg->dev, "CHG_DETAILS00(0x%x)\n", reg_data2);
if ((reg_data & MAX77705_BATP_OK) || !(reg_data2 & MAX77705_BATP_DTLS))
*val = true;
@@ -131,9 +131,9 @@ static int max77705_check_battery(struct max77705_charger_data *charger, int *va
return 0;
}
-static int max77705_get_charge_type(struct max77705_charger_data *charger, int *val)
+static int max77705_get_charge_type(struct max77705_charger_data *chg, int *val)
{
- struct regmap *regmap = charger->regmap;
+ struct regmap *regmap = chg->regmap;
unsigned int reg_data;
regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, ®_data);
@@ -159,9 +159,9 @@ static int max77705_get_charge_type(struct max77705_charger_data *charger, int *
return 0;
}
-static int max77705_get_status(struct max77705_charger_data *charger, int *val)
+static int max77705_get_status(struct max77705_charger_data *chg, int *val)
{
- struct regmap *regmap = charger->regmap;
+ struct regmap *regmap = chg->regmap;
unsigned int reg_data;
regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, ®_data);
@@ -234,10 +234,10 @@ static int max77705_get_vbus_state(struct regmap *regmap, int *value)
return 0;
}
-static int max77705_get_battery_health(struct max77705_charger_data *charger,
+static int max77705_get_battery_health(struct max77705_charger_data *chg,
int *value)
{
- struct regmap *regmap = charger->regmap;
+ struct regmap *regmap = chg->regmap;
unsigned int bat_dtls;
regmap_read(regmap, MAX77705_CHG_REG_DETAILS_01, &bat_dtls);
@@ -245,16 +245,16 @@ static int max77705_get_battery_health(struct max77705_charger_data *charger,
switch (bat_dtls) {
case MAX77705_BATTERY_NOBAT:
- dev_dbg(charger->dev, "%s: No battery and the charger is suspended\n",
+ dev_dbg(chg->dev, "%s: No battery and the chg is suspended\n",
__func__);
*value = POWER_SUPPLY_HEALTH_NO_BATTERY;
break;
case MAX77705_BATTERY_PREQUALIFICATION:
- dev_dbg(charger->dev, "%s: battery is okay but its voltage is low(~VPQLB)\n",
+ dev_dbg(chg->dev, "%s: battery is okay but its voltage is low(~VPQLB)\n",
__func__);
break;
case MAX77705_BATTERY_DEAD:
- dev_dbg(charger->dev, "%s: battery dead\n", __func__);
+ dev_dbg(chg->dev, "%s: battery dead\n", __func__);
*value = POWER_SUPPLY_HEALTH_DEAD;
break;
case MAX77705_BATTERY_GOOD:
@@ -262,11 +262,11 @@ static int max77705_get_battery_health(struct max77705_charger_data *charger,
*value = POWER_SUPPLY_HEALTH_GOOD;
break;
case MAX77705_BATTERY_OVERVOLTAGE:
- dev_dbg(charger->dev, "%s: battery ovp\n", __func__);
+ dev_dbg(chg->dev, "%s: battery ovp\n", __func__);
*value = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
break;
default:
- dev_dbg(charger->dev, "%s: battery unknown\n", __func__);
+ dev_dbg(chg->dev, "%s: battery unknown\n", __func__);
*value = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
break;
}
@@ -274,9 +274,9 @@ static int max77705_get_battery_health(struct max77705_charger_data *charger,
return 0;
}
-static int max77705_get_health(struct max77705_charger_data *charger, int *val)
+static int max77705_get_health(struct max77705_charger_data *chg, int *val)
{
- struct regmap *regmap = charger->regmap;
+ struct regmap *regmap = chg->regmap;
int ret, is_online = 0;
ret = max77705_get_online(regmap, &is_online);
@@ -287,15 +287,15 @@ static int max77705_get_health(struct max77705_charger_data *charger, int *val)
if (ret || (*val != POWER_SUPPLY_HEALTH_GOOD))
return ret;
}
- return max77705_get_battery_health(charger, val);
+ return max77705_get_battery_health(chg, val);
}
-static int max77705_get_input_current(struct max77705_charger_data *charger,
+static int max77705_get_input_current(struct max77705_charger_data *chg,
int *val)
{
unsigned int reg_data;
int get_current = 0;
- struct regmap *regmap = charger->regmap;
+ struct regmap *regmap = chg->regmap;
regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, ®_data);
@@ -313,11 +313,11 @@ static int max77705_get_input_current(struct max77705_charger_data *charger,
return 0;
}
-static int max77705_get_charge_current(struct max77705_charger_data *charger,
+static int max77705_get_charge_current(struct max77705_charger_data *chg,
int *val)
{
unsigned int reg_data;
- struct regmap *regmap = charger->regmap;
+ struct regmap *regmap = chg->regmap;
regmap_read(regmap, MAX77705_CHG_REG_CNFG_02, ®_data);
reg_data &= MAX77705_CHG_CC;
@@ -327,12 +327,12 @@ static int max77705_get_charge_current(struct max77705_charger_data *charger,
return 0;
}
-static int max77705_set_float_voltage(struct max77705_charger_data *charger,
+static int max77705_set_float_voltage(struct max77705_charger_data *chg,
int float_voltage)
{
int float_voltage_mv;
unsigned int reg_data = 0;
- struct regmap *regmap = charger->regmap;
+ struct regmap *regmap = chg->regmap;
float_voltage_mv = float_voltage / 1000;
reg_data = float_voltage_mv <= 4000 ? 0x0 :
@@ -345,12 +345,12 @@ static int max77705_set_float_voltage(struct max77705_charger_data *charger,
(reg_data << MAX77705_CHG_CV_PRM_SHIFT));
}
-static int max77705_get_float_voltage(struct max77705_charger_data *charger,
+static int max77705_get_float_voltage(struct max77705_charger_data *chg,
int *val)
{
unsigned int reg_data = 0;
int voltage_mv;
- struct regmap *regmap = charger->regmap;
+ struct regmap *regmap = chg->regmap;
regmap_read(regmap, MAX77705_CHG_REG_CNFG_04, ®_data);
reg_data &= MAX77705_CHG_PRM_MASK;
@@ -365,28 +365,28 @@ static int max77705_chg_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
- struct max77705_charger_data *charger = power_supply_get_drvdata(psy);
- struct regmap *regmap = charger->regmap;
+ struct max77705_charger_data *chg = power_supply_get_drvdata(psy);
+ struct regmap *regmap = chg->regmap;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
return max77705_get_online(regmap, &val->intval);
case POWER_SUPPLY_PROP_PRESENT:
- return max77705_check_battery(charger, &val->intval);
+ return max77705_check_battery(chg, &val->intval);
case POWER_SUPPLY_PROP_STATUS:
- return max77705_get_status(charger, &val->intval);
+ return max77705_get_status(chg, &val->intval);
case POWER_SUPPLY_PROP_CHARGE_TYPE:
- return max77705_get_charge_type(charger, &val->intval);
+ return max77705_get_charge_type(chg, &val->intval);
case POWER_SUPPLY_PROP_HEALTH:
- return max77705_get_health(charger, &val->intval);
+ return max77705_get_health(chg, &val->intval);
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
- return max77705_get_input_current(charger, &val->intval);
+ return max77705_get_input_current(chg, &val->intval);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
- return max77705_get_charge_current(charger, &val->intval);
+ return max77705_get_charge_current(chg, &val->intval);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
- return max77705_get_float_voltage(charger, &val->intval);
+ return max77705_get_float_voltage(chg, &val->intval);
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
- val->intval = charger->bat_info->voltage_max_design_uv;
+ val->intval = chg->bat_info->voltage_max_design_uv;
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = max77705_charger_model;
@@ -410,10 +410,10 @@ static const struct power_supply_desc max77705_charger_psy_desc = {
static void max77705_chgin_isr_work(struct work_struct *work)
{
- struct max77705_charger_data *charger =
+ struct max77705_charger_data *chg =
container_of(work, struct max77705_charger_data, chgin_work);
- power_supply_changed(charger->psy_chg);
+ power_supply_changed(chg->psy_chg);
}
static void max77705_charger_initialize(struct max77705_charger_data *chg)
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/9] power: supply: max77705_charger: use regfields for config registers
2025-08-30 20:45 [PATCH 0/9] power: supply: fixes and improvements for max77(705,976) chargers Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 1/9] power: supply: max77705_charger: move active discharge setting to mfd parent Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 2/9] power: supply: max77705_charger: refactoring: rename charger to chg Dzmitry Sankouski
@ 2025-08-30 20:45 ` Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 4/9] power: supply: max77705_charger: return error when config fails Dzmitry Sankouski
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Dzmitry Sankouski @ 2025-08-30 20:45 UTC (permalink / raw)
To: Chanwoo Choi, Krzysztof Kozlowski, Lee Jones, Sebastian Reichel,
Luca Ceresoli
Cc: Krzysztof Kozlowski, Sebastian Reichel, linux-kernel, linux-pm,
Dzmitry Sankouski
Using regfields allows to cleanup masks and register offset definition,
allowing to access register info by it's functional name.
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
drivers/power/supply/max77705_charger.c | 105 ++++++++++++--------------------
include/linux/power/max77705_charger.h | 99 ++++++++++++++++--------------
2 files changed, 92 insertions(+), 112 deletions(-)
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
index 7855f890e0a9..29bb763e56be 100644
--- a/drivers/power/supply/max77705_charger.c
+++ b/drivers/power/supply/max77705_charger.c
@@ -74,8 +74,7 @@ static int max77705_charger_enable(struct max77705_charger_data *chg)
{
int rv;
- rv = regmap_update_bits(chg->regmap, MAX77705_CHG_REG_CNFG_09,
- MAX77705_CHG_EN_MASK, MAX77705_CHG_EN_MASK);
+ rv = regmap_field_write(chg->rfield[MAX77705_CHG_EN], 1);
if (rv)
dev_err(chg->dev, "unable to enable the charger: %d\n", rv);
@@ -87,10 +86,7 @@ static void max77705_charger_disable(void *data)
struct max77705_charger_data *chg = data;
int rv;
- rv = regmap_update_bits(chg->regmap,
- MAX77705_CHG_REG_CNFG_09,
- MAX77705_CHG_EN_MASK,
- MAX77705_CHG_DISABLE);
+ rv = regmap_field_write(chg->rfield[MAX77705_CHG_EN], MAX77705_CHG_DISABLE);
if (rv)
dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
}
@@ -134,10 +130,10 @@ static int max77705_check_battery(struct max77705_charger_data *chg, int *val)
static int max77705_get_charge_type(struct max77705_charger_data *chg, int *val)
{
struct regmap *regmap = chg->regmap;
- unsigned int reg_data;
+ unsigned int reg_data, chg_en;
- regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, ®_data);
- if (!MAX77705_CHARGER_CHG_CHARGING(reg_data)) {
+ regmap_field_read(chg->rfield[MAX77705_CHG_EN], &chg_en);
+ if (!chg_en) {
*val = POWER_SUPPLY_CHARGE_TYPE_NONE;
return 0;
}
@@ -162,10 +158,10 @@ static int max77705_get_charge_type(struct max77705_charger_data *chg, int *val)
static int max77705_get_status(struct max77705_charger_data *chg, int *val)
{
struct regmap *regmap = chg->regmap;
- unsigned int reg_data;
+ unsigned int reg_data, chg_en;
- regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, ®_data);
- if (!MAX77705_CHARGER_CHG_CHARGING(reg_data)) {
+ regmap_field_read(chg->rfield[MAX77705_CHG_EN], &chg_en);
+ if (!chg_en) {
*val = POWER_SUPPLY_CHARGE_TYPE_NONE;
return 0;
}
@@ -295,16 +291,11 @@ static int max77705_get_input_current(struct max77705_charger_data *chg,
{
unsigned int reg_data;
int get_current = 0;
- struct regmap *regmap = chg->regmap;
- regmap_read(regmap, MAX77705_CHG_REG_CNFG_09, ®_data);
-
- reg_data &= MAX77705_CHG_CHGIN_LIM_MASK;
+ regmap_field_read(chg->rfield[MAX77705_CHG_CHGIN_LIM], ®_data);
if (reg_data <= 3)
get_current = MAX77705_CURRENT_CHGIN_MIN;
- else if (reg_data >= MAX77705_CHG_CHGIN_LIM_MASK)
- get_current = MAX77705_CURRENT_CHGIN_MAX;
else
get_current = (reg_data + 1) * MAX77705_CURRENT_CHGIN_STEP;
@@ -317,10 +308,8 @@ static int max77705_get_charge_current(struct max77705_charger_data *chg,
int *val)
{
unsigned int reg_data;
- struct regmap *regmap = chg->regmap;
- regmap_read(regmap, MAX77705_CHG_REG_CNFG_02, ®_data);
- reg_data &= MAX77705_CHG_CC;
+ regmap_field_read(chg->rfield[MAX77705_CHG_CC_LIM], ®_data);
*val = reg_data <= 0x2 ? MAX77705_CURRENT_CHGIN_MIN : reg_data * MAX77705_CURRENT_CHG_STEP;
@@ -332,7 +321,6 @@ static int max77705_set_float_voltage(struct max77705_charger_data *chg,
{
int float_voltage_mv;
unsigned int reg_data = 0;
- struct regmap *regmap = chg->regmap;
float_voltage_mv = float_voltage / 1000;
reg_data = float_voltage_mv <= 4000 ? 0x0 :
@@ -340,9 +328,7 @@ static int max77705_set_float_voltage(struct max77705_charger_data *chg,
(float_voltage_mv <= 4200) ? (float_voltage_mv - 4000) / 50 :
(((float_voltage_mv - 4200) / 10) + 0x04);
- return regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_04,
- MAX77705_CHG_CV_PRM_MASK,
- (reg_data << MAX77705_CHG_CV_PRM_SHIFT));
+ return regmap_field_write(chg->rfield[MAX77705_CHG_CV_PRM], reg_data);
}
static int max77705_get_float_voltage(struct max77705_charger_data *chg,
@@ -350,10 +336,8 @@ static int max77705_get_float_voltage(struct max77705_charger_data *chg,
{
unsigned int reg_data = 0;
int voltage_mv;
- struct regmap *regmap = chg->regmap;
- regmap_read(regmap, MAX77705_CHG_REG_CNFG_04, ®_data);
- reg_data &= MAX77705_CHG_PRM_MASK;
+ regmap_field_read(chg->rfield[MAX77705_CHG_CV_PRM], ®_data);
voltage_mv = reg_data <= 0x04 ? reg_data * 50 + 4000 :
(reg_data - 4) * 10 + 4200;
*val = voltage_mv * 1000;
@@ -418,7 +402,6 @@ static void max77705_chgin_isr_work(struct work_struct *work)
static void max77705_charger_initialize(struct max77705_charger_data *chg)
{
- u8 reg_data;
struct power_supply_battery_info *info;
struct regmap *regmap = chg->regmap;
@@ -429,45 +412,31 @@ static void max77705_charger_initialize(struct max77705_charger_data *chg)
/* unlock charger setting protect */
/* slowest LX slope */
- reg_data = MAX77705_CHGPROT_MASK | MAX77705_SLOWEST_LX_SLOPE;
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_06, reg_data,
- reg_data);
+ regmap_field_write(chg->rfield[MAX77705_CHGPROT], MAX77705_CHGPROT_MASK);
+ regmap_field_write(chg->rfield[MAX77705_LX_SLOPE], MAX77705_SLOWEST_LX_SLOPE);
/* fast charge timer disable */
/* restart threshold disable */
/* pre-qual charge disable */
- reg_data = (MAX77705_FCHGTIME_DISABLE << MAX77705_FCHGTIME_SHIFT) |
- (MAX77705_CHG_RSTRT_DISABLE << MAX77705_CHG_RSTRT_SHIFT) |
- (MAX77705_CHG_PQEN_DISABLE << MAX77705_PQEN_SHIFT);
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_01,
- (MAX77705_FCHGTIME_MASK |
- MAX77705_CHG_RSTRT_MASK |
- MAX77705_PQEN_MASK),
- reg_data);
-
- /* OTG off(UNO on), boost off */
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_00,
- MAX77705_OTG_CTRL, 0);
+ regmap_field_write(chg->rfield[MAX77705_FCHGTIME], MAX77705_FCHGTIME_DISABLE);
+ regmap_field_write(chg->rfield[MAX77705_CHG_RSTRT], MAX77705_CHG_RSTRT_DISABLE);
+ regmap_field_write(chg->rfield[MAX77705_CHG_PQEN], MAX77705_CHG_PQEN_DISABLE);
+
+ regmap_field_write(chg->rfield[MAX77705_MODE],
+ MAX77705_CHG_MASK | MAX77705_BUCK_MASK);
/* charge current 450mA(default) */
/* otg current limit 900mA */
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_02,
- MAX77705_OTG_ILIM_MASK,
- MAX77705_OTG_ILIM_900 << MAX77705_OTG_ILIM_SHIFT);
+ regmap_field_write(chg->rfield[MAX77705_OTG_ILIM], MAX77705_OTG_ILIM_900);
/* BAT to SYS OCP 4.80A */
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_05,
- MAX77705_REG_B2SOVRC_MASK,
- MAX77705_B2SOVRC_4_8A << MAX77705_REG_B2SOVRC_SHIFT);
+ regmap_field_write(chg->rfield[MAX77705_REG_B2SOVRC], MAX77705_B2SOVRC_4_8A);
+
/* top off current 150mA */
/* top off timer 30min */
- reg_data = (MAX77705_TO_ITH_150MA << MAX77705_TO_ITH_SHIFT) |
- (MAX77705_TO_TIME_30M << MAX77705_TO_TIME_SHIFT) |
- (MAX77705_SYS_TRACK_DISABLE << MAX77705_SYS_TRACK_DIS_SHIFT);
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_03,
- (MAX77705_TO_ITH_MASK |
- MAX77705_TO_TIME_MASK |
- MAX77705_SYS_TRACK_DIS_MASK), reg_data);
+ regmap_field_write(chg->rfield[MAX77705_TO], MAX77705_TO_ITH_150MA);
+ regmap_field_write(chg->rfield[MAX77705_TO_TIME], MAX77705_TO_TIME_30M);
+ regmap_field_write(chg->rfield[MAX77705_SYS_TRACK], MAX77705_SYS_TRACK_DISABLE);
/* cv voltage 4.2V or 4.35V */
/* MINVSYS 3.6V(default) */
@@ -478,25 +447,21 @@ static void max77705_charger_initialize(struct max77705_charger_data *chg)
max77705_set_float_voltage(chg, info->voltage_max_design_uv);
}
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_12,
- MAX77705_VCHGIN_REG_MASK, MAX77705_VCHGIN_4_5);
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_12,
- MAX77705_WCIN_REG_MASK, MAX77705_WCIN_4_5);
+ regmap_field_write(chg->rfield[MAX77705_VCHGIN], MAX77705_VCHGIN_4_5);
+ regmap_field_write(chg->rfield[MAX77705_WCIN], MAX77705_WCIN_4_5);
/* Watchdog timer */
regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_00,
MAX77705_WDTEN_MASK, 0);
/* VBYPSET=5.0V */
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_11, MAX77705_VBYPSET_MASK, 0);
+ regmap_field_write(chg->rfield[MAX77705_VBYPSET], 0);
/* Switching Frequency : 1.5MHz */
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_08, MAX77705_REG_FSW_MASK,
- (MAX77705_CHG_FSW_1_5MHz << MAX77705_REG_FSW_SHIFT));
+ regmap_field_write(chg->rfield[MAX77705_REG_FSW], MAX77705_CHG_FSW_1_5MHz);
/* Auto skip mode */
- regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_12, MAX77705_REG_DISKIP_MASK,
- (MAX77705_AUTO_SKIP << MAX77705_REG_DISKIP_SHIFT));
+ regmap_field_write(chg->rfield[MAX77705_REG_DISKIP], MAX77705_AUTO_SKIP);
}
static int max77705_charger_probe(struct i2c_client *i2c)
@@ -520,6 +485,14 @@ static int max77705_charger_probe(struct i2c_client *i2c)
if (IS_ERR(chg->regmap))
return PTR_ERR(chg->regmap);
+ for (int i = 0; i < MAX77705_N_REGMAP_FIELDS; i++) {
+ chg->rfield[i] = devm_regmap_field_alloc(dev, chg->regmap,
+ max77705_reg_field[i]);
+ if (IS_ERR(chg->rfield[i]))
+ return dev_err_probe(dev, PTR_ERR(chg->rfield[i]),
+ "cannot allocate regmap field\n");
+ }
+
ret = regmap_update_bits(chg->regmap,
MAX77705_CHG_REG_INT_MASK,
MAX77705_CHGIN_IM, 0);
diff --git a/include/linux/power/max77705_charger.h b/include/linux/power/max77705_charger.h
index fdec9af9c541..aec908ac5c01 100644
--- a/include/linux/power/max77705_charger.h
+++ b/include/linux/power/max77705_charger.h
@@ -9,6 +9,8 @@
#ifndef __MAX77705_CHARGER_H
#define __MAX77705_CHARGER_H __FILE__
+#include <linux/regmap.h>
+
/* MAX77705_CHG_REG_CHG_INT */
#define MAX77705_BYP_I BIT(0)
#define MAX77705_INP_LIMIT_I BIT(1)
@@ -63,7 +65,6 @@
#define MAX77705_BUCK_SHIFT 2
#define MAX77705_BOOST_SHIFT 3
#define MAX77705_WDTEN_SHIFT 4
-#define MAX77705_MODE_MASK GENMASK(3, 0)
#define MAX77705_CHG_MASK BIT(MAX77705_CHG_SHIFT)
#define MAX77705_UNO_MASK BIT(MAX77705_UNO_SHIFT)
#define MAX77705_OTG_MASK BIT(MAX77705_OTG_SHIFT)
@@ -74,34 +75,19 @@
#define MAX77705_OTG_CTRL (MAX77705_OTG_MASK | MAX77705_BOOST_MASK)
/* MAX77705_CHG_REG_CNFG_01 */
-#define MAX77705_FCHGTIME_SHIFT 0
-#define MAX77705_FCHGTIME_MASK GENMASK(2, 0)
-#define MAX77705_CHG_RSTRT_SHIFT 4
-#define MAX77705_CHG_RSTRT_MASK GENMASK(5, 4)
#define MAX77705_FCHGTIME_DISABLE 0
#define MAX77705_CHG_RSTRT_DISABLE 0x3
-#define MAX77705_PQEN_SHIFT 7
-#define MAX77705_PQEN_MASK BIT(7)
#define MAX77705_CHG_PQEN_DISABLE 0
#define MAX77705_CHG_PQEN_ENABLE 1
/* MAX77705_CHG_REG_CNFG_02 */
-#define MAX77705_OTG_ILIM_SHIFT 6
-#define MAX77705_OTG_ILIM_MASK GENMASK(7, 6)
#define MAX77705_OTG_ILIM_500 0
#define MAX77705_OTG_ILIM_900 1
#define MAX77705_OTG_ILIM_1200 2
#define MAX77705_OTG_ILIM_1500 3
-#define MAX77705_CHG_CC GENMASK(5, 0)
/* MAX77705_CHG_REG_CNFG_03 */
-#define MAX77705_TO_ITH_SHIFT 0
-#define MAX77705_TO_ITH_MASK GENMASK(2, 0)
-#define MAX77705_TO_TIME_SHIFT 3
-#define MAX77705_TO_TIME_MASK GENMASK(5, 3)
-#define MAX77705_SYS_TRACK_DIS_SHIFT 7
-#define MAX77705_SYS_TRACK_DIS_MASK BIT(7)
#define MAX77705_TO_ITH_150MA 0
#define MAX77705_TO_TIME_30M 3
#define MAX77705_SYS_TRACK_ENABLE 0
@@ -110,15 +96,8 @@
/* MAX77705_CHG_REG_CNFG_04 */
#define MAX77705_CHG_MINVSYS_SHIFT 6
#define MAX77705_CHG_MINVSYS_MASK GENMASK(7, 6)
-#define MAX77705_CHG_PRM_SHIFT 0
-#define MAX77705_CHG_PRM_MASK GENMASK(5, 0)
-
-#define MAX77705_CHG_CV_PRM_SHIFT 0
-#define MAX77705_CHG_CV_PRM_MASK GENMASK(5, 0)
/* MAX77705_CHG_REG_CNFG_05 */
-#define MAX77705_REG_B2SOVRC_SHIFT 0
-#define MAX77705_REG_B2SOVRC_MASK GENMASK(3, 0)
#define MAX77705_B2SOVRC_DISABLE 0
#define MAX77705_B2SOVRC_4_5A 6
#define MAX77705_B2SOVRC_4_8A 8
@@ -130,7 +109,7 @@
#define MAX77705_WDTCLR 1
#define MAX77705_CHGPROT_MASK GENMASK(3, 2)
#define MAX77705_CHGPROT_UNLOCKED GENMASK(3, 2)
-#define MAX77705_SLOWEST_LX_SLOPE GENMASK(6, 5)
+#define MAX77705_SLOWEST_LX_SLOPE 3
/* MAX77705_CHG_REG_CNFG_07 */
#define MAX77705_CHG_FMBST 4
@@ -140,36 +119,14 @@
#define MAX77705_REG_FGSRC_MASK BIT(MAX77705_REG_FGSRC_SHIFT)
/* MAX77705_CHG_REG_CNFG_08 */
-#define MAX77705_REG_FSW_SHIFT 0
-#define MAX77705_REG_FSW_MASK GENMASK(1, 0)
#define MAX77705_CHG_FSW_3MHz 0
#define MAX77705_CHG_FSW_2MHz 1
#define MAX77705_CHG_FSW_1_5MHz 2
/* MAX77705_CHG_REG_CNFG_09 */
-#define MAX77705_CHG_CHGIN_LIM_MASK GENMASK(6, 0)
-#define MAX77705_CHG_EN_MASK BIT(7)
#define MAX77705_CHG_DISABLE 0
-#define MAX77705_CHARGER_CHG_CHARGING(_reg) \
- (((_reg) & MAX77705_CHG_EN_MASK) > 1)
-
-
-/* MAX77705_CHG_REG_CNFG_10 */
-#define MAX77705_CHG_WCIN_LIM GENMASK(5, 0)
-
-/* MAX77705_CHG_REG_CNFG_11 */
-#define MAX77705_VBYPSET_SHIFT 0
-#define MAX77705_VBYPSET_MASK GENMASK(6, 0)
/* MAX77705_CHG_REG_CNFG_12 */
-#define MAX77705_CHGINSEL_SHIFT 5
-#define MAX77705_CHGINSEL_MASK BIT(MAX77705_CHGINSEL_SHIFT)
-#define MAX77705_WCINSEL_SHIFT 6
-#define MAX77705_WCINSEL_MASK BIT(MAX77705_WCINSEL_SHIFT)
-#define MAX77705_VCHGIN_REG_MASK GENMASK(4, 3)
-#define MAX77705_WCIN_REG_MASK GENMASK(2, 1)
-#define MAX77705_REG_DISKIP_SHIFT 0
-#define MAX77705_REG_DISKIP_MASK BIT(MAX77705_REG_DISKIP_SHIFT)
/* REG=4.5V, UVLO=4.7V */
#define MAX77705_VCHGIN_4_5 0
/* REG=4.5V, UVLO=4.7V */
@@ -183,9 +140,59 @@
#define MAX77705_CURRENT_CHGIN_MIN 100000
#define MAX77705_CURRENT_CHGIN_MAX 3200000
+enum max77705_field_idx {
+ MAX77705_CHGPROT,
+ MAX77705_CHG_EN,
+ MAX77705_CHG_CC_LIM,
+ MAX77705_CHG_CHGIN_LIM,
+ MAX77705_CHG_CV_PRM,
+ MAX77705_CHG_PQEN,
+ MAX77705_CHG_RSTRT,
+ MAX77705_CHG_WCIN,
+ MAX77705_FCHGTIME,
+ MAX77705_LX_SLOPE,
+ MAX77705_MODE,
+ MAX77705_OTG_ILIM,
+ MAX77705_REG_B2SOVRC,
+ MAX77705_REG_DISKIP,
+ MAX77705_REG_FSW,
+ MAX77705_SYS_TRACK,
+ MAX77705_TO,
+ MAX77705_TO_TIME,
+ MAX77705_VBYPSET,
+ MAX77705_VCHGIN,
+ MAX77705_WCIN,
+ MAX77705_N_REGMAP_FIELDS,
+};
+
+static const struct reg_field max77705_reg_field[MAX77705_N_REGMAP_FIELDS] = {
+ [MAX77705_MODE] = REG_FIELD(MAX77705_CHG_REG_CNFG_00, 0, 3),
+ [MAX77705_FCHGTIME] = REG_FIELD(MAX77705_CHG_REG_CNFG_01, 0, 2),
+ [MAX77705_CHG_RSTRT] = REG_FIELD(MAX77705_CHG_REG_CNFG_01, 4, 5),
+ [MAX77705_CHG_PQEN] = REG_FIELD(MAX77705_CHG_REG_CNFG_01, 7, 7),
+ [MAX77705_CHG_CC_LIM] = REG_FIELD(MAX77705_CHG_REG_CNFG_02, 0, 5),
+ [MAX77705_OTG_ILIM] = REG_FIELD(MAX77705_CHG_REG_CNFG_02, 6, 7),
+ [MAX77705_TO] = REG_FIELD(MAX77705_CHG_REG_CNFG_03, 0, 2),
+ [MAX77705_TO_TIME] = REG_FIELD(MAX77705_CHG_REG_CNFG_03, 3, 5),
+ [MAX77705_SYS_TRACK] = REG_FIELD(MAX77705_CHG_REG_CNFG_03, 7, 7),
+ [MAX77705_CHG_CV_PRM] = REG_FIELD(MAX77705_CHG_REG_CNFG_04, 0, 5),
+ [MAX77705_REG_B2SOVRC] = REG_FIELD(MAX77705_CHG_REG_CNFG_05, 0, 3),
+ [MAX77705_CHGPROT] = REG_FIELD(MAX77705_CHG_REG_CNFG_06, 2, 3),
+ [MAX77705_LX_SLOPE] = REG_FIELD(MAX77705_CHG_REG_CNFG_06, 5, 6),
+ [MAX77705_REG_FSW] = REG_FIELD(MAX77705_CHG_REG_CNFG_08, 0, 1),
+ [MAX77705_CHG_CHGIN_LIM] = REG_FIELD(MAX77705_CHG_REG_CNFG_09, 0, 6),
+ [MAX77705_CHG_EN] = REG_FIELD(MAX77705_CHG_REG_CNFG_09, 7, 7),
+ [MAX77705_CHG_WCIN] = REG_FIELD(MAX77705_CHG_REG_CNFG_10, 0, 5),
+ [MAX77705_VBYPSET] = REG_FIELD(MAX77705_CHG_REG_CNFG_11, 0, 6),
+ [MAX77705_REG_DISKIP] = REG_FIELD(MAX77705_CHG_REG_CNFG_12, 0, 0),
+ [MAX77705_WCIN] = REG_FIELD(MAX77705_CHG_REG_CNFG_12, 1, 2),
+ [MAX77705_VCHGIN] = REG_FIELD(MAX77705_CHG_REG_CNFG_12, 3, 4),
+};
+
struct max77705_charger_data {
struct device *dev;
struct regmap *regmap;
+ struct regmap_field *rfield[MAX77705_N_REGMAP_FIELDS];
struct power_supply_battery_info *bat_info;
struct workqueue_struct *wqueue;
struct work_struct chgin_work;
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/9] power: supply: max77705_charger: return error when config fails
2025-08-30 20:45 [PATCH 0/9] power: supply: fixes and improvements for max77(705,976) chargers Dzmitry Sankouski
` (2 preceding siblings ...)
2025-08-30 20:45 ` [PATCH 3/9] power: supply: max77705_charger: use regfields for config registers Dzmitry Sankouski
@ 2025-08-30 20:45 ` Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 5/9] power: supply: max77705_charger: add writable properties Dzmitry Sankouski
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Dzmitry Sankouski @ 2025-08-30 20:45 UTC (permalink / raw)
To: Chanwoo Choi, Krzysztof Kozlowski, Lee Jones, Sebastian Reichel,
Luca Ceresoli
Cc: Krzysztof Kozlowski, Sebastian Reichel, linux-kernel, linux-pm,
Dzmitry Sankouski
Handle error, returned from register writes in init function.
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
drivers/power/supply/max77705_charger.c | 90 +++++++++++++++++++++++++--------
1 file changed, 70 insertions(+), 20 deletions(-)
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
index 29bb763e56be..1cd122e96953 100644
--- a/drivers/power/supply/max77705_charger.c
+++ b/drivers/power/supply/max77705_charger.c
@@ -400,43 +400,72 @@ static void max77705_chgin_isr_work(struct work_struct *work)
power_supply_changed(chg->psy_chg);
}
-static void max77705_charger_initialize(struct max77705_charger_data *chg)
+static int max77705_charger_initialize(struct max77705_charger_data *chg)
{
struct power_supply_battery_info *info;
struct regmap *regmap = chg->regmap;
+ int err;
- if (power_supply_get_battery_info(chg->psy_chg, &info) < 0)
- return;
+ err = power_supply_get_battery_info(chg->psy_chg, &info);
+ if (err)
+ return dev_err_probe(chg->dev, err, "error on getting battery info");
chg->bat_info = info;
/* unlock charger setting protect */
/* slowest LX slope */
- regmap_field_write(chg->rfield[MAX77705_CHGPROT], MAX77705_CHGPROT_MASK);
- regmap_field_write(chg->rfield[MAX77705_LX_SLOPE], MAX77705_SLOWEST_LX_SLOPE);
+ err = regmap_field_write(chg->rfield[MAX77705_CHGPROT], MAX77705_CHGPROT_MASK);
+ if (err)
+ goto err;
+
+ err = regmap_field_write(chg->rfield[MAX77705_LX_SLOPE], MAX77705_SLOWEST_LX_SLOPE);
+ if (err)
+ goto err;
/* fast charge timer disable */
/* restart threshold disable */
/* pre-qual charge disable */
- regmap_field_write(chg->rfield[MAX77705_FCHGTIME], MAX77705_FCHGTIME_DISABLE);
- regmap_field_write(chg->rfield[MAX77705_CHG_RSTRT], MAX77705_CHG_RSTRT_DISABLE);
- regmap_field_write(chg->rfield[MAX77705_CHG_PQEN], MAX77705_CHG_PQEN_DISABLE);
+ err = regmap_field_write(chg->rfield[MAX77705_FCHGTIME], MAX77705_FCHGTIME_DISABLE);
+ if (err)
+ goto err;
+
+ err = regmap_field_write(chg->rfield[MAX77705_CHG_RSTRT], MAX77705_CHG_RSTRT_DISABLE);
+ if (err)
+ goto err;
- regmap_field_write(chg->rfield[MAX77705_MODE],
+ err = regmap_field_write(chg->rfield[MAX77705_CHG_PQEN], MAX77705_CHG_PQEN_DISABLE);
+ if (err)
+ goto err;
+
+ err = regmap_field_write(chg->rfield[MAX77705_MODE],
MAX77705_CHG_MASK | MAX77705_BUCK_MASK);
+ if (err)
+ goto err;
/* charge current 450mA(default) */
/* otg current limit 900mA */
- regmap_field_write(chg->rfield[MAX77705_OTG_ILIM], MAX77705_OTG_ILIM_900);
+ err = regmap_field_write(chg->rfield[MAX77705_OTG_ILIM], MAX77705_OTG_ILIM_900);
+ if (err)
+ goto err;
/* BAT to SYS OCP 4.80A */
- regmap_field_write(chg->rfield[MAX77705_REG_B2SOVRC], MAX77705_B2SOVRC_4_8A);
+ err = regmap_field_write(chg->rfield[MAX77705_REG_B2SOVRC], MAX77705_B2SOVRC_4_8A);
+ if (err)
+ goto err;
/* top off current 150mA */
/* top off timer 30min */
- regmap_field_write(chg->rfield[MAX77705_TO], MAX77705_TO_ITH_150MA);
- regmap_field_write(chg->rfield[MAX77705_TO_TIME], MAX77705_TO_TIME_30M);
- regmap_field_write(chg->rfield[MAX77705_SYS_TRACK], MAX77705_SYS_TRACK_DISABLE);
+ err = regmap_field_write(chg->rfield[MAX77705_TO], MAX77705_TO_ITH_150MA);
+ if (err)
+ goto err;
+
+ err = regmap_field_write(chg->rfield[MAX77705_TO_TIME], MAX77705_TO_TIME_30M);
+ if (err)
+ goto err;
+
+ err = regmap_field_write(chg->rfield[MAX77705_SYS_TRACK], MAX77705_SYS_TRACK_DISABLE);
+ if (err)
+ goto err;
/* cv voltage 4.2V or 4.35V */
/* MINVSYS 3.6V(default) */
@@ -447,21 +476,38 @@ static void max77705_charger_initialize(struct max77705_charger_data *chg)
max77705_set_float_voltage(chg, info->voltage_max_design_uv);
}
- regmap_field_write(chg->rfield[MAX77705_VCHGIN], MAX77705_VCHGIN_4_5);
- regmap_field_write(chg->rfield[MAX77705_WCIN], MAX77705_WCIN_4_5);
+ err = regmap_field_write(chg->rfield[MAX77705_VCHGIN], MAX77705_VCHGIN_4_5);
+ if (err)
+ goto err;
+
+ err = regmap_field_write(chg->rfield[MAX77705_WCIN], MAX77705_WCIN_4_5);
+ if (err)
+ goto err;
/* Watchdog timer */
regmap_update_bits(regmap, MAX77705_CHG_REG_CNFG_00,
MAX77705_WDTEN_MASK, 0);
/* VBYPSET=5.0V */
- regmap_field_write(chg->rfield[MAX77705_VBYPSET], 0);
+ err = regmap_field_write(chg->rfield[MAX77705_VBYPSET], 0);
+ if (err)
+ goto err;
/* Switching Frequency : 1.5MHz */
- regmap_field_write(chg->rfield[MAX77705_REG_FSW], MAX77705_CHG_FSW_1_5MHz);
+ err = regmap_field_write(chg->rfield[MAX77705_REG_FSW], MAX77705_CHG_FSW_1_5MHz);
+ if (err)
+ goto err;
/* Auto skip mode */
- regmap_field_write(chg->rfield[MAX77705_REG_DISKIP], MAX77705_AUTO_SKIP);
+ err = regmap_field_write(chg->rfield[MAX77705_REG_DISKIP], MAX77705_AUTO_SKIP);
+ if (err)
+ goto err;
+
+ return 0;
+
+err:
+ return dev_err_probe(chg->dev, err, "error while configuring");
+
}
static int max77705_charger_probe(struct i2c_client *i2c)
@@ -524,7 +570,11 @@ static int max77705_charger_probe(struct i2c_client *i2c)
goto destroy_wq;
}
- max77705_charger_initialize(chg);
+ ret = max77705_charger_initialize(chg);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to initialize charger IC\n");
+ goto destroy_wq;
+ }
ret = max77705_charger_enable(chg);
if (ret) {
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/9] power: supply: max77705_charger: add writable properties
2025-08-30 20:45 [PATCH 0/9] power: supply: fixes and improvements for max77(705,976) chargers Dzmitry Sankouski
` (3 preceding siblings ...)
2025-08-30 20:45 ` [PATCH 4/9] power: supply: max77705_charger: return error when config fails Dzmitry Sankouski
@ 2025-08-30 20:45 ` Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 6/9] power: supply: max77705_charger: rework interrupts Dzmitry Sankouski
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Dzmitry Sankouski @ 2025-08-30 20:45 UTC (permalink / raw)
To: Chanwoo Choi, Krzysztof Kozlowski, Lee Jones, Sebastian Reichel,
Luca Ceresoli
Cc: Krzysztof Kozlowski, Sebastian Reichel, linux-kernel, linux-pm,
Dzmitry Sankouski
Add INPUT_CURRENT_LIMIT, CONSTANT_CHARGE_CURRENT properties as writeable
to be able to control input power consumption and charging speed.
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
drivers/power/supply/max77705_charger.c | 54 +++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
index 1cd122e96953..de2184327ff8 100644
--- a/drivers/power/supply/max77705_charger.c
+++ b/drivers/power/supply/max77705_charger.c
@@ -105,6 +105,17 @@ static int max77705_get_online(struct regmap *regmap, int *val)
return 0;
}
+static int max77705_set_integer(struct max77705_charger_data *chg, enum max77705_field_idx fidx,
+ unsigned int clamp_min, unsigned int clamp_max,
+ unsigned int div, int val)
+{
+ unsigned int regval;
+
+ regval = clamp_val(val, clamp_min, clamp_max) / div;
+
+ return regmap_field_write(chg->rfield[fidx], regval);
+}
+
static int max77705_check_battery(struct max77705_charger_data *chg, int *val)
{
unsigned int reg_data;
@@ -384,12 +395,55 @@ static int max77705_chg_get_property(struct power_supply *psy,
return 0;
}
+static int max77705_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct max77705_charger_data *charger = power_supply_get_drvdata(psy);
+ int err = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ err = max77705_set_integer(charger, MAX77705_CHG_CC_LIM,
+ MAX77705_CURRENT_CHGIN_MIN,
+ MAX77705_CURRENT_CHGIN_MAX,
+ MAX77705_CURRENT_CHG_STEP,
+ val->intval);
+ break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ err = max77705_set_integer(charger, MAX77705_CHG_CHGIN_LIM,
+ MAX77705_CURRENT_CHGIN_MIN,
+ MAX77705_CURRENT_CHGIN_MAX,
+ MAX77705_CURRENT_CHGIN_STEP,
+ val->intval);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+};
+
+static int max77705_property_is_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct power_supply_desc max77705_charger_psy_desc = {
.name = "max77705-charger",
.type = POWER_SUPPLY_TYPE_USB,
.properties = max77705_charger_props,
+ .property_is_writeable = max77705_property_is_writeable,
.num_properties = ARRAY_SIZE(max77705_charger_props),
.get_property = max77705_chg_get_property,
+ .set_property = max77705_set_property,
};
static void max77705_chgin_isr_work(struct work_struct *work)
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/9] power: supply: max77705_charger: rework interrupts
2025-08-30 20:45 [PATCH 0/9] power: supply: fixes and improvements for max77(705,976) chargers Dzmitry Sankouski
` (4 preceding siblings ...)
2025-08-30 20:45 ` [PATCH 5/9] power: supply: max77705_charger: add writable properties Dzmitry Sankouski
@ 2025-08-30 20:45 ` Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 7/9] power: supply: max77705_charger: use REGMAP_IRQ_REG_LINE macro Dzmitry Sankouski
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Dzmitry Sankouski @ 2025-08-30 20:45 UTC (permalink / raw)
To: Chanwoo Choi, Krzysztof Kozlowski, Lee Jones, Sebastian Reichel,
Luca Ceresoli
Cc: Krzysztof Kozlowski, Sebastian Reichel, linux-kernel, linux-pm,
Dzmitry Sankouski
Current implementation uses handle_post_irq to actually handle chgin
irq. This is not how things are meant to work in regmap-irq.
Remove handle_post_irq, and request a threaded interrupt for chgin.
Fixes: a6a494c8e3ce ("power: supply: max77705: Add charger driver for Maxim 77705")
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
drivers/power/supply/max77705_charger.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
index de2184327ff8..a1b04ec8921e 100644
--- a/drivers/power/supply/max77705_charger.c
+++ b/drivers/power/supply/max77705_charger.c
@@ -40,13 +40,13 @@ static enum power_supply_property max77705_charger_props[] = {
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
};
-static int max77705_chgin_irq(void *irq_drv_data)
+static irqreturn_t max77705_chgin_irq(int irq, void *irq_drv_data)
{
struct max77705_charger_data *chg = irq_drv_data;
queue_work(chg->wqueue, &chg->chgin_work);
- return 0;
+ return IRQ_HANDLED;
}
static const struct regmap_irq max77705_charger_irqs[] = {
@@ -64,7 +64,6 @@ static struct regmap_irq_chip max77705_charger_irq_chip = {
.name = "max77705-charger",
.status_base = MAX77705_CHG_REG_INT,
.mask_base = MAX77705_CHG_REG_INT_MASK,
- .handle_post_irq = max77705_chgin_irq,
.num_regs = 1,
.irqs = max77705_charger_irqs,
.num_irqs = ARRAY_SIZE(max77705_charger_irqs),
@@ -593,12 +592,6 @@ static int max77705_charger_probe(struct i2c_client *i2c)
"cannot allocate regmap field\n");
}
- ret = regmap_update_bits(chg->regmap,
- MAX77705_CHG_REG_INT_MASK,
- MAX77705_CHGIN_IM, 0);
- if (ret)
- return ret;
-
pscfg.fwnode = dev_fwnode(dev);
pscfg.drv_data = chg;
@@ -614,6 +607,15 @@ static int max77705_charger_probe(struct i2c_client *i2c)
if (ret)
return dev_err_probe(dev, ret, "failed to add irq chip\n");
+ ret = devm_request_threaded_irq(dev, regmap_irq_get_virq(irq_data, MAX77705_CHGIN_I),
+ NULL, max77705_chgin_irq,
+ IRQF_TRIGGER_HIGH,
+ "chgin-irq", chg);
+ if (ret) {
+ pr_err("%s: Failed to Request IRQ (%d)\n", __func__, ret);
+ return ret;
+ }
+
chg->wqueue = create_singlethread_workqueue(dev_name(dev));
if (!chg->wqueue)
return dev_err_probe(dev, -ENOMEM, "failed to create workqueue\n");
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 7/9] power: supply: max77705_charger: use REGMAP_IRQ_REG_LINE macro
2025-08-30 20:45 [PATCH 0/9] power: supply: fixes and improvements for max77(705,976) chargers Dzmitry Sankouski
` (5 preceding siblings ...)
2025-08-30 20:45 ` [PATCH 6/9] power: supply: max77705_charger: rework interrupts Dzmitry Sankouski
@ 2025-08-30 20:45 ` Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 8/9] power: supply: max77705_charger: implement aicl feature Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 9/9] power: supply: max77976_charger: fix constant current reporting Dzmitry Sankouski
8 siblings, 0 replies; 10+ messages in thread
From: Dzmitry Sankouski @ 2025-08-30 20:45 UTC (permalink / raw)
To: Chanwoo Choi, Krzysztof Kozlowski, Lee Jones, Sebastian Reichel,
Luca Ceresoli
Cc: Krzysztof Kozlowski, Sebastian Reichel, linux-kernel, linux-pm,
Dzmitry Sankouski
Refactor regmap_irq declarations with REGMAP_IRQ_REG_LINE saves a few
lines on definitions.
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
drivers/power/supply/max77705_charger.c | 16 ++++++-------
include/linux/power/max77705_charger.h | 42 +++++++++++++--------------------
2 files changed, 24 insertions(+), 34 deletions(-)
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
index a1b04ec8921e..aa0ffa1fde39 100644
--- a/drivers/power/supply/max77705_charger.c
+++ b/drivers/power/supply/max77705_charger.c
@@ -50,14 +50,14 @@ static irqreturn_t max77705_chgin_irq(int irq, void *irq_drv_data)
}
static const struct regmap_irq max77705_charger_irqs[] = {
- { .mask = MAX77705_BYP_IM, },
- { .mask = MAX77705_INP_LIMIT_IM, },
- { .mask = MAX77705_BATP_IM, },
- { .mask = MAX77705_BAT_IM, },
- { .mask = MAX77705_CHG_IM, },
- { .mask = MAX77705_WCIN_IM, },
- { .mask = MAX77705_CHGIN_IM, },
- { .mask = MAX77705_AICL_IM, },
+ REGMAP_IRQ_REG_LINE(MAX77705_BYP_I, BITS_PER_BYTE),
+ REGMAP_IRQ_REG_LINE(MAX77705_INP_LIMIT_I, BITS_PER_BYTE),
+ REGMAP_IRQ_REG_LINE(MAX77705_BATP_I, BITS_PER_BYTE),
+ REGMAP_IRQ_REG_LINE(MAX77705_BAT_I, BITS_PER_BYTE),
+ REGMAP_IRQ_REG_LINE(MAX77705_CHG_I, BITS_PER_BYTE),
+ REGMAP_IRQ_REG_LINE(MAX77705_WCIN_I, BITS_PER_BYTE),
+ REGMAP_IRQ_REG_LINE(MAX77705_CHGIN_I, BITS_PER_BYTE),
+ REGMAP_IRQ_REG_LINE(MAX77705_AICL_I, BITS_PER_BYTE),
};
static struct regmap_irq_chip max77705_charger_irq_chip = {
diff --git a/include/linux/power/max77705_charger.h b/include/linux/power/max77705_charger.h
index aec908ac5c01..df1d46ff9527 100644
--- a/include/linux/power/max77705_charger.h
+++ b/include/linux/power/max77705_charger.h
@@ -12,34 +12,24 @@
#include <linux/regmap.h>
/* MAX77705_CHG_REG_CHG_INT */
-#define MAX77705_BYP_I BIT(0)
-#define MAX77705_INP_LIMIT_I BIT(1)
-#define MAX77705_BATP_I BIT(2)
-#define MAX77705_BAT_I BIT(3)
-#define MAX77705_CHG_I BIT(4)
-#define MAX77705_WCIN_I BIT(5)
-#define MAX77705_CHGIN_I BIT(6)
-#define MAX77705_AICL_I BIT(7)
-
-/* MAX77705_CHG_REG_CHG_INT_MASK */
-#define MAX77705_BYP_IM BIT(0)
-#define MAX77705_INP_LIMIT_IM BIT(1)
-#define MAX77705_BATP_IM BIT(2)
-#define MAX77705_BAT_IM BIT(3)
-#define MAX77705_CHG_IM BIT(4)
-#define MAX77705_WCIN_IM BIT(5)
-#define MAX77705_CHGIN_IM BIT(6)
-#define MAX77705_AICL_IM BIT(7)
+#define MAX77705_BYP_I (0)
+#define MAX77705_INP_LIMIT_I (1)
+#define MAX77705_BATP_I (2)
+#define MAX77705_BAT_I (3)
+#define MAX77705_CHG_I (4)
+#define MAX77705_WCIN_I (5)
+#define MAX77705_CHGIN_I (6)
+#define MAX77705_AICL_I (7)
/* MAX77705_CHG_REG_CHG_INT_OK */
-#define MAX77705_BYP_OK BIT(0)
-#define MAX77705_DISQBAT_OK BIT(1)
-#define MAX77705_BATP_OK BIT(2)
-#define MAX77705_BAT_OK BIT(3)
-#define MAX77705_CHG_OK BIT(4)
-#define MAX77705_WCIN_OK BIT(5)
-#define MAX77705_CHGIN_OK BIT(6)
-#define MAX77705_AICL_OK BIT(7)
+#define MAX77705_BYP_OK BIT(MAX77705_BYP_I)
+#define MAX77705_DISQBAT_OK BIT(MAX77705_INP_LIMIT_I)
+#define MAX77705_BATP_OK BIT(MAX77705_BATP_I)
+#define MAX77705_BAT_OK BIT(MAX77705_BAT_I)
+#define MAX77705_CHG_OK BIT(MAX77705_CHG_I)
+#define MAX77705_WCIN_OK BIT(MAX77705_WCIN_I)
+#define MAX77705_CHGIN_OK BIT(MAX77705_CHGIN_I)
+#define MAX77705_AICL_OK BIT(MAX77705_AICL_I)
/* MAX77705_CHG_REG_DETAILS_00 */
#define MAX77705_BATP_DTLS BIT(0)
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 8/9] power: supply: max77705_charger: implement aicl feature
2025-08-30 20:45 [PATCH 0/9] power: supply: fixes and improvements for max77(705,976) chargers Dzmitry Sankouski
` (6 preceding siblings ...)
2025-08-30 20:45 ` [PATCH 7/9] power: supply: max77705_charger: use REGMAP_IRQ_REG_LINE macro Dzmitry Sankouski
@ 2025-08-30 20:45 ` Dzmitry Sankouski
2025-08-30 20:45 ` [PATCH 9/9] power: supply: max77976_charger: fix constant current reporting Dzmitry Sankouski
8 siblings, 0 replies; 10+ messages in thread
From: Dzmitry Sankouski @ 2025-08-30 20:45 UTC (permalink / raw)
To: Chanwoo Choi, Krzysztof Kozlowski, Lee Jones, Sebastian Reichel,
Luca Ceresoli
Cc: Krzysztof Kozlowski, Sebastian Reichel, linux-kernel, linux-pm,
Dzmitry Sankouski
Adaptive input current allows charger to reduce it's current
consumption, when source is not able to provide enough power.
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
drivers/power/supply/max77705_charger.c | 60 +++++++++++++++++++++++++++++++++
include/linux/power/max77705_charger.h | 5 +++
2 files changed, 65 insertions(+)
diff --git a/drivers/power/supply/max77705_charger.c b/drivers/power/supply/max77705_charger.c
index aa0ffa1fde39..a82e32483ae5 100644
--- a/drivers/power/supply/max77705_charger.c
+++ b/drivers/power/supply/max77705_charger.c
@@ -40,6 +40,16 @@ static enum power_supply_property max77705_charger_props[] = {
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
};
+static irqreturn_t max77705_aicl_irq(int irq, void *irq_drv_data)
+{
+ struct max77705_charger_data *chg = irq_drv_data;
+
+ queue_delayed_work(chg->wqueue, &chg->aicl_work,
+ msecs_to_jiffies(AICL_WORK_DELAY));
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t max77705_chgin_irq(int irq, void *irq_drv_data)
{
struct max77705_charger_data *chg = irq_drv_data;
@@ -445,6 +455,40 @@ static const struct power_supply_desc max77705_charger_psy_desc = {
.set_property = max77705_set_property,
};
+static void max77705_aicl_isr_work(struct work_struct *work)
+{
+ unsigned int regval, irq_status;
+ int err;
+ struct max77705_charger_data *chg =
+ container_of(work, struct max77705_charger_data, aicl_work.work);
+
+ regmap_read(chg->regmap, MAX77705_CHG_REG_INT_OK, &irq_status);
+ if (!chg->is_aicl_irq_disabled) {
+ disable_irq(chg->aicl_irq);
+ chg->is_aicl_irq_disabled = true;
+ }
+
+ if (!(irq_status & BIT(MAX77705_AICL_I))) {
+ err = regmap_field_read(chg->rfield[MAX77705_CHG_CHGIN_LIM], ®val);
+ if (err < 0)
+ return;
+
+ regval--;
+
+ pr_info("aicl call. regval: %d\n", regval);
+ err = regmap_field_write(chg->rfield[MAX77705_CHG_CHGIN_LIM], regval);
+ if (err < 0)
+ return;
+
+ queue_delayed_work(chg->wqueue, &chg->aicl_work,
+ msecs_to_jiffies(AICL_WORK_DELAY));
+ } else {
+ pr_info("aicl finish\n");
+ enable_irq(chg->aicl_irq);
+ chg->is_aicl_irq_disabled = false;
+ }
+}
+
static void max77705_chgin_isr_work(struct work_struct *work)
{
struct max77705_charger_data *chg =
@@ -616,6 +660,16 @@ static int max77705_charger_probe(struct i2c_client *i2c)
return ret;
}
+ chg->aicl_irq = regmap_irq_get_virq(irq_data, MAX77705_AICL_I);
+ ret = devm_request_threaded_irq(dev, chg->aicl_irq,
+ NULL, max77705_aicl_irq,
+ IRQF_TRIGGER_HIGH,
+ "aicl-irq", chg);
+ if (ret) {
+ pr_err("%s: Failed to Request IRQ (%d)\n", __func__, ret);
+ return ret;
+ }
+
chg->wqueue = create_singlethread_workqueue(dev_name(dev));
if (!chg->wqueue)
return dev_err_probe(dev, -ENOMEM, "failed to create workqueue\n");
@@ -626,6 +680,12 @@ static int max77705_charger_probe(struct i2c_client *i2c)
goto destroy_wq;
}
+ ret = devm_delayed_work_autocancel(dev, &chg->aicl_work, max77705_aicl_isr_work);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to initialize interrupt work\n");
+ goto destroy_wq;
+ }
+
ret = max77705_charger_initialize(chg);
if (ret) {
dev_err_probe(dev, ret, "failed to initialize charger IC\n");
diff --git a/include/linux/power/max77705_charger.h b/include/linux/power/max77705_charger.h
index df1d46ff9527..da048dda4e44 100644
--- a/include/linux/power/max77705_charger.h
+++ b/include/linux/power/max77705_charger.h
@@ -124,6 +124,8 @@
#define MAX77705_DISABLE_SKIP 1
#define MAX77705_AUTO_SKIP 0
+#define AICL_WORK_DELAY 100
+
/* uA */
#define MAX77705_CURRENT_CHGIN_STEP 25000
#define MAX77705_CURRENT_CHG_STEP 50000
@@ -186,7 +188,10 @@ struct max77705_charger_data {
struct power_supply_battery_info *bat_info;
struct workqueue_struct *wqueue;
struct work_struct chgin_work;
+ struct delayed_work aicl_work;
struct power_supply *psy_chg;
+ int is_aicl_irq_disabled;
+ int aicl_irq;
};
#endif /* __MAX77705_CHARGER_H */
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 9/9] power: supply: max77976_charger: fix constant current reporting
2025-08-30 20:45 [PATCH 0/9] power: supply: fixes and improvements for max77(705,976) chargers Dzmitry Sankouski
` (7 preceding siblings ...)
2025-08-30 20:45 ` [PATCH 8/9] power: supply: max77705_charger: implement aicl feature Dzmitry Sankouski
@ 2025-08-30 20:45 ` Dzmitry Sankouski
8 siblings, 0 replies; 10+ messages in thread
From: Dzmitry Sankouski @ 2025-08-30 20:45 UTC (permalink / raw)
To: Chanwoo Choi, Krzysztof Kozlowski, Lee Jones, Sebastian Reichel,
Luca Ceresoli
Cc: Krzysztof Kozlowski, Sebastian Reichel, linux-kernel, linux-pm,
Dzmitry Sankouski
CHARGE_CONTROL_LIMIT is a wrong property to report charge current limit,
because `CHARGE_*` attributes represents capacity, not current. The
correct attribute to report and set charge current limit is
CONSTANT_CHARGE_CURRENT.
Rename CHARGE_CONTROL_LIMIT to CONSTANT_CHARGE_CURRENT.
Fixes: 715ecbc10d6a ("power: supply: max77976: add Maxim MAX77976 charger driver")
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
drivers/power/supply/max77976_charger.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/power/supply/max77976_charger.c b/drivers/power/supply/max77976_charger.c
index e6fe68cebc32..3d6ff4005533 100644
--- a/drivers/power/supply/max77976_charger.c
+++ b/drivers/power/supply/max77976_charger.c
@@ -292,10 +292,10 @@ static int max77976_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_ONLINE:
err = max77976_get_online(chg, &val->intval);
break;
- case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = MAX77976_CHG_CC_MAX;
break;
- case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
err = max77976_get_integer(chg, CHG_CC,
MAX77976_CHG_CC_MIN,
MAX77976_CHG_CC_MAX,
@@ -330,7 +330,7 @@ static int max77976_set_property(struct power_supply *psy,
int err = 0;
switch (psp) {
- case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
err = max77976_set_integer(chg, CHG_CC,
MAX77976_CHG_CC_MIN,
MAX77976_CHG_CC_MAX,
@@ -355,7 +355,7 @@ static int max77976_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
- case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return true;
default:
@@ -368,8 +368,8 @@ static enum power_supply_property max77976_psy_props[] = {
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_ONLINE,
- POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
- POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread