* [PATCH v7 0/7] Add support for the TI BQ25792 battery charger
@ 2026-06-02 20:10 Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 1/7] regulator: bq257xx: Drop the regulator_dev from the driver data Alexey Charkov
` (7 more replies)
0 siblings, 8 replies; 10+ messages in thread
From: Alexey Charkov @ 2026-06-02 20:10 UTC (permalink / raw)
To: Chris Morgan, Mark Brown, Sebastian Reichel, Liam Girdwood,
Lee Jones
Cc: linux-kernel, Sebastian Reichel, linux-pm, Alexey Charkov, stable
This adds support for the TI BQ25792 battery charger, which is similar in
overall logic to the BQ25703A, but has a different register layout and
slightly different lower-level programming logic.
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
Changes in v7:
- Rebase onto recent -next and dropped patches already applied by Mark and Lee
- Enable the Input Current Optimizer to improve reliability with unrecognized chargers
- Explicitly program the battery cell count at init time to alleviate transient glitches
with the charger going into spurious battery overvoltage state due to misdetected
battery cell count
- Handle return values of all regmap writes in the init function
- Link to v6: https://lore.kernel.org/r/20260331-bq25792-v6-0-0278fba33eb9@flipper.net
Changes in v6:
- Changed -EINVAL to -ENODEV for non-match cases in the MFD driver, to stay
in line with what other drivers do in similar situations (Lee Jones)
- Link to v5: https://lore.kernel.org/r/20260324-bq25792-v5-0-0a2eb58cf11d@flipper.net
Changes in v5:
- Added non-OF match data and switched to i2c_get_match_data() to support
non-OF platforms (Lee Jones)
- Shifted the types in the enum to start at 1 to avoid confusion with
zero-initialized data and non-match cases (Lee Jones)
- Reinstated the const qualifier on the MFD cell array (Lee Jones)
- Link to v4: https://lore.kernel.org/r/20260311-bq25792-v4-0-7213415d9eec@flipper.net
Changes in v4:
- Avoid additional data structures and pass 'type' within the existing
struct bq257xx_device instead (Lee Jones)
- Move comments for new struct fields to the patches where those fields
are added (Sebastian Reichel)
- Collect tags from Sebastian Reichel (thanks!)
- Link to v3: https://lore.kernel.org/r/20260310-bq25792-v3-0-02f8e232d63b@flipper.net
Changes in v3:
- Move MFD cell definitions back out of the probe function (Lee Jones)
- Collect tags from Mark Brown, Krzysztof Kozlowski and Chris Morgan (thanks!)
- Enable ship FET functionality at init for BQ25792
- Link to v2: https://lore.kernel.org/r/20260306-bq25792-v2-0-6595249d6e6f@flipper.net
Changes in v2:
- Fix an error in DT schema (thanks Rob's bot)
- Ensure the broadest constraints for all variants remain in the common
part of the schema, per writing-schema doc (thanks Krzysztof)
- Link to v1: https://lore.kernel.org/r/20260303-bq25792-v1-0-e6e5e0033458@flipper.net
---
Alexey Charkov (7):
regulator: bq257xx: Drop the regulator_dev from the driver data
power: supply: bq257xx: Fix VSYSMIN clamping logic
power: supply: bq257xx: Make the default current limit a per-chip attribute
power: supply: bq257xx: Consistently use indirect get/set helpers
power: supply: bq257xx: Add fields for 'charging' and 'overvoltage' states
regulator: bq257xx: Add support for BQ25792
power: supply: bq257xx: Add support for BQ25792
drivers/power/supply/bq257xx_charger.c | 580 ++++++++++++++++++++++++++++++++-
drivers/regulator/bq257xx-regulator.c | 106 +++++-
include/linux/mfd/bq257xx.h | 14 +
3 files changed, 681 insertions(+), 19 deletions(-)
---
base-commit: 08484c504b55a98bd100527fbe10a3caf55ff3ff
change-id: 20260303-bq25792-0132ac86846d
Best regards,
--
Alexey Charkov <alchark@flipper.net>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v7 1/7] regulator: bq257xx: Drop the regulator_dev from the driver data
2026-06-02 20:10 [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Alexey Charkov
@ 2026-06-02 20:10 ` Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 2/7] power: supply: bq257xx: Fix VSYSMIN clamping logic Alexey Charkov
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Alexey Charkov @ 2026-06-02 20:10 UTC (permalink / raw)
To: Chris Morgan, Mark Brown, Sebastian Reichel, Liam Girdwood,
Lee Jones
Cc: linux-kernel, Sebastian Reichel, linux-pm, Alexey Charkov
The field was not used anywhere in the driver, so just drop it. This helps
further slim down the platform data structure.
Acked-by: Mark Brown <broonie@kernel.org>
Tested-by: Chris Morgan <macromorgan@hotmail.com>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/regulator/bq257xx-regulator.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c
index 09c466052c04..913ca9186bf1 100644
--- a/drivers/regulator/bq257xx-regulator.c
+++ b/drivers/regulator/bq257xx-regulator.c
@@ -15,7 +15,6 @@
#include <linux/regulator/of_regulator.h>
struct bq257xx_reg_data {
- struct regulator_dev *bq257xx_reg;
struct gpio_desc *otg_en_gpio;
struct regulator_desc desc;
};
@@ -145,6 +144,7 @@ static int bq257xx_regulator_probe(struct platform_device *pdev)
struct bq257xx_reg_data *pdata;
struct device_node *np = dev->of_node;
struct regulator_config cfg = {};
+ struct regulator_dev *rdev;
device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
@@ -164,9 +164,9 @@ static int bq257xx_regulator_probe(struct platform_device *pdev)
if (!cfg.regmap)
return -ENODEV;
- pdata->bq257xx_reg = devm_regulator_register(dev, &pdata->desc, &cfg);
- if (IS_ERR(pdata->bq257xx_reg)) {
- return dev_err_probe(&pdev->dev, PTR_ERR(pdata->bq257xx_reg),
+ rdev = devm_regulator_register(dev, &pdata->desc, &cfg);
+ if (IS_ERR(rdev)) {
+ return dev_err_probe(&pdev->dev, PTR_ERR(rdev),
"error registering bq257xx regulator");
}
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v7 2/7] power: supply: bq257xx: Fix VSYSMIN clamping logic
2026-06-02 20:10 [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 1/7] regulator: bq257xx: Drop the regulator_dev from the driver data Alexey Charkov
@ 2026-06-02 20:10 ` Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 3/7] power: supply: bq257xx: Make the default current limit a per-chip attribute Alexey Charkov
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Alexey Charkov @ 2026-06-02 20:10 UTC (permalink / raw)
To: Chris Morgan, Mark Brown, Sebastian Reichel, Liam Girdwood,
Lee Jones
Cc: linux-kernel, Sebastian Reichel, linux-pm, Alexey Charkov, stable
The minimal system voltage (VSYSMIN) is meant to protect the battery from
dangerous over-discharge. When the device tree provides a value for the
minimum design voltage of the battery, the user should not be allowed to
set a lower VSYSMIN, as that would defeat the purpose of this protection.
Flip the clamping logic when setting VSYSMIN to ensure that battery design
voltage is respected.
Cc: stable@vger.kernel.org
Fixes: 1cc017b7f9c7 ("power: supply: bq257xx: Add support for BQ257XX charger")
Tested-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/power/supply/bq257xx_charger.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/power/supply/bq257xx_charger.c b/drivers/power/supply/bq257xx_charger.c
index 02c7d8b61e82..7ca4ae610902 100644
--- a/drivers/power/supply/bq257xx_charger.c
+++ b/drivers/power/supply/bq257xx_charger.c
@@ -128,9 +128,8 @@ static int bq25703_get_min_vsys(struct bq257xx_chg *pdata, int *intval)
* @vsys: voltage value to set in uV.
*
* This function takes a requested minimum system voltage value, clamps
- * it between the minimum supported value by the charger and a user
- * defined minimum system value, and then writes the value to the
- * appropriate register.
+ * it between the user defined minimum system value and the maximum supported
+ * value by the charger, and then writes the value to the appropriate register.
*
* Return: Returns 0 on success or error if an error occurs.
*/
@@ -139,7 +138,7 @@ static int bq25703_set_min_vsys(struct bq257xx_chg *pdata, int vsys)
unsigned int reg;
int vsys_min = pdata->vsys_min;
- vsys = clamp(vsys, BQ25703_MINVSYS_MIN_UV, vsys_min);
+ vsys = clamp(vsys, vsys_min, BQ25703_MINVSYS_MAX_UV);
reg = ((vsys - BQ25703_MINVSYS_MIN_UV) / BQ25703_MINVSYS_STEP_UV);
reg = FIELD_PREP(BQ25703_MINVSYS_MASK, reg);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v7 3/7] power: supply: bq257xx: Make the default current limit a per-chip attribute
2026-06-02 20:10 [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 1/7] regulator: bq257xx: Drop the regulator_dev from the driver data Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 2/7] power: supply: bq257xx: Fix VSYSMIN clamping logic Alexey Charkov
@ 2026-06-02 20:10 ` Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 4/7] power: supply: bq257xx: Consistently use indirect get/set helpers Alexey Charkov
` (4 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Alexey Charkov @ 2026-06-02 20:10 UTC (permalink / raw)
To: Chris Morgan, Mark Brown, Sebastian Reichel, Liam Girdwood,
Lee Jones
Cc: linux-kernel, Sebastian Reichel, linux-pm, Alexey Charkov
Add a field for the default current limit to the bq257xx_info structure and
use it instead of the hardcoded value in the probe function.
This prepares the driver for allowing different electrical constraints for
different chip variants.
Tested-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/power/supply/bq257xx_charger.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/power/supply/bq257xx_charger.c b/drivers/power/supply/bq257xx_charger.c
index 7ca4ae610902..39718223c3f9 100644
--- a/drivers/power/supply/bq257xx_charger.c
+++ b/drivers/power/supply/bq257xx_charger.c
@@ -18,6 +18,7 @@ struct bq257xx_chg;
/**
* struct bq257xx_chip_info - chip specific routines
+ * @default_iindpm_uA: default input current limit in microamps
* @bq257xx_hw_init: init function for hw
* @bq257xx_hw_shutdown: shutdown function for hw
* @bq257xx_get_state: get and update state of hardware
@@ -26,6 +27,7 @@ struct bq257xx_chg;
* @bq257xx_set_iindpm: set maximum input current (in uA)
*/
struct bq257xx_chip_info {
+ int default_iindpm_uA;
int (*bq257xx_hw_init)(struct bq257xx_chg *pdata);
void (*bq257xx_hw_shutdown)(struct bq257xx_chg *pdata);
int (*bq257xx_get_state)(struct bq257xx_chg *pdata);
@@ -627,6 +629,7 @@ static const struct power_supply_desc bq257xx_power_supply_desc = {
};
static const struct bq257xx_chip_info bq25703_chip_info = {
+ .default_iindpm_uA = BQ25703_IINDPM_DEFAULT_UA,
.bq257xx_hw_init = &bq25703_hw_init,
.bq257xx_hw_shutdown = &bq25703_hw_shutdown,
.bq257xx_get_state = &bq25703_get_state,
@@ -675,7 +678,7 @@ static int bq257xx_parse_dt(struct bq257xx_chg *pdata,
"input-current-limit-microamp",
&pdata->iindpm_max);
if (ret)
- pdata->iindpm_max = BQ25703_IINDPM_DEFAULT_UA;
+ pdata->iindpm_max = pdata->chip->default_iindpm_uA;
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v7 4/7] power: supply: bq257xx: Consistently use indirect get/set helpers
2026-06-02 20:10 [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Alexey Charkov
` (2 preceding siblings ...)
2026-06-02 20:10 ` [PATCH v7 3/7] power: supply: bq257xx: Make the default current limit a per-chip attribute Alexey Charkov
@ 2026-06-02 20:10 ` Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 5/7] power: supply: bq257xx: Add fields for 'charging' and 'overvoltage' states Alexey Charkov
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Alexey Charkov @ 2026-06-02 20:10 UTC (permalink / raw)
To: Chris Morgan, Mark Brown, Sebastian Reichel, Liam Girdwood,
Lee Jones
Cc: linux-kernel, Sebastian Reichel, linux-pm, Alexey Charkov
Move the remaining get/set helper functions to indirect calls via the
per-chip bq257xx_chip_info struct.
This improves the consistency of the code and prepares the driver to
support multiple chip variants with different register layouts and bit
definitions.
Tested-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/power/supply/bq257xx_charger.c | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/power/supply/bq257xx_charger.c b/drivers/power/supply/bq257xx_charger.c
index 39718223c3f9..0765673728e4 100644
--- a/drivers/power/supply/bq257xx_charger.c
+++ b/drivers/power/supply/bq257xx_charger.c
@@ -22,18 +22,30 @@ struct bq257xx_chg;
* @bq257xx_hw_init: init function for hw
* @bq257xx_hw_shutdown: shutdown function for hw
* @bq257xx_get_state: get and update state of hardware
+ * @bq257xx_get_ichg: get maximum charge current (in uA)
* @bq257xx_set_ichg: set maximum charge current (in uA)
+ * @bq257xx_get_vbatreg: get maximum charge voltage (in uV)
* @bq257xx_set_vbatreg: set maximum charge voltage (in uV)
+ * @bq257xx_get_iindpm: get maximum input current (in uA)
* @bq257xx_set_iindpm: set maximum input current (in uA)
+ * @bq257xx_get_cur: get battery current from ADC (in uA)
+ * @bq257xx_get_vbat: get battery voltage from ADC (in uV)
+ * @bq257xx_get_min_vsys: get minimum system voltage (in uV)
*/
struct bq257xx_chip_info {
int default_iindpm_uA;
int (*bq257xx_hw_init)(struct bq257xx_chg *pdata);
void (*bq257xx_hw_shutdown)(struct bq257xx_chg *pdata);
int (*bq257xx_get_state)(struct bq257xx_chg *pdata);
+ int (*bq257xx_get_ichg)(struct bq257xx_chg *pdata, int *intval);
int (*bq257xx_set_ichg)(struct bq257xx_chg *pdata, int ichg);
+ int (*bq257xx_get_vbatreg)(struct bq257xx_chg *pdata, int *intval);
int (*bq257xx_set_vbatreg)(struct bq257xx_chg *pdata, int vbatreg);
+ int (*bq257xx_get_iindpm)(struct bq257xx_chg *pdata, int *intval);
int (*bq257xx_set_iindpm)(struct bq257xx_chg *pdata, int iindpm);
+ int (*bq257xx_get_cur)(struct bq257xx_chg *pdata, int *intval);
+ int (*bq257xx_get_vbat)(struct bq257xx_chg *pdata, int *intval);
+ int (*bq257xx_get_min_vsys)(struct bq257xx_chg *pdata, int *intval);
};
/**
@@ -490,22 +502,22 @@ static int bq257xx_get_charger_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
- return bq25703_get_iindpm(pdata, &val->intval);
+ return pdata->chip->bq257xx_get_iindpm(pdata, &val->intval);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
- return bq25703_get_chrg_volt(pdata, &val->intval);
+ return pdata->chip->bq257xx_get_vbatreg(pdata, &val->intval);
case POWER_SUPPLY_PROP_CURRENT_NOW:
- return bq25703_get_cur(pdata, &val->intval);
+ return pdata->chip->bq257xx_get_cur(pdata, &val->intval);
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- return bq25703_get_vbat(pdata, &val->intval);
+ return pdata->chip->bq257xx_get_vbat(pdata, &val->intval);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
- return bq25703_get_ichg_cur(pdata, &val->intval);
+ return pdata->chip->bq257xx_get_ichg(pdata, &val->intval);
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
- return bq25703_get_min_vsys(pdata, &val->intval);
+ return pdata->chip->bq257xx_get_min_vsys(pdata, &val->intval);
case POWER_SUPPLY_PROP_USB_TYPE:
val->intval = pdata->usb_type;
@@ -633,9 +645,15 @@ static const struct bq257xx_chip_info bq25703_chip_info = {
.bq257xx_hw_init = &bq25703_hw_init,
.bq257xx_hw_shutdown = &bq25703_hw_shutdown,
.bq257xx_get_state = &bq25703_get_state,
+ .bq257xx_get_ichg = &bq25703_get_ichg_cur,
.bq257xx_set_ichg = &bq25703_set_ichg_cur,
+ .bq257xx_get_vbatreg = &bq25703_get_chrg_volt,
.bq257xx_set_vbatreg = &bq25703_set_chrg_volt,
+ .bq257xx_get_iindpm = &bq25703_get_iindpm,
.bq257xx_set_iindpm = &bq25703_set_iindpm,
+ .bq257xx_get_cur = &bq25703_get_cur,
+ .bq257xx_get_vbat = &bq25703_get_vbat,
+ .bq257xx_get_min_vsys = &bq25703_get_min_vsys,
};
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v7 5/7] power: supply: bq257xx: Add fields for 'charging' and 'overvoltage' states
2026-06-02 20:10 [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Alexey Charkov
` (3 preceding siblings ...)
2026-06-02 20:10 ` [PATCH v7 4/7] power: supply: bq257xx: Consistently use indirect get/set helpers Alexey Charkov
@ 2026-06-02 20:10 ` Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 6/7] regulator: bq257xx: Add support for BQ25792 Alexey Charkov
` (2 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Alexey Charkov @ 2026-06-02 20:10 UTC (permalink / raw)
To: Chris Morgan, Mark Brown, Sebastian Reichel, Liam Girdwood,
Lee Jones
Cc: linux-kernel, Sebastian Reichel, linux-pm, Alexey Charkov
The driver currently reports the 'charging' and 'overvoltage' states based
on a logical expression in the get_charger_property() wrapper function.
This doesn't scale well to other chip variants, which may have a different
number and type of hardware reported conditions which fall into these
broad power supply states.
Move the logic for determining 'charging' and 'overvoltage' states into
chip-specific accessors, which can be overridden by each variant as
needed.
This helps keep the get_charger_property() wrapper function chip-agnostic
while allowing for new chip variants to be added bringing their own logic.
Tested-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/power/supply/bq257xx_charger.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/power/supply/bq257xx_charger.c b/drivers/power/supply/bq257xx_charger.c
index 0765673728e4..9c082865e745 100644
--- a/drivers/power/supply/bq257xx_charger.c
+++ b/drivers/power/supply/bq257xx_charger.c
@@ -54,8 +54,10 @@ struct bq257xx_chip_info {
* @bq: parent MFD device
* @charger: power supply device
* @online: charger input is present
+ * @charging: charger is actively charging the battery
* @fast_charge: charger is in fast charge mode
* @pre_charge: charger is in pre-charge mode
+ * @overvoltage: overvoltage fault detected
* @ov_fault: charger reports over voltage fault
* @batoc_fault: charger reports battery over current fault
* @oc_fault: charger reports over current fault
@@ -71,8 +73,10 @@ struct bq257xx_chg {
struct bq257xx_device *bq;
struct power_supply *charger;
bool online;
+ bool charging;
bool fast_charge;
bool pre_charge;
+ bool overvoltage;
bool ov_fault;
bool batoc_fault;
bool oc_fault;
@@ -106,8 +110,10 @@ static int bq25703_get_state(struct bq257xx_chg *pdata)
pdata->online = reg & BQ25703_STS_AC_STAT;
pdata->fast_charge = reg & BQ25703_STS_IN_FCHRG;
pdata->pre_charge = reg & BQ25703_STS_IN_PCHRG;
+ pdata->charging = pdata->fast_charge || pdata->pre_charge;
pdata->ov_fault = reg & BQ25703_STS_FAULT_ACOV;
pdata->batoc_fault = reg & BQ25703_STS_FAULT_BATOC;
+ pdata->overvoltage = pdata->ov_fault || pdata->batoc_fault;
pdata->oc_fault = reg & BQ25703_STS_FAULT_ACOC;
return 0;
@@ -478,14 +484,14 @@ static int bq257xx_get_charger_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_STATUS:
if (!pdata->online)
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
- else if (pdata->fast_charge || pdata->pre_charge)
+ else if (pdata->charging)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
case POWER_SUPPLY_PROP_HEALTH:
- if (pdata->ov_fault || pdata->batoc_fault)
+ if (pdata->overvoltage)
val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
else if (pdata->oc_fault)
val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT;
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v7 6/7] regulator: bq257xx: Add support for BQ25792
2026-06-02 20:10 [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Alexey Charkov
` (4 preceding siblings ...)
2026-06-02 20:10 ` [PATCH v7 5/7] power: supply: bq257xx: Add fields for 'charging' and 'overvoltage' states Alexey Charkov
@ 2026-06-02 20:10 ` Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 7/7] power: supply: " Alexey Charkov
2026-06-03 20:52 ` [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Sebastian Reichel
7 siblings, 0 replies; 10+ messages in thread
From: Alexey Charkov @ 2026-06-02 20:10 UTC (permalink / raw)
To: Chris Morgan, Mark Brown, Sebastian Reichel, Liam Girdwood,
Lee Jones
Cc: linux-kernel, Sebastian Reichel, linux-pm, Alexey Charkov
Add support for TI BQ25792, an integrated battery charger and buck/boost
regulator. This enables VBUS output from the charger's boost converter
for use in USB OTG applications, supporting 2.8-22V output at up to 3.32A
with 10mV and 40mA resolution.
Acked-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/regulator/bq257xx-regulator.c | 98 ++++++++++++++++++++++++++++++++++-
1 file changed, 97 insertions(+), 1 deletion(-)
diff --git a/drivers/regulator/bq257xx-regulator.c b/drivers/regulator/bq257xx-regulator.c
index 913ca9186bf1..fec75b23cd40 100644
--- a/drivers/regulator/bq257xx-regulator.c
+++ b/drivers/regulator/bq257xx-regulator.c
@@ -31,6 +31,32 @@ static int bq25703_vbus_get_cur_limit(struct regulator_dev *rdev)
return FIELD_GET(BQ25703_OTG_CUR_MASK, reg) * BQ25703_OTG_CUR_STEP_UA;
}
+static int bq25792_vbus_get_cur_limit(struct regulator_dev *rdev)
+{
+ struct regmap *regmap = rdev_get_regmap(rdev);
+ int ret;
+ unsigned int reg;
+
+ ret = regmap_read(regmap, BQ25792_REG0D_IOTG_REGULATION, ®);
+ if (ret)
+ return ret;
+ return FIELD_GET(BQ25792_REG0D_IOTG_MASK, reg) * BQ25792_OTG_CUR_STEP_UA;
+}
+
+static int bq25792_vbus_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct regmap *regmap = rdev_get_regmap(rdev);
+ __be16 reg;
+ int ret;
+
+ ret = regmap_raw_read(regmap, BQ25792_REG0B_VOTG_REGULATION,
+ ®, sizeof(reg));
+ if (ret)
+ return ret;
+
+ return FIELD_GET(BQ25792_REG0B_VOTG_MASK, be16_to_cpu(reg));
+}
+
/*
* Check if the minimum current and maximum current requested are
* sane values, then set the register accordingly.
@@ -54,6 +80,37 @@ static int bq25703_vbus_set_cur_limit(struct regulator_dev *rdev,
FIELD_PREP(BQ25703_OTG_CUR_MASK, reg));
}
+static int bq25792_vbus_set_cur_limit(struct regulator_dev *rdev,
+ int min_uA, int max_uA)
+{
+ struct regmap *regmap = rdev_get_regmap(rdev);
+ unsigned int reg;
+
+ if ((min_uA > BQ25792_OTG_CUR_MAX_UA) ||
+ (max_uA < BQ25792_OTG_CUR_MIN_UA))
+ return -EINVAL;
+
+ reg = (max_uA / BQ25792_OTG_CUR_STEP_UA);
+
+ /* Catch rounding errors since our step is 40000uA. */
+ if ((reg * BQ25792_OTG_CUR_STEP_UA) < min_uA)
+ return -EINVAL;
+
+ return regmap_write(regmap, BQ25792_REG0D_IOTG_REGULATION,
+ FIELD_PREP(BQ25792_REG0D_IOTG_MASK, reg));
+}
+
+static int bq25792_vbus_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ struct regmap *regmap = rdev_get_regmap(rdev);
+ __be16 reg;
+
+ reg = cpu_to_be16(FIELD_PREP(BQ25792_REG0B_VOTG_MASK, sel));
+ return regmap_raw_write(regmap, BQ25792_REG0B_VOTG_REGULATION,
+ ®, sizeof(reg));
+}
+
static int bq25703_vbus_enable(struct regulator_dev *rdev)
{
struct bq257xx_reg_data *pdata = rdev_get_drvdata(rdev);
@@ -101,6 +158,34 @@ static const struct regulator_desc bq25703_vbus_desc = {
.vsel_mask = BQ25703_OTG_VOLT_MASK,
};
+static const struct regulator_ops bq25792_vbus_ops = {
+ /* No GPIO for enabling the OTG regulator */
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .get_voltage_sel = bq25792_vbus_get_voltage_sel,
+ .set_voltage_sel = bq25792_vbus_set_voltage_sel,
+ .get_current_limit = bq25792_vbus_get_cur_limit,
+ .set_current_limit = bq25792_vbus_set_cur_limit,
+};
+
+static const struct regulator_desc bq25792_vbus_desc = {
+ .name = "vbus",
+ .of_match = of_match_ptr("vbus"),
+ .regulators_node = of_match_ptr("regulators"),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .ops = &bq25792_vbus_ops,
+ .min_uV = BQ25792_OTG_VOLT_MIN_UV,
+ .uV_step = BQ25792_OTG_VOLT_STEP_UV,
+ .n_voltages = BQ25792_OTG_VOLT_NUM_VOLT,
+ .enable_mask = BQ25792_REG12_EN_OTG,
+ .enable_reg = BQ25792_REG12_CHARGER_CONTROL_3,
+ .enable_val = BQ25792_REG12_EN_OTG,
+ .disable_val = 0,
+};
+
/* Get optional GPIO for OTG regulator enable. */
static void bq257xx_reg_dt_parse_gpio(struct platform_device *pdev)
{
@@ -141,6 +226,7 @@ static void bq257xx_reg_dt_parse_gpio(struct platform_device *pdev)
static int bq257xx_regulator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct bq257xx_device *bq = dev_get_drvdata(pdev->dev.parent);
struct bq257xx_reg_data *pdata;
struct device_node *np = dev->of_node;
struct regulator_config cfg = {};
@@ -152,7 +238,17 @@ static int bq257xx_regulator_probe(struct platform_device *pdev)
if (!pdata)
return -ENOMEM;
- pdata->desc = bq25703_vbus_desc;
+ switch (bq->type) {
+ case BQ25703A:
+ pdata->desc = bq25703_vbus_desc;
+ break;
+ case BQ25792:
+ pdata->desc = bq25792_vbus_desc;
+ break;
+ default:
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Unsupported device type\n");
+ }
platform_set_drvdata(pdev, pdata);
bq257xx_reg_dt_parse_gpio(pdev);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v7 7/7] power: supply: bq257xx: Add support for BQ25792
2026-06-02 20:10 [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Alexey Charkov
` (5 preceding siblings ...)
2026-06-02 20:10 ` [PATCH v7 6/7] regulator: bq257xx: Add support for BQ25792 Alexey Charkov
@ 2026-06-02 20:10 ` Alexey Charkov
2026-06-03 20:49 ` Sebastian Reichel
2026-06-03 20:52 ` [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Sebastian Reichel
7 siblings, 1 reply; 10+ messages in thread
From: Alexey Charkov @ 2026-06-02 20:10 UTC (permalink / raw)
To: Chris Morgan, Mark Brown, Sebastian Reichel, Liam Girdwood,
Lee Jones
Cc: linux-kernel, Sebastian Reichel, linux-pm, Alexey Charkov
Add support for TI BQ25792 integrated battery charger and buck-boost
converter.
It shares high-level logic of operation with the already supported
BQ25703A, but has a different register map, bit definitions and some of
the lower-level hardware states.
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/power/supply/bq257xx_charger.c | 528 ++++++++++++++++++++++++++++++++-
include/linux/mfd/bq257xx.h | 14 +
2 files changed, 541 insertions(+), 1 deletion(-)
diff --git a/drivers/power/supply/bq257xx_charger.c b/drivers/power/supply/bq257xx_charger.c
index 9c082865e745..7d02169248b1 100644
--- a/drivers/power/supply/bq257xx_charger.c
+++ b/drivers/power/supply/bq257xx_charger.c
@@ -5,6 +5,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/byteorder/generic.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mfd/bq257xx.h>
@@ -88,6 +89,53 @@ struct bq257xx_chg {
u32 vsys_min;
};
+/**
+ * bq25792_read16() - Read a 16-bit value from device register
+ * @pdata: driver platform data
+ * @reg: register address to read from
+ * @val: pointer to store the register value
+ *
+ * Read a 16-bit big-endian value from the BQ25792 device via regmap
+ * and convert to CPU byte order.
+ *
+ * Return: Returns 0 on success or error on failure to read.
+ */
+static int bq25792_read16(struct bq257xx_chg *pdata, unsigned int reg, u16 *val)
+{
+ __be16 regval;
+ int ret;
+
+ ret = regmap_raw_read(pdata->bq->regmap, reg, ®val, sizeof(regval));
+ if (ret)
+ return ret;
+
+ *val = be16_to_cpu(regval);
+ return 0;
+}
+
+/**
+ * bq25792_write16() - Write a 16-bit value to device register
+ * @pdata: driver platform data
+ * @reg: register address to write to
+ * @val: 16-bit value to write in CPU byte order
+ *
+ * Convert the value to big-endian and write a 16-bit value to the
+ * BQ25792 device via regmap.
+ *
+ * Return: Returns 0 on success or error on failure to write.
+ */
+static int bq25792_write16(struct bq257xx_chg *pdata, unsigned int reg, u16 val)
+{
+ __be16 regval = cpu_to_be16(val);
+ int ret;
+
+ ret = regmap_raw_write(pdata->bq->regmap, reg, ®val, sizeof(regval));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
/**
* bq25703_get_state() - Get the current state of the device
* @pdata: driver platform data
@@ -119,6 +167,43 @@ static int bq25703_get_state(struct bq257xx_chg *pdata)
return 0;
}
+/**
+ * bq25792_get_state() - Get the current state of the device
+ * @pdata: driver platform data
+ *
+ * Get the current state of the BQ25792 charger by reading status
+ * registers. Updates the online, charging, overvoltage, and fault
+ * status fields in the driver data structure.
+ *
+ * Return: Returns 0 on success or error on failure to read device.
+ */
+static int bq25792_get_state(struct bq257xx_chg *pdata)
+{
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(pdata->bq->regmap, BQ25792_REG1B_CHARGER_STATUS_0, ®);
+ if (ret)
+ return ret;
+
+ pdata->online = reg & BQ25792_REG1B_PG_STAT;
+
+ ret = regmap_read(pdata->bq->regmap, BQ25792_REG1C_CHARGER_STATUS_1, ®);
+ if (ret)
+ return ret;
+
+ pdata->charging = reg & BQ25792_REG1C_CHG_STAT_MASK;
+
+ ret = regmap_read(pdata->bq->regmap, BQ25792_REG20_FAULT_STATUS_0, ®);
+ if (ret)
+ return ret;
+
+ pdata->overvoltage = reg & BQ25792_REG20_OVERVOLTAGE_MASK;
+ pdata->oc_fault = reg & BQ25792_REG20_OVERCURRENT_MASK;
+
+ return 0;
+}
+
/**
* bq25703_get_min_vsys() - Get the minimum system voltage
* @pdata: driver platform data
@@ -142,6 +227,31 @@ static int bq25703_get_min_vsys(struct bq257xx_chg *pdata, int *intval)
return ret;
}
+/**
+ * bq25792_get_min_vsys() - Get the minimum system voltage
+ * @pdata: driver platform data
+ * @intval: pointer to store the minimum voltage value
+ *
+ * Read the current minimum system voltage setting from the device
+ * and return it in microvolts.
+ *
+ * Return: Returns 0 on success or error on failure to read.
+ */
+static int bq25792_get_min_vsys(struct bq257xx_chg *pdata, int *intval)
+{
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(pdata->bq->regmap, BQ25792_REG00_MIN_SYS_VOLTAGE, ®);
+ if (ret)
+ return ret;
+
+ reg = FIELD_GET(BQ25792_REG00_VSYSMIN_MASK, reg);
+ *intval = (reg * BQ25792_MINVSYS_STEP_UV) + BQ25792_MINVSYS_MIN_UV;
+
+ return ret;
+}
+
/**
* bq25703_set_min_vsys() - Set the minimum system voltage
* @pdata: driver platform data
@@ -166,6 +276,29 @@ static int bq25703_set_min_vsys(struct bq257xx_chg *pdata, int vsys)
reg);
}
+/**
+ * bq25792_set_min_vsys() - Set the minimum system voltage
+ * @pdata: driver platform data
+ * @vsys: voltage value to set in uV
+ *
+ * Set the minimum system voltage by clamping the requested value
+ * between device limits and writing to the appropriate register.
+ *
+ * Return: Returns 0 on success or error on failure to write.
+ */
+static int bq25792_set_min_vsys(struct bq257xx_chg *pdata, int vsys)
+{
+ unsigned int reg;
+ int vsys_min = pdata->vsys_min;
+
+ vsys = clamp(vsys, vsys_min, BQ25792_MINVSYS_MAX_UV);
+ reg = ((vsys - BQ25792_MINVSYS_MIN_UV) / BQ25792_MINVSYS_STEP_UV);
+ reg = FIELD_PREP(BQ25792_REG00_VSYSMIN_MASK, reg);
+
+ return regmap_write(pdata->bq->regmap,
+ BQ25792_REG00_MIN_SYS_VOLTAGE, reg);
+}
+
/**
* bq25703_get_cur() - Get the reported current from the battery
* @pdata: driver platform data
@@ -195,6 +328,30 @@ static int bq25703_get_cur(struct bq257xx_chg *pdata, int *intval)
return ret;
}
+/**
+ * bq25792_get_cur() - Get the reported current from the battery
+ * @pdata: driver platform data
+ * @intval: pointer to store the battery current value
+ *
+ * Read the current ADC value from the device representing the battery
+ * charge or discharge current and return it in microamps.
+ *
+ * Return: Returns 0 on success or error on failure to read.
+ */
+static int bq25792_get_cur(struct bq257xx_chg *pdata, int *intval)
+{
+ u16 reg;
+ int ret;
+
+ ret = bq25792_read16(pdata, BQ25792_REG33_IBAT_ADC, ®);
+ if (ret < 0)
+ return ret;
+
+ *intval = (s16)reg * BQ25792_ADCIBAT_STEP_UA;
+
+ return ret;
+}
+
/**
* bq25703_get_ichg_cur() - Get the maximum reported charge current
* @pdata: driver platform data
@@ -218,6 +375,30 @@ static int bq25703_get_ichg_cur(struct bq257xx_chg *pdata, int *intval)
return ret;
}
+/**
+ * bq25792_get_ichg_cur() - Get the maximum reported charge current
+ * @pdata: driver platform data
+ * @intval: pointer to store the maximum charge current value
+ *
+ * Read the programmed maximum charge current limit from the device.
+ *
+ * Return: Returns 0 on success or error on failure to read value.
+ */
+static int bq25792_get_ichg_cur(struct bq257xx_chg *pdata, int *intval)
+{
+ u16 reg;
+ int ret;
+
+ ret = bq25792_read16(pdata, BQ25792_REG03_CHARGE_CURRENT_LIMIT, ®);
+ if (ret)
+ return ret;
+
+ *intval = FIELD_GET(BQ25792_REG03_ICHG_MASK, reg) *
+ BQ25792_ICHG_STEP_UA;
+
+ return ret;
+}
+
/**
* bq25703_set_ichg_cur() - Set the maximum charge current
* @pdata: driver platform data
@@ -242,6 +423,28 @@ static int bq25703_set_ichg_cur(struct bq257xx_chg *pdata, int ichg)
reg);
}
+/**
+ * bq25792_set_ichg_cur() - Set the maximum charge current
+ * @pdata: driver platform data
+ * @ichg: current value to set in uA
+ *
+ * Set the maximum charge current by clamping the requested value
+ * between device limits and writing to the appropriate register.
+ *
+ * Return: Returns 0 on success or error on failure to write.
+ */
+static int bq25792_set_ichg_cur(struct bq257xx_chg *pdata, int ichg)
+{
+ int ichg_max = pdata->ichg_max;
+ u16 reg;
+
+ ichg = clamp(ichg, BQ25792_ICHG_MIN_UA, ichg_max);
+ reg = FIELD_PREP(BQ25792_REG03_ICHG_MASK,
+ (ichg / BQ25792_ICHG_STEP_UA));
+
+ return bq25792_write16(pdata, BQ25792_REG03_CHARGE_CURRENT_LIMIT, reg);
+}
+
/**
* bq25703_get_chrg_volt() - Get the maximum set charge voltage
* @pdata: driver platform data
@@ -265,6 +468,30 @@ static int bq25703_get_chrg_volt(struct bq257xx_chg *pdata, int *intval)
return ret;
}
+/**
+ * bq25792_get_chrg_volt() - Get the maximum set charge voltage
+ * @pdata: driver platform data
+ * @intval: pointer to store the maximum charge voltage value
+ *
+ * Read the current charge voltage limit from the device.
+ *
+ * Return: Returns 0 on success or error on failure to read value.
+ */
+static int bq25792_get_chrg_volt(struct bq257xx_chg *pdata, int *intval)
+{
+ u16 reg;
+ int ret;
+
+ ret = bq25792_read16(pdata, BQ25792_REG01_CHARGE_VOLTAGE_LIMIT, ®);
+ if (ret)
+ return ret;
+
+ *intval = FIELD_GET(BQ25792_REG01_VREG_MASK, reg) *
+ BQ25792_VBATREG_STEP_UV;
+
+ return ret;
+}
+
/**
* bq25703_set_chrg_volt() - Set the maximum charge voltage
* @pdata: driver platform data
@@ -291,6 +518,29 @@ static int bq25703_set_chrg_volt(struct bq257xx_chg *pdata, int vbat)
reg);
}
+/**
+ * bq25792_set_chrg_volt() - Set the maximum charge voltage
+ * @pdata: driver platform data
+ * @vbat: voltage value to set in uV
+ *
+ * Set the maximum charge voltage by clamping the requested value
+ * between device limits and writing to the appropriate register.
+ *
+ * Return: Returns 0 on success or error on failure to write.
+ */
+static int bq25792_set_chrg_volt(struct bq257xx_chg *pdata, int vbat)
+{
+ int vbat_max = pdata->vbat_max;
+ u16 reg;
+
+ vbat = clamp(vbat, BQ25792_VBATREG_MIN_UV, vbat_max);
+
+ reg = FIELD_PREP(BQ25792_REG01_VREG_MASK,
+ (vbat / BQ25792_VBATREG_STEP_UV));
+
+ return bq25792_write16(pdata, BQ25792_REG01_CHARGE_VOLTAGE_LIMIT, reg);
+}
+
/**
* bq25703_get_iindpm() - Get the maximum set input current
* @pdata: driver platform data
@@ -319,6 +569,30 @@ static int bq25703_get_iindpm(struct bq257xx_chg *pdata, int *intval)
return ret;
}
+/**
+ * bq25792_get_iindpm() - Get the maximum set input current
+ * @pdata: driver platform data
+ * @intval: pointer to store the maximum input current value
+ *
+ * Read the current input current limit from the device.
+ *
+ * Return: Returns 0 on success or error on failure to read value.
+ */
+static int bq25792_get_iindpm(struct bq257xx_chg *pdata, int *intval)
+{
+ u16 reg;
+ int ret;
+
+ ret = bq25792_read16(pdata, BQ25792_REG06_INPUT_CURRENT_LIMIT, ®);
+ if (ret)
+ return ret;
+
+ reg = FIELD_GET(BQ25792_REG06_IINDPM_MASK, reg);
+ *intval = reg * BQ25792_IINDPM_STEP_UA;
+
+ return ret;
+}
+
/**
* bq25703_set_iindpm() - Set the maximum input current
* @pdata: driver platform data
@@ -344,6 +618,29 @@ static int bq25703_set_iindpm(struct bq257xx_chg *pdata, int iindpm)
FIELD_PREP(BQ25703_IINDPM_MASK, reg));
}
+/**
+ * bq25792_set_iindpm() - Set the maximum input current
+ * @pdata: driver platform data
+ * @iindpm: current value in uA
+ *
+ * Set the maximum input current by clamping the requested value
+ * between device limits and writing to the appropriate register.
+ *
+ * Return: Returns 0 on success or error on failure to write.
+ */
+static int bq25792_set_iindpm(struct bq257xx_chg *pdata, int iindpm)
+{
+ u16 reg;
+ int iindpm_max = pdata->iindpm_max;
+
+ iindpm = clamp(iindpm, BQ25792_IINDPM_MIN_UA, iindpm_max);
+
+ reg = iindpm / BQ25792_IINDPM_STEP_UA;
+
+ return bq25792_write16(pdata, BQ25792_REG06_INPUT_CURRENT_LIMIT,
+ FIELD_PREP(BQ25792_REG06_IINDPM_MASK, reg));
+}
+
/**
* bq25703_get_vbat() - Get the reported voltage from the battery
* @pdata: driver platform data
@@ -368,6 +665,30 @@ static int bq25703_get_vbat(struct bq257xx_chg *pdata, int *intval)
return ret;
}
+/**
+ * bq25792_get_vbat() - Get the reported voltage from the battery
+ * @pdata: driver platform data
+ * @intval: pointer to store the battery voltage value
+ *
+ * Read the current ADC value representing the battery voltage
+ * and return it in microvolts.
+ *
+ * Return: Returns 0 on success or error on failure to read value.
+ */
+static int bq25792_get_vbat(struct bq257xx_chg *pdata, int *intval)
+{
+ u16 reg;
+ int ret;
+
+ ret = bq25792_read16(pdata, BQ25792_REG3B_VBAT_ADC, ®);
+ if (ret)
+ return ret;
+
+ *intval = reg * BQ25792_ADCVSYSVBAT_STEP_UV;
+
+ return ret;
+}
+
/**
* bq25703_hw_init() - Set all the required registers to init the charger
* @pdata: driver platform data
@@ -434,6 +755,108 @@ static int bq25703_hw_init(struct bq257xx_chg *pdata)
return ret;
}
+/**
+ * bq25792_hw_init() - Initialize BQ25792 hardware
+ * @pdata: driver platform data
+ *
+ * Initialize the BQ25792 by disabling the watchdog, enabling discharge
+ * current sensing with 5A limit, and configuring input current regulation.
+ * Set the charge current, charge voltage, minimum system voltage, and
+ * input current limit from platform data. Enable and configure the ADC
+ * to measure all available channels.
+ *
+ * Return: Returns 0 on success or error code on error.
+ */
+static int bq25792_hw_init(struct bq257xx_chg *pdata)
+{
+ struct regmap *regmap = pdata->bq->regmap;
+ int ret = 0;
+ u8 reg;
+
+ /* Disable watchdog (TODO: make it work instead) */
+ ret = regmap_write(regmap, BQ25792_REG10_CHARGER_CONTROL_1, 0);
+ if (ret)
+ return ret;
+
+ /*
+ * Enable battery discharge current sensing, 5A discharge current
+ * limit, input current regulation and ship FET functions
+ */
+ ret = regmap_write(regmap, BQ25792_REG14_CHARGER_CONTROL_5,
+ BQ25792_REG14_SFET_PRESENT |
+ BQ25792_REG14_EN_IBAT |
+ BQ25792_IBAT_5A |
+ BQ25792_REG14_EN_IINDPM);
+ if (ret)
+ return ret;
+
+ if (pdata->vbat_max < 5000000) {
+ /* 1S batteries */
+ reg = FIELD_PREP(BQ25792_REG0A_CELL_MASK, BQ25792_CELL_1S);
+ } else if (pdata->vbat_max < 10000000) {
+ /* 2S batteries */
+ reg = FIELD_PREP(BQ25792_REG0A_CELL_MASK, BQ25792_CELL_2S);
+ } else if (pdata->vbat_max < 14000000) {
+ /* 3S batteries */
+ reg = FIELD_PREP(BQ25792_REG0A_CELL_MASK, BQ25792_CELL_3S);
+ } else {
+ /* 4S batteries */
+ reg = FIELD_PREP(BQ25792_REG0A_CELL_MASK, BQ25792_CELL_4S);
+ }
+
+ /* Recharge voltage detection deglitch time (default 1024ms) */
+ reg |= FIELD_PREP(BQ25792_REG0A_TRECHG_MASK, BQ25792_TRECHG_1024MS);
+
+ /* Recharge voltage offset: 5% of the set charge voltage */
+ reg |= FIELD_PREP(BQ25792_REG0A_VRECHG_MASK,
+ (pdata->vbat_max / 20 - BQ25792_VRECHG_MIN_UV) / BQ25792_VRECHG_STEP_UV);
+
+ ret = regmap_write(regmap, BQ25792_REG0A_RECHARGE_CONTROL, reg);
+ if (ret)
+ return ret;
+
+ ret = pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max);
+ if (ret)
+ return ret;
+
+ ret = pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max);
+ if (ret)
+ return ret;
+
+ ret = bq25792_set_min_vsys(pdata, pdata->vsys_min);
+ if (ret)
+ return ret;
+
+ ret = pdata->chip->bq257xx_set_iindpm(pdata, pdata->iindpm_max);
+ if (ret)
+ return ret;
+
+ /* Enable the Input Current Optimizer (the rest is at POR value) */
+ ret = regmap_write(regmap, BQ25792_REG0F_CHARGER_CONTROL_0,
+ BQ25792_REG0F_EN_AUTO_IBATDIS |
+ BQ25792_REG0F_EN_CHG |
+ BQ25792_REG0F_EN_ICO |
+ BQ25792_REG0F_EN_TERM);
+ if (ret)
+ return ret;
+
+ /* Enable the ADC. */
+ ret = regmap_write(regmap, BQ25792_REG2E_ADC_CONTROL, BQ25792_REG2E_ADC_EN);
+ if (ret)
+ return ret;
+
+ /* Clear per-channel ADC disable bits - enable all channels */
+ ret = regmap_write(regmap, BQ25792_REG2F_ADC_FUNCTION_DISABLE_0, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(regmap, BQ25792_REG30_ADC_FUNCTION_DISABLE_1, 0);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
/**
* bq25703_hw_shutdown() - Set registers for shutdown
* @pdata: driver platform data
@@ -446,6 +869,30 @@ static void bq25703_hw_shutdown(struct bq257xx_chg *pdata)
BQ25703_EN_LWPWR, BQ25703_EN_LWPWR);
}
+/**
+ * bq25792_hw_shutdown() - Shutdown BQ25792 hardware
+ * @pdata: driver platform data
+ *
+ * Perform hardware shutdown for the BQ25792. Currently a no-op
+ * as the device does not require special shutdown configuration.
+ */
+static void bq25792_hw_shutdown(struct bq257xx_chg *pdata)
+{
+ /* Nothing to do here */
+}
+
+/**
+ * bq257xx_set_charger_property() - Set a power supply property
+ * @psy: power supply device
+ * @prop: power supply property to set
+ * @val: value to set for the property
+ *
+ * Handle requests to set power supply properties such as input current
+ * limit, constant charge voltage, and constant charge current. Routes
+ * the request to the chip-specific implementation.
+ *
+ * Return: Returns 0 on success or -EINVAL if property is not supported.
+ */
static int bq257xx_set_charger_property(struct power_supply *psy,
enum power_supply_property prop,
const union power_supply_propval *val)
@@ -469,6 +916,19 @@ static int bq257xx_set_charger_property(struct power_supply *psy,
return -EINVAL;
}
+/**
+ * bq257xx_get_charger_property() - Get a power supply property
+ * @psy: power supply device
+ * @psp: power supply property to get
+ * @val: pointer to store the property value
+ *
+ * Handle requests to get power supply properties, including status,
+ * health, manufacturer, online state, and various voltage/current
+ * measurements. Reads current device state and routes chip-specific
+ * property requests to appropriate handlers.
+ *
+ * Return: Returns 0 on success or -EINVAL if property is not supported.
+ */
static int bq257xx_get_charger_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -550,6 +1010,17 @@ static enum power_supply_property bq257xx_power_supply_props[] = {
POWER_SUPPLY_PROP_USB_TYPE,
};
+/**
+ * bq257xx_property_is_writeable() - Check if a property is writeable
+ * @psy: power supply device
+ * @prop: power supply property to check
+ *
+ * Determines which power supply properties can be written to. Only
+ * charge current limit, charge voltage limit, and input current
+ * limit are writeable.
+ *
+ * Return: Returns 1 if property is writeable, 0 otherwise.
+ */
static int bq257xx_property_is_writeable(struct power_supply *psy,
enum power_supply_property prop)
{
@@ -622,6 +1093,17 @@ static void bq257xx_external_power_changed(struct power_supply *psy)
power_supply_changed(psy);
}
+/**
+ * bq257xx_irq_handler_thread() - Handle charger interrupt
+ * @irq: interrupt number
+ * @private: pointer to driver private data
+ *
+ * Thread handler for charger interrupts. Triggers re-evaluation of
+ * external power status and updates power supply state in response
+ * to charger events.
+ *
+ * Return: Returns IRQ_HANDLED if interrupt was processed.
+ */
static irqreturn_t bq257xx_irq_handler_thread(int irq, void *private)
{
struct bq257xx_chg *pdata = private;
@@ -662,6 +1144,22 @@ static const struct bq257xx_chip_info bq25703_chip_info = {
.bq257xx_get_min_vsys = &bq25703_get_min_vsys,
};
+static const struct bq257xx_chip_info bq25792_chip_info = {
+ .default_iindpm_uA = BQ25792_IINDPM_DEFAULT_UA,
+ .bq257xx_hw_init = &bq25792_hw_init,
+ .bq257xx_hw_shutdown = &bq25792_hw_shutdown,
+ .bq257xx_get_state = &bq25792_get_state,
+ .bq257xx_get_ichg = &bq25792_get_ichg_cur,
+ .bq257xx_set_ichg = &bq25792_set_ichg_cur,
+ .bq257xx_get_vbatreg = &bq25792_get_chrg_volt,
+ .bq257xx_set_vbatreg = &bq25792_set_chrg_volt,
+ .bq257xx_get_iindpm = &bq25792_get_iindpm,
+ .bq257xx_set_iindpm = &bq25792_set_iindpm,
+ .bq257xx_get_cur = &bq25792_get_cur,
+ .bq257xx_get_vbat = &bq25792_get_vbat,
+ .bq257xx_get_min_vsys = &bq25792_get_min_vsys,
+};
+
/**
* bq257xx_parse_dt() - Parse the device tree for required properties
* @pdata: driver platform data
@@ -707,6 +1205,17 @@ static int bq257xx_parse_dt(struct bq257xx_chg *pdata,
return 0;
}
+/**
+ * bq257xx_charger_probe() - Probe routine for charger platform device
+ * @pdev: platform device
+ *
+ * Probe the charger device, allocate driver data structure, select the
+ * appropriate chip-specific function pointers, register the power supply,
+ * parse device tree properties for battery limits, initialize hardware,
+ * and set up the interrupt handler if available.
+ *
+ * Return: Returns 0 on success or error code on failure.
+ */
static int bq257xx_charger_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -722,7 +1231,17 @@ static int bq257xx_charger_probe(struct platform_device *pdev)
return -ENOMEM;
pdata->bq = bq;
- pdata->chip = &bq25703_chip_info;
+
+ switch (bq->type) {
+ case BQ25703A:
+ pdata->chip = &bq25703_chip_info;
+ break;
+ case BQ25792:
+ pdata->chip = &bq25792_chip_info;
+ break;
+ default:
+ return dev_err_probe(dev, -EINVAL, "Unknown chip type\n");
+ }
platform_set_drvdata(pdev, pdata);
@@ -760,6 +1279,13 @@ static int bq257xx_charger_probe(struct platform_device *pdev)
return ret;
}
+/**
+ * bq257xx_charger_shutdown() - Shutdown routine for charger platform device
+ * @pdev: platform device
+ *
+ * Called during system shutdown to perform charger cleanup, including
+ * disabling watchdog timers or other chip-specific shutdown procedures.
+ */
static void bq257xx_charger_shutdown(struct platform_device *pdev)
{
struct bq257xx_chg *pdata = platform_get_drvdata(pdev);
diff --git a/include/linux/mfd/bq257xx.h b/include/linux/mfd/bq257xx.h
index 4ec72eb920f2..379ef4ee8291 100644
--- a/include/linux/mfd/bq257xx.h
+++ b/include/linux/mfd/bq257xx.h
@@ -200,6 +200,20 @@
#define BQ25792_REG0A_TRECHG_MASK GENMASK(5, 4)
#define BQ25792_REG0A_VRECHG_MASK GENMASK(3, 0)
+#define BQ25792_CELL_1S 0
+#define BQ25792_CELL_2S 1
+#define BQ25792_CELL_3S 2
+#define BQ25792_CELL_4S 3
+
+#define BQ25792_TRECHG_64MS 0
+#define BQ25792_TRECHG_256MS 1
+#define BQ25792_TRECHG_1024MS 2
+#define BQ25792_TRECHG_2048MS 3
+
+#define BQ25792_VRECHG_MIN_UV 50000
+#define BQ25792_VRECHG_STEP_UV 50000
+#define BQ25792_VRECHG_MAX_UV 800000
+
/* VOTG regulation */
#define BQ25792_REG0B_VOTG_MASK GENMASK(10, 0)
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v7 7/7] power: supply: bq257xx: Add support for BQ25792
2026-06-02 20:10 ` [PATCH v7 7/7] power: supply: " Alexey Charkov
@ 2026-06-03 20:49 ` Sebastian Reichel
0 siblings, 0 replies; 10+ messages in thread
From: Sebastian Reichel @ 2026-06-03 20:49 UTC (permalink / raw)
To: Alexey Charkov
Cc: Chris Morgan, Mark Brown, Liam Girdwood, Lee Jones, linux-kernel,
linux-pm
[-- Attachment #1: Type: text/plain, Size: 24280 bytes --]
Hi,
On Wed, Jun 03, 2026 at 12:10:55AM +0400, Alexey Charkov wrote:
> Add support for TI BQ25792 integrated battery charger and buck-boost
> converter.
>
> It shares high-level logic of operation with the already supported
> BQ25703A, but has a different register map, bit definitions and some of
> the lower-level hardware states.
>
> Signed-off-by: Alexey Charkov <alchark@flipper.net>
> ---
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
This has to wait a cycle as it does not apply due to the MFD header
change.
Greetings,
-- Sebastian
> drivers/power/supply/bq257xx_charger.c | 528 ++++++++++++++++++++++++++++++++-
> include/linux/mfd/bq257xx.h | 14 +
> 2 files changed, 541 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/power/supply/bq257xx_charger.c b/drivers/power/supply/bq257xx_charger.c
> index 9c082865e745..7d02169248b1 100644
> --- a/drivers/power/supply/bq257xx_charger.c
> +++ b/drivers/power/supply/bq257xx_charger.c
> @@ -5,6 +5,7 @@
> */
>
> #include <linux/bitfield.h>
> +#include <linux/byteorder/generic.h>
> #include <linux/i2c.h>
> #include <linux/interrupt.h>
> #include <linux/mfd/bq257xx.h>
> @@ -88,6 +89,53 @@ struct bq257xx_chg {
> u32 vsys_min;
> };
>
> +/**
> + * bq25792_read16() - Read a 16-bit value from device register
> + * @pdata: driver platform data
> + * @reg: register address to read from
> + * @val: pointer to store the register value
> + *
> + * Read a 16-bit big-endian value from the BQ25792 device via regmap
> + * and convert to CPU byte order.
> + *
> + * Return: Returns 0 on success or error on failure to read.
> + */
> +static int bq25792_read16(struct bq257xx_chg *pdata, unsigned int reg, u16 *val)
> +{
> + __be16 regval;
> + int ret;
> +
> + ret = regmap_raw_read(pdata->bq->regmap, reg, ®val, sizeof(regval));
> + if (ret)
> + return ret;
> +
> + *val = be16_to_cpu(regval);
> + return 0;
> +}
> +
> +/**
> + * bq25792_write16() - Write a 16-bit value to device register
> + * @pdata: driver platform data
> + * @reg: register address to write to
> + * @val: 16-bit value to write in CPU byte order
> + *
> + * Convert the value to big-endian and write a 16-bit value to the
> + * BQ25792 device via regmap.
> + *
> + * Return: Returns 0 on success or error on failure to write.
> + */
> +static int bq25792_write16(struct bq257xx_chg *pdata, unsigned int reg, u16 val)
> +{
> + __be16 regval = cpu_to_be16(val);
> + int ret;
> +
> + ret = regmap_raw_write(pdata->bq->regmap, reg, ®val, sizeof(regval));
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> /**
> * bq25703_get_state() - Get the current state of the device
> * @pdata: driver platform data
> @@ -119,6 +167,43 @@ static int bq25703_get_state(struct bq257xx_chg *pdata)
> return 0;
> }
>
> +/**
> + * bq25792_get_state() - Get the current state of the device
> + * @pdata: driver platform data
> + *
> + * Get the current state of the BQ25792 charger by reading status
> + * registers. Updates the online, charging, overvoltage, and fault
> + * status fields in the driver data structure.
> + *
> + * Return: Returns 0 on success or error on failure to read device.
> + */
> +static int bq25792_get_state(struct bq257xx_chg *pdata)
> +{
> + unsigned int reg;
> + int ret;
> +
> + ret = regmap_read(pdata->bq->regmap, BQ25792_REG1B_CHARGER_STATUS_0, ®);
> + if (ret)
> + return ret;
> +
> + pdata->online = reg & BQ25792_REG1B_PG_STAT;
> +
> + ret = regmap_read(pdata->bq->regmap, BQ25792_REG1C_CHARGER_STATUS_1, ®);
> + if (ret)
> + return ret;
> +
> + pdata->charging = reg & BQ25792_REG1C_CHG_STAT_MASK;
> +
> + ret = regmap_read(pdata->bq->regmap, BQ25792_REG20_FAULT_STATUS_0, ®);
> + if (ret)
> + return ret;
> +
> + pdata->overvoltage = reg & BQ25792_REG20_OVERVOLTAGE_MASK;
> + pdata->oc_fault = reg & BQ25792_REG20_OVERCURRENT_MASK;
> +
> + return 0;
> +}
> +
> /**
> * bq25703_get_min_vsys() - Get the minimum system voltage
> * @pdata: driver platform data
> @@ -142,6 +227,31 @@ static int bq25703_get_min_vsys(struct bq257xx_chg *pdata, int *intval)
> return ret;
> }
>
> +/**
> + * bq25792_get_min_vsys() - Get the minimum system voltage
> + * @pdata: driver platform data
> + * @intval: pointer to store the minimum voltage value
> + *
> + * Read the current minimum system voltage setting from the device
> + * and return it in microvolts.
> + *
> + * Return: Returns 0 on success or error on failure to read.
> + */
> +static int bq25792_get_min_vsys(struct bq257xx_chg *pdata, int *intval)
> +{
> + unsigned int reg;
> + int ret;
> +
> + ret = regmap_read(pdata->bq->regmap, BQ25792_REG00_MIN_SYS_VOLTAGE, ®);
> + if (ret)
> + return ret;
> +
> + reg = FIELD_GET(BQ25792_REG00_VSYSMIN_MASK, reg);
> + *intval = (reg * BQ25792_MINVSYS_STEP_UV) + BQ25792_MINVSYS_MIN_UV;
> +
> + return ret;
> +}
> +
> /**
> * bq25703_set_min_vsys() - Set the minimum system voltage
> * @pdata: driver platform data
> @@ -166,6 +276,29 @@ static int bq25703_set_min_vsys(struct bq257xx_chg *pdata, int vsys)
> reg);
> }
>
> +/**
> + * bq25792_set_min_vsys() - Set the minimum system voltage
> + * @pdata: driver platform data
> + * @vsys: voltage value to set in uV
> + *
> + * Set the minimum system voltage by clamping the requested value
> + * between device limits and writing to the appropriate register.
> + *
> + * Return: Returns 0 on success or error on failure to write.
> + */
> +static int bq25792_set_min_vsys(struct bq257xx_chg *pdata, int vsys)
> +{
> + unsigned int reg;
> + int vsys_min = pdata->vsys_min;
> +
> + vsys = clamp(vsys, vsys_min, BQ25792_MINVSYS_MAX_UV);
> + reg = ((vsys - BQ25792_MINVSYS_MIN_UV) / BQ25792_MINVSYS_STEP_UV);
> + reg = FIELD_PREP(BQ25792_REG00_VSYSMIN_MASK, reg);
> +
> + return regmap_write(pdata->bq->regmap,
> + BQ25792_REG00_MIN_SYS_VOLTAGE, reg);
> +}
> +
> /**
> * bq25703_get_cur() - Get the reported current from the battery
> * @pdata: driver platform data
> @@ -195,6 +328,30 @@ static int bq25703_get_cur(struct bq257xx_chg *pdata, int *intval)
> return ret;
> }
>
> +/**
> + * bq25792_get_cur() - Get the reported current from the battery
> + * @pdata: driver platform data
> + * @intval: pointer to store the battery current value
> + *
> + * Read the current ADC value from the device representing the battery
> + * charge or discharge current and return it in microamps.
> + *
> + * Return: Returns 0 on success or error on failure to read.
> + */
> +static int bq25792_get_cur(struct bq257xx_chg *pdata, int *intval)
> +{
> + u16 reg;
> + int ret;
> +
> + ret = bq25792_read16(pdata, BQ25792_REG33_IBAT_ADC, ®);
> + if (ret < 0)
> + return ret;
> +
> + *intval = (s16)reg * BQ25792_ADCIBAT_STEP_UA;
> +
> + return ret;
> +}
> +
> /**
> * bq25703_get_ichg_cur() - Get the maximum reported charge current
> * @pdata: driver platform data
> @@ -218,6 +375,30 @@ static int bq25703_get_ichg_cur(struct bq257xx_chg *pdata, int *intval)
> return ret;
> }
>
> +/**
> + * bq25792_get_ichg_cur() - Get the maximum reported charge current
> + * @pdata: driver platform data
> + * @intval: pointer to store the maximum charge current value
> + *
> + * Read the programmed maximum charge current limit from the device.
> + *
> + * Return: Returns 0 on success or error on failure to read value.
> + */
> +static int bq25792_get_ichg_cur(struct bq257xx_chg *pdata, int *intval)
> +{
> + u16 reg;
> + int ret;
> +
> + ret = bq25792_read16(pdata, BQ25792_REG03_CHARGE_CURRENT_LIMIT, ®);
> + if (ret)
> + return ret;
> +
> + *intval = FIELD_GET(BQ25792_REG03_ICHG_MASK, reg) *
> + BQ25792_ICHG_STEP_UA;
> +
> + return ret;
> +}
> +
> /**
> * bq25703_set_ichg_cur() - Set the maximum charge current
> * @pdata: driver platform data
> @@ -242,6 +423,28 @@ static int bq25703_set_ichg_cur(struct bq257xx_chg *pdata, int ichg)
> reg);
> }
>
> +/**
> + * bq25792_set_ichg_cur() - Set the maximum charge current
> + * @pdata: driver platform data
> + * @ichg: current value to set in uA
> + *
> + * Set the maximum charge current by clamping the requested value
> + * between device limits and writing to the appropriate register.
> + *
> + * Return: Returns 0 on success or error on failure to write.
> + */
> +static int bq25792_set_ichg_cur(struct bq257xx_chg *pdata, int ichg)
> +{
> + int ichg_max = pdata->ichg_max;
> + u16 reg;
> +
> + ichg = clamp(ichg, BQ25792_ICHG_MIN_UA, ichg_max);
> + reg = FIELD_PREP(BQ25792_REG03_ICHG_MASK,
> + (ichg / BQ25792_ICHG_STEP_UA));
> +
> + return bq25792_write16(pdata, BQ25792_REG03_CHARGE_CURRENT_LIMIT, reg);
> +}
> +
> /**
> * bq25703_get_chrg_volt() - Get the maximum set charge voltage
> * @pdata: driver platform data
> @@ -265,6 +468,30 @@ static int bq25703_get_chrg_volt(struct bq257xx_chg *pdata, int *intval)
> return ret;
> }
>
> +/**
> + * bq25792_get_chrg_volt() - Get the maximum set charge voltage
> + * @pdata: driver platform data
> + * @intval: pointer to store the maximum charge voltage value
> + *
> + * Read the current charge voltage limit from the device.
> + *
> + * Return: Returns 0 on success or error on failure to read value.
> + */
> +static int bq25792_get_chrg_volt(struct bq257xx_chg *pdata, int *intval)
> +{
> + u16 reg;
> + int ret;
> +
> + ret = bq25792_read16(pdata, BQ25792_REG01_CHARGE_VOLTAGE_LIMIT, ®);
> + if (ret)
> + return ret;
> +
> + *intval = FIELD_GET(BQ25792_REG01_VREG_MASK, reg) *
> + BQ25792_VBATREG_STEP_UV;
> +
> + return ret;
> +}
> +
> /**
> * bq25703_set_chrg_volt() - Set the maximum charge voltage
> * @pdata: driver platform data
> @@ -291,6 +518,29 @@ static int bq25703_set_chrg_volt(struct bq257xx_chg *pdata, int vbat)
> reg);
> }
>
> +/**
> + * bq25792_set_chrg_volt() - Set the maximum charge voltage
> + * @pdata: driver platform data
> + * @vbat: voltage value to set in uV
> + *
> + * Set the maximum charge voltage by clamping the requested value
> + * between device limits and writing to the appropriate register.
> + *
> + * Return: Returns 0 on success or error on failure to write.
> + */
> +static int bq25792_set_chrg_volt(struct bq257xx_chg *pdata, int vbat)
> +{
> + int vbat_max = pdata->vbat_max;
> + u16 reg;
> +
> + vbat = clamp(vbat, BQ25792_VBATREG_MIN_UV, vbat_max);
> +
> + reg = FIELD_PREP(BQ25792_REG01_VREG_MASK,
> + (vbat / BQ25792_VBATREG_STEP_UV));
> +
> + return bq25792_write16(pdata, BQ25792_REG01_CHARGE_VOLTAGE_LIMIT, reg);
> +}
> +
> /**
> * bq25703_get_iindpm() - Get the maximum set input current
> * @pdata: driver platform data
> @@ -319,6 +569,30 @@ static int bq25703_get_iindpm(struct bq257xx_chg *pdata, int *intval)
> return ret;
> }
>
> +/**
> + * bq25792_get_iindpm() - Get the maximum set input current
> + * @pdata: driver platform data
> + * @intval: pointer to store the maximum input current value
> + *
> + * Read the current input current limit from the device.
> + *
> + * Return: Returns 0 on success or error on failure to read value.
> + */
> +static int bq25792_get_iindpm(struct bq257xx_chg *pdata, int *intval)
> +{
> + u16 reg;
> + int ret;
> +
> + ret = bq25792_read16(pdata, BQ25792_REG06_INPUT_CURRENT_LIMIT, ®);
> + if (ret)
> + return ret;
> +
> + reg = FIELD_GET(BQ25792_REG06_IINDPM_MASK, reg);
> + *intval = reg * BQ25792_IINDPM_STEP_UA;
> +
> + return ret;
> +}
> +
> /**
> * bq25703_set_iindpm() - Set the maximum input current
> * @pdata: driver platform data
> @@ -344,6 +618,29 @@ static int bq25703_set_iindpm(struct bq257xx_chg *pdata, int iindpm)
> FIELD_PREP(BQ25703_IINDPM_MASK, reg));
> }
>
> +/**
> + * bq25792_set_iindpm() - Set the maximum input current
> + * @pdata: driver platform data
> + * @iindpm: current value in uA
> + *
> + * Set the maximum input current by clamping the requested value
> + * between device limits and writing to the appropriate register.
> + *
> + * Return: Returns 0 on success or error on failure to write.
> + */
> +static int bq25792_set_iindpm(struct bq257xx_chg *pdata, int iindpm)
> +{
> + u16 reg;
> + int iindpm_max = pdata->iindpm_max;
> +
> + iindpm = clamp(iindpm, BQ25792_IINDPM_MIN_UA, iindpm_max);
> +
> + reg = iindpm / BQ25792_IINDPM_STEP_UA;
> +
> + return bq25792_write16(pdata, BQ25792_REG06_INPUT_CURRENT_LIMIT,
> + FIELD_PREP(BQ25792_REG06_IINDPM_MASK, reg));
> +}
> +
> /**
> * bq25703_get_vbat() - Get the reported voltage from the battery
> * @pdata: driver platform data
> @@ -368,6 +665,30 @@ static int bq25703_get_vbat(struct bq257xx_chg *pdata, int *intval)
> return ret;
> }
>
> +/**
> + * bq25792_get_vbat() - Get the reported voltage from the battery
> + * @pdata: driver platform data
> + * @intval: pointer to store the battery voltage value
> + *
> + * Read the current ADC value representing the battery voltage
> + * and return it in microvolts.
> + *
> + * Return: Returns 0 on success or error on failure to read value.
> + */
> +static int bq25792_get_vbat(struct bq257xx_chg *pdata, int *intval)
> +{
> + u16 reg;
> + int ret;
> +
> + ret = bq25792_read16(pdata, BQ25792_REG3B_VBAT_ADC, ®);
> + if (ret)
> + return ret;
> +
> + *intval = reg * BQ25792_ADCVSYSVBAT_STEP_UV;
> +
> + return ret;
> +}
> +
> /**
> * bq25703_hw_init() - Set all the required registers to init the charger
> * @pdata: driver platform data
> @@ -434,6 +755,108 @@ static int bq25703_hw_init(struct bq257xx_chg *pdata)
> return ret;
> }
>
> +/**
> + * bq25792_hw_init() - Initialize BQ25792 hardware
> + * @pdata: driver platform data
> + *
> + * Initialize the BQ25792 by disabling the watchdog, enabling discharge
> + * current sensing with 5A limit, and configuring input current regulation.
> + * Set the charge current, charge voltage, minimum system voltage, and
> + * input current limit from platform data. Enable and configure the ADC
> + * to measure all available channels.
> + *
> + * Return: Returns 0 on success or error code on error.
> + */
> +static int bq25792_hw_init(struct bq257xx_chg *pdata)
> +{
> + struct regmap *regmap = pdata->bq->regmap;
> + int ret = 0;
> + u8 reg;
> +
> + /* Disable watchdog (TODO: make it work instead) */
> + ret = regmap_write(regmap, BQ25792_REG10_CHARGER_CONTROL_1, 0);
> + if (ret)
> + return ret;
> +
> + /*
> + * Enable battery discharge current sensing, 5A discharge current
> + * limit, input current regulation and ship FET functions
> + */
> + ret = regmap_write(regmap, BQ25792_REG14_CHARGER_CONTROL_5,
> + BQ25792_REG14_SFET_PRESENT |
> + BQ25792_REG14_EN_IBAT |
> + BQ25792_IBAT_5A |
> + BQ25792_REG14_EN_IINDPM);
> + if (ret)
> + return ret;
> +
> + if (pdata->vbat_max < 5000000) {
> + /* 1S batteries */
> + reg = FIELD_PREP(BQ25792_REG0A_CELL_MASK, BQ25792_CELL_1S);
> + } else if (pdata->vbat_max < 10000000) {
> + /* 2S batteries */
> + reg = FIELD_PREP(BQ25792_REG0A_CELL_MASK, BQ25792_CELL_2S);
> + } else if (pdata->vbat_max < 14000000) {
> + /* 3S batteries */
> + reg = FIELD_PREP(BQ25792_REG0A_CELL_MASK, BQ25792_CELL_3S);
> + } else {
> + /* 4S batteries */
> + reg = FIELD_PREP(BQ25792_REG0A_CELL_MASK, BQ25792_CELL_4S);
> + }
> +
> + /* Recharge voltage detection deglitch time (default 1024ms) */
> + reg |= FIELD_PREP(BQ25792_REG0A_TRECHG_MASK, BQ25792_TRECHG_1024MS);
> +
> + /* Recharge voltage offset: 5% of the set charge voltage */
> + reg |= FIELD_PREP(BQ25792_REG0A_VRECHG_MASK,
> + (pdata->vbat_max / 20 - BQ25792_VRECHG_MIN_UV) / BQ25792_VRECHG_STEP_UV);
> +
> + ret = regmap_write(regmap, BQ25792_REG0A_RECHARGE_CONTROL, reg);
> + if (ret)
> + return ret;
> +
> + ret = pdata->chip->bq257xx_set_ichg(pdata, pdata->ichg_max);
> + if (ret)
> + return ret;
> +
> + ret = pdata->chip->bq257xx_set_vbatreg(pdata, pdata->vbat_max);
> + if (ret)
> + return ret;
> +
> + ret = bq25792_set_min_vsys(pdata, pdata->vsys_min);
> + if (ret)
> + return ret;
> +
> + ret = pdata->chip->bq257xx_set_iindpm(pdata, pdata->iindpm_max);
> + if (ret)
> + return ret;
> +
> + /* Enable the Input Current Optimizer (the rest is at POR value) */
> + ret = regmap_write(regmap, BQ25792_REG0F_CHARGER_CONTROL_0,
> + BQ25792_REG0F_EN_AUTO_IBATDIS |
> + BQ25792_REG0F_EN_CHG |
> + BQ25792_REG0F_EN_ICO |
> + BQ25792_REG0F_EN_TERM);
> + if (ret)
> + return ret;
> +
> + /* Enable the ADC. */
> + ret = regmap_write(regmap, BQ25792_REG2E_ADC_CONTROL, BQ25792_REG2E_ADC_EN);
> + if (ret)
> + return ret;
> +
> + /* Clear per-channel ADC disable bits - enable all channels */
> + ret = regmap_write(regmap, BQ25792_REG2F_ADC_FUNCTION_DISABLE_0, 0);
> + if (ret)
> + return ret;
> +
> + ret = regmap_write(regmap, BQ25792_REG30_ADC_FUNCTION_DISABLE_1, 0);
> + if (ret)
> + return ret;
> +
> + return ret;
> +}
> +
> /**
> * bq25703_hw_shutdown() - Set registers for shutdown
> * @pdata: driver platform data
> @@ -446,6 +869,30 @@ static void bq25703_hw_shutdown(struct bq257xx_chg *pdata)
> BQ25703_EN_LWPWR, BQ25703_EN_LWPWR);
> }
>
> +/**
> + * bq25792_hw_shutdown() - Shutdown BQ25792 hardware
> + * @pdata: driver platform data
> + *
> + * Perform hardware shutdown for the BQ25792. Currently a no-op
> + * as the device does not require special shutdown configuration.
> + */
> +static void bq25792_hw_shutdown(struct bq257xx_chg *pdata)
> +{
> + /* Nothing to do here */
> +}
> +
> +/**
> + * bq257xx_set_charger_property() - Set a power supply property
> + * @psy: power supply device
> + * @prop: power supply property to set
> + * @val: value to set for the property
> + *
> + * Handle requests to set power supply properties such as input current
> + * limit, constant charge voltage, and constant charge current. Routes
> + * the request to the chip-specific implementation.
> + *
> + * Return: Returns 0 on success or -EINVAL if property is not supported.
> + */
> static int bq257xx_set_charger_property(struct power_supply *psy,
> enum power_supply_property prop,
> const union power_supply_propval *val)
> @@ -469,6 +916,19 @@ static int bq257xx_set_charger_property(struct power_supply *psy,
> return -EINVAL;
> }
>
> +/**
> + * bq257xx_get_charger_property() - Get a power supply property
> + * @psy: power supply device
> + * @psp: power supply property to get
> + * @val: pointer to store the property value
> + *
> + * Handle requests to get power supply properties, including status,
> + * health, manufacturer, online state, and various voltage/current
> + * measurements. Reads current device state and routes chip-specific
> + * property requests to appropriate handlers.
> + *
> + * Return: Returns 0 on success or -EINVAL if property is not supported.
> + */
> static int bq257xx_get_charger_property(struct power_supply *psy,
> enum power_supply_property psp,
> union power_supply_propval *val)
> @@ -550,6 +1010,17 @@ static enum power_supply_property bq257xx_power_supply_props[] = {
> POWER_SUPPLY_PROP_USB_TYPE,
> };
>
> +/**
> + * bq257xx_property_is_writeable() - Check if a property is writeable
> + * @psy: power supply device
> + * @prop: power supply property to check
> + *
> + * Determines which power supply properties can be written to. Only
> + * charge current limit, charge voltage limit, and input current
> + * limit are writeable.
> + *
> + * Return: Returns 1 if property is writeable, 0 otherwise.
> + */
> static int bq257xx_property_is_writeable(struct power_supply *psy,
> enum power_supply_property prop)
> {
> @@ -622,6 +1093,17 @@ static void bq257xx_external_power_changed(struct power_supply *psy)
> power_supply_changed(psy);
> }
>
> +/**
> + * bq257xx_irq_handler_thread() - Handle charger interrupt
> + * @irq: interrupt number
> + * @private: pointer to driver private data
> + *
> + * Thread handler for charger interrupts. Triggers re-evaluation of
> + * external power status and updates power supply state in response
> + * to charger events.
> + *
> + * Return: Returns IRQ_HANDLED if interrupt was processed.
> + */
> static irqreturn_t bq257xx_irq_handler_thread(int irq, void *private)
> {
> struct bq257xx_chg *pdata = private;
> @@ -662,6 +1144,22 @@ static const struct bq257xx_chip_info bq25703_chip_info = {
> .bq257xx_get_min_vsys = &bq25703_get_min_vsys,
> };
>
> +static const struct bq257xx_chip_info bq25792_chip_info = {
> + .default_iindpm_uA = BQ25792_IINDPM_DEFAULT_UA,
> + .bq257xx_hw_init = &bq25792_hw_init,
> + .bq257xx_hw_shutdown = &bq25792_hw_shutdown,
> + .bq257xx_get_state = &bq25792_get_state,
> + .bq257xx_get_ichg = &bq25792_get_ichg_cur,
> + .bq257xx_set_ichg = &bq25792_set_ichg_cur,
> + .bq257xx_get_vbatreg = &bq25792_get_chrg_volt,
> + .bq257xx_set_vbatreg = &bq25792_set_chrg_volt,
> + .bq257xx_get_iindpm = &bq25792_get_iindpm,
> + .bq257xx_set_iindpm = &bq25792_set_iindpm,
> + .bq257xx_get_cur = &bq25792_get_cur,
> + .bq257xx_get_vbat = &bq25792_get_vbat,
> + .bq257xx_get_min_vsys = &bq25792_get_min_vsys,
> +};
> +
> /**
> * bq257xx_parse_dt() - Parse the device tree for required properties
> * @pdata: driver platform data
> @@ -707,6 +1205,17 @@ static int bq257xx_parse_dt(struct bq257xx_chg *pdata,
> return 0;
> }
>
> +/**
> + * bq257xx_charger_probe() - Probe routine for charger platform device
> + * @pdev: platform device
> + *
> + * Probe the charger device, allocate driver data structure, select the
> + * appropriate chip-specific function pointers, register the power supply,
> + * parse device tree properties for battery limits, initialize hardware,
> + * and set up the interrupt handler if available.
> + *
> + * Return: Returns 0 on success or error code on failure.
> + */
> static int bq257xx_charger_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> @@ -722,7 +1231,17 @@ static int bq257xx_charger_probe(struct platform_device *pdev)
> return -ENOMEM;
>
> pdata->bq = bq;
> - pdata->chip = &bq25703_chip_info;
> +
> + switch (bq->type) {
> + case BQ25703A:
> + pdata->chip = &bq25703_chip_info;
> + break;
> + case BQ25792:
> + pdata->chip = &bq25792_chip_info;
> + break;
> + default:
> + return dev_err_probe(dev, -EINVAL, "Unknown chip type\n");
> + }
>
> platform_set_drvdata(pdev, pdata);
>
> @@ -760,6 +1279,13 @@ static int bq257xx_charger_probe(struct platform_device *pdev)
> return ret;
> }
>
> +/**
> + * bq257xx_charger_shutdown() - Shutdown routine for charger platform device
> + * @pdev: platform device
> + *
> + * Called during system shutdown to perform charger cleanup, including
> + * disabling watchdog timers or other chip-specific shutdown procedures.
> + */
> static void bq257xx_charger_shutdown(struct platform_device *pdev)
> {
> struct bq257xx_chg *pdata = platform_get_drvdata(pdev);
> diff --git a/include/linux/mfd/bq257xx.h b/include/linux/mfd/bq257xx.h
> index 4ec72eb920f2..379ef4ee8291 100644
> --- a/include/linux/mfd/bq257xx.h
> +++ b/include/linux/mfd/bq257xx.h
> @@ -200,6 +200,20 @@
> #define BQ25792_REG0A_TRECHG_MASK GENMASK(5, 4)
> #define BQ25792_REG0A_VRECHG_MASK GENMASK(3, 0)
>
> +#define BQ25792_CELL_1S 0
> +#define BQ25792_CELL_2S 1
> +#define BQ25792_CELL_3S 2
> +#define BQ25792_CELL_4S 3
> +
> +#define BQ25792_TRECHG_64MS 0
> +#define BQ25792_TRECHG_256MS 1
> +#define BQ25792_TRECHG_1024MS 2
> +#define BQ25792_TRECHG_2048MS 3
> +
> +#define BQ25792_VRECHG_MIN_UV 50000
> +#define BQ25792_VRECHG_STEP_UV 50000
> +#define BQ25792_VRECHG_MAX_UV 800000
> +
> /* VOTG regulation */
> #define BQ25792_REG0B_VOTG_MASK GENMASK(10, 0)
>
>
> --
> 2.53.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v7 0/7] Add support for the TI BQ25792 battery charger
2026-06-02 20:10 [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Alexey Charkov
` (6 preceding siblings ...)
2026-06-02 20:10 ` [PATCH v7 7/7] power: supply: " Alexey Charkov
@ 2026-06-03 20:52 ` Sebastian Reichel
7 siblings, 0 replies; 10+ messages in thread
From: Sebastian Reichel @ 2026-06-03 20:52 UTC (permalink / raw)
To: Alexey Charkov
Cc: Chris Morgan, Mark Brown, Liam Girdwood, Lee Jones, linux-kernel,
linux-pm, stable
[-- Attachment #1: Type: text/plain, Size: 3776 bytes --]
Hi,
On Wed, Jun 03, 2026 at 12:10:48AM +0400, Alexey Charkov wrote:
> This adds support for the TI BQ25792 battery charger, which is similar in
> overall logic to the BQ25703A, but has a different register layout and
> slightly different lower-level programming logic.
>
> Signed-off-by: Alexey Charkov <alchark@flipper.net>
> ---
> Changes in v7:
> - Rebase onto recent -next and dropped patches already applied by Mark and Lee
> - Enable the Input Current Optimizer to improve reliability with unrecognized chargers
> - Explicitly program the battery cell count at init time to alleviate transient glitches
> with the charger going into spurious battery overvoltage state due to misdetected
> battery cell count
> - Handle return values of all regmap writes in the init function
> - Link to v6: https://lore.kernel.org/r/20260331-bq25792-v6-0-0278fba33eb9@flipper.net
>
> Changes in v6:
> - Changed -EINVAL to -ENODEV for non-match cases in the MFD driver, to stay
> in line with what other drivers do in similar situations (Lee Jones)
> - Link to v5: https://lore.kernel.org/r/20260324-bq25792-v5-0-0a2eb58cf11d@flipper.net
>
> Changes in v5:
> - Added non-OF match data and switched to i2c_get_match_data() to support
> non-OF platforms (Lee Jones)
> - Shifted the types in the enum to start at 1 to avoid confusion with
> zero-initialized data and non-match cases (Lee Jones)
> - Reinstated the const qualifier on the MFD cell array (Lee Jones)
> - Link to v4: https://lore.kernel.org/r/20260311-bq25792-v4-0-7213415d9eec@flipper.net
>
> Changes in v4:
> - Avoid additional data structures and pass 'type' within the existing
> struct bq257xx_device instead (Lee Jones)
> - Move comments for new struct fields to the patches where those fields
> are added (Sebastian Reichel)
> - Collect tags from Sebastian Reichel (thanks!)
> - Link to v3: https://lore.kernel.org/r/20260310-bq25792-v3-0-02f8e232d63b@flipper.net
>
> Changes in v3:
> - Move MFD cell definitions back out of the probe function (Lee Jones)
> - Collect tags from Mark Brown, Krzysztof Kozlowski and Chris Morgan (thanks!)
> - Enable ship FET functionality at init for BQ25792
> - Link to v2: https://lore.kernel.org/r/20260306-bq25792-v2-0-6595249d6e6f@flipper.net
>
> Changes in v2:
> - Fix an error in DT schema (thanks Rob's bot)
> - Ensure the broadest constraints for all variants remain in the common
> part of the schema, per writing-schema doc (thanks Krzysztof)
> - Link to v1: https://lore.kernel.org/r/20260303-bq25792-v1-0-e6e5e0033458@flipper.net
>
> ---
> Alexey Charkov (7):
> regulator: bq257xx: Drop the regulator_dev from the driver data
> power: supply: bq257xx: Fix VSYSMIN clamping logic
> power: supply: bq257xx: Make the default current limit a per-chip attribute
> power: supply: bq257xx: Consistently use indirect get/set helpers
> power: supply: bq257xx: Add fields for 'charging' and 'overvoltage' states
I merged patches 2-5.
> regulator: bq257xx: Add support for BQ25792
> power: supply: bq257xx: Add support for BQ25792
This one updates the MFD header and does not apply to me tree. It
will have to wait a cycle, as there is not enough time to sync with
Lee how to proceed :)
Greetings,
-- Sebastian
>
> drivers/power/supply/bq257xx_charger.c | 580 ++++++++++++++++++++++++++++++++-
> drivers/regulator/bq257xx-regulator.c | 106 +++++-
> include/linux/mfd/bq257xx.h | 14 +
> 3 files changed, 681 insertions(+), 19 deletions(-)
> ---
> base-commit: 08484c504b55a98bd100527fbe10a3caf55ff3ff
> change-id: 20260303-bq25792-0132ac86846d
>
> Best regards,
> --
> Alexey Charkov <alchark@flipper.net>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-06-03 20:52 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-02 20:10 [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 1/7] regulator: bq257xx: Drop the regulator_dev from the driver data Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 2/7] power: supply: bq257xx: Fix VSYSMIN clamping logic Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 3/7] power: supply: bq257xx: Make the default current limit a per-chip attribute Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 4/7] power: supply: bq257xx: Consistently use indirect get/set helpers Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 5/7] power: supply: bq257xx: Add fields for 'charging' and 'overvoltage' states Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 6/7] regulator: bq257xx: Add support for BQ25792 Alexey Charkov
2026-06-02 20:10 ` [PATCH v7 7/7] power: supply: " Alexey Charkov
2026-06-03 20:49 ` Sebastian Reichel
2026-06-03 20:52 ` [PATCH v7 0/7] Add support for the TI BQ25792 battery charger Sebastian Reichel
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.