* [PATCH v6] bq27xxx: support interchangeable OnePlus 6/6T fuel gauges
@ 2026-10-18 21:15 Rinat Muhamedgaliev via B4 Relay
2026-10-18 21:15 ` [PATCH v6] power: supply: bq27xxx: detect bq27541 behind bq27411 compatible Rinat Muhamedgaliev via B4 Relay
0 siblings, 1 reply; 3+ messages in thread
From: Rinat Muhamedgaliev via B4 Relay @ 2026-10-18 21:15 UTC (permalink / raw)
To: linux-pm
Cc: pali, sre, afd, konrad.dybcio, david, krzk, linux-arm-msm,
linux-kernel, Rinat Muhamedgaliev
OnePlus 6 and 6T replacement battery packs can contain either a bq27411 or a
bq27541 fuel gauge. The latter requires a different register map and produces
invalid battery readings when interpreted as a bq27411.
The I2C driver reads DeviceType while probing either of those compatible
devices and selects the matching profile.
The bq27541 path was tested on a OnePlus 6T with DeviceType 0x0541. It
reported 4.338 V, 100% capacity, 27.8 C, and Full/Good battery status.
Testing on an OnePlus 6 or 6T whose fuel gauge reports DeviceType 0x0421
(bq27411) would be appreciated.
Changes in v6:
- Compare the detected model with the compatible-selected model.
- Support both BQ27411-to-BQ27541 and BQ27541-to-BQ27411 detection.
- Document the pair of models checked at probe time.
- Link to v5: https://patch.msgid.link/20261018-master-v5-0-0be16441cdd1@gmail.com
Changes in v5:
- Report detected and expected DeviceType values instead of hard-coding chip names.
- Describe an unknown DeviceType as unrecognized.
- Link to v4: https://patch.msgid.link/20260928-master-v4-1-052c73ec1767@gmail.com
Changes in v4:
- Drop the generic compatible and binding update.
- Keep the established OnePlus DTS unchanged.
- Detect bq27541 from DeviceType in the bq27411 probe path.
- Send as a new thread.
---
Rinat Muhamedgaliev (1):
power: supply: bq27xxx: detect bq27541 behind bq27411 compatible
drivers/power/supply/bq27xxx_battery_i2c.c | 57 ++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
---
base-commit: 830b3c68c1fb1e9176028d02ef86f3cf76aa2476
change-id: 20260927-master-bd0afd9696ef
Best regards,
--
Rinat Muhamedgaliev <rinat.muhamedgaliev@gmail.com>
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH v6] power: supply: bq27xxx: detect bq27541 behind bq27411 compatible 2026-10-18 21:15 [PATCH v6] bq27xxx: support interchangeable OnePlus 6/6T fuel gauges Rinat Muhamedgaliev via B4 Relay @ 2026-10-18 21:15 ` Rinat Muhamedgaliev via B4 Relay 2026-10-18 22:17 ` David Heidelberg 0 siblings, 1 reply; 3+ messages in thread From: Rinat Muhamedgaliev via B4 Relay @ 2026-10-18 21:15 UTC (permalink / raw) To: linux-pm Cc: pali, sre, afd, konrad.dybcio, david, krzk, linux-arm-msm, linux-kernel, Rinat Muhamedgaliev From: Rinat Muhamedgaliev <rinat.muhamedgaliev@gmail.com> OnePlus 6 and 6T replacement battery packs may contain either a bq27411 or a bq27541 fuel gauge at I2C address 0x55. The device tree currently identifies the gauge as bq27411, but a bq27541 uses a different register map and then reports invalid battery values. Read the DeviceType control subcommand when probing a bq27411. Keep the existing profile for DeviceType 0x0421, but select the bq27541 profile for DeviceType 0x0541. This retains the established DT ABI and supports replacement packs without introducing a generic compatible. Tested on OnePlus 6T (fajita) with DeviceType 0x0541: voltage, state of charge, and temperature were reported correctly. Testing on hardware with DeviceType 0x0421 would be appreciated. Signed-off-by: Rinat Muhamedgaliev <rinat.muhamedgaliev@gmail.com> --- drivers/power/supply/bq27xxx_battery_i2c.c | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 94b00bb89c17..0b957888ad2b 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -16,6 +16,11 @@ static DEFINE_IDR(battery_id); static DEFINE_MUTEX(battery_mutex); +#define BQ27XXX_REG_CTRL 0x00 +#define BQ27XXX_DEVICE_TYPE 0x0001 +#define BQ27411_DEVICE_TYPE 0x0421 +#define BQ27541_DEVICE_TYPE 0x0541 + static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data) { struct bq27xxx_device_info *di = data; @@ -136,6 +141,46 @@ static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di, return 0; } +static int bq27xxx_battery_i2c_check_device_type(struct bq27xxx_device_info *di) +{ + enum bq27xxx_chip detected_chip; + int expected_type; + int ret; + + ret = di->bus.write(di, BQ27XXX_REG_CTRL, BQ27XXX_DEVICE_TYPE, + false); + if (ret < 0) + return ret; + + ret = di->bus.read(di, BQ27XXX_REG_CTRL, false); + if (ret < 0) + return ret; + + switch (ret) { + case BQ27411_DEVICE_TYPE: + detected_chip = BQ27411; + break; + case BQ27541_DEVICE_TYPE: + detected_chip = BQ27541; + break; + default: + dev_err(di->dev, "unrecognized DeviceType 0x%04x\n", ret); + return -ENODEV; + } + + if (detected_chip == di->chip) + return 0; + + expected_type = di->chip == BQ27411 ? BQ27411_DEVICE_TYPE : + BQ27541_DEVICE_TYPE; + dev_warn(di->dev, + "detected DeviceType 0x%04x instead of expected 0x%04x\n", + ret, expected_type); + di->chip = detected_chip; + + return 0; +} + static int bq27xxx_battery_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -169,6 +214,18 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client, di->bus.read_bulk = bq27xxx_battery_i2c_bulk_read; di->bus.write_bulk = bq27xxx_battery_i2c_bulk_write; + /* BQ27411 and BQ27541 may be interchanged in replacement battery packs. */ + switch (di->chip) { + case BQ27411: + case BQ27541: + ret = bq27xxx_battery_i2c_check_device_type(di); + if (ret) + goto err_failed; + break; + default: + break; + } + ret = bq27xxx_battery_setup(di); if (ret) goto err_failed; -- 2.56.0 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v6] power: supply: bq27xxx: detect bq27541 behind bq27411 compatible 2026-10-18 21:15 ` [PATCH v6] power: supply: bq27xxx: detect bq27541 behind bq27411 compatible Rinat Muhamedgaliev via B4 Relay @ 2026-10-18 22:17 ` David Heidelberg 0 siblings, 0 replies; 3+ messages in thread From: David Heidelberg @ 2026-10-18 22:17 UTC (permalink / raw) To: rinat.muhamedgaliev, linux-pm Cc: pali, sre, afd, konrad.dybcio, krzk, linux-arm-msm, linux-kernel On 18/10/2026 23:15, Rinat Muhamedgaliev via B4 Relay wrote: > From: Rinat Muhamedgaliev <rinat.muhamedgaliev@gmail.com> > > OnePlus 6 and 6T replacement battery packs may contain either a bq27411 > or a bq27541 fuel gauge at I2C address 0x55. The device tree currently > identifies the gauge as bq27411, but a bq27541 uses a different register > map and then reports invalid battery values. > > Read the DeviceType control subcommand when probing a bq27411. Keep the > existing profile for DeviceType 0x0421, but select the bq27541 profile > for DeviceType 0x0541. This retains the established DT ABI and supports > replacement packs without introducing a generic compatible. > > Tested on OnePlus 6T (fajita) with DeviceType 0x0541: voltage, state of > charge, and temperature were reported correctly. Testing on hardware with > DeviceType 0x0421 would be appreciated. > > Signed-off-by: Rinat Muhamedgaliev <rinat.muhamedgaliev@gmail.com> > --- > drivers/power/supply/bq27xxx_battery_i2c.c | 57 ++++++++++++++++++++++++++++++ > 1 file changed, 57 insertions(+) > > diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c > index 94b00bb89c17..0b957888ad2b 100644 > --- a/drivers/power/supply/bq27xxx_battery_i2c.c > +++ b/drivers/power/supply/bq27xxx_battery_i2c.c > @@ -16,6 +16,11 @@ > static DEFINE_IDR(battery_id); > static DEFINE_MUTEX(battery_mutex); > > +#define BQ27XXX_REG_CTRL 0x00 > +#define BQ27XXX_DEVICE_TYPE 0x0001 > +#define BQ27411_DEVICE_TYPE 0x0421 > +#define BQ27541_DEVICE_TYPE 0x0541 > + > static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data) > { > struct bq27xxx_device_info *di = data; > @@ -136,6 +141,46 @@ static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di, > return 0; > } > > +static int bq27xxx_battery_i2c_check_device_type(struct bq27xxx_device_info *di) > +{ > + enum bq27xxx_chip detected_chip; > + int expected_type; > + int ret; > + > + ret = di->bus.write(di, BQ27XXX_REG_CTRL, BQ27XXX_DEVICE_TYPE, > + false); > + if (ret < 0) > + return ret; > + > + ret = di->bus.read(di, BQ27XXX_REG_CTRL, false); > + if (ret < 0) > + return ret; > + > + switch (ret) { > + case BQ27411_DEVICE_TYPE: > + detected_chip = BQ27411; > + break; > + case BQ27541_DEVICE_TYPE: > + detected_chip = BQ27541; > + break; > + default: > + dev_err(di->dev, "unrecognized DeviceType 0x%04x\n", ret); > + return -ENODEV; > + } > + > + if (detected_chip == di->chip) > + return 0; > + > + expected_type = di->chip == BQ27411 ? BQ27411_DEVICE_TYPE : > + BQ27541_DEVICE_TYPE; This is not that generic, I would go for extensible design, something like: switch (di->chip) { case BQ27411: expected_type = BQ27411_DEVICE_TYPE case BQ27541: expected_type = BQ27541_DEVICE_TYPE default: dev_warn(di->dev, "expected chip undefined\n"); } > + dev_warn(di->dev, > + "detected DeviceType 0x%04x instead of expected 0x%04x\n", > + ret, expected_type); > + di->chip = detected_chip; > + > + return 0; > +} > + > static int bq27xxx_battery_i2c_probe(struct i2c_client *client, > const struct i2c_device_id *id) > { > @@ -169,6 +214,18 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client, > di->bus.read_bulk = bq27xxx_battery_i2c_bulk_read; > di->bus.write_bulk = bq27xxx_battery_i2c_bulk_write; > > + /* BQ27411 and BQ27541 may be interchanged in replacement battery packs. */ We can see this from the code. The comment should imply the list should be extended with devices which can be detected over i2c. For all devices supporting reporting it's ID - if we can check at boot it's really reporting, it brings the value - e.g. broken or different device will not show 0 or 100% of battery charge, but fail to load. Otherwise IMHO looks good. Thanks > + switch (di->chip) { > + case BQ27411: > + case BQ27541: > + ret = bq27xxx_battery_i2c_check_device_type(di); > + if (ret) > + goto err_failed; > + break; > + default: > + break; > + } > + > ret = bq27xxx_battery_setup(di); > if (ret) > goto err_failed; > ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-18 22:17 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-18 21:15 [PATCH v6] bq27xxx: support interchangeable OnePlus 6/6T fuel gauges Rinat Muhamedgaliev via B4 Relay 2026-10-18 21:15 ` [PATCH v6] power: supply: bq27xxx: detect bq27541 behind bq27411 compatible Rinat Muhamedgaliev via B4 Relay 2026-10-18 22:17 ` David Heidelberg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox