* [PATCH v7] bq27xxx: support interchangeable OnePlus 6/6T fuel gauges
@ 2026-10-18 23:03 Rinat Muhamedgaliev via B4 Relay
2026-10-18 23:03 ` [PATCH v7] 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 23:03 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 v7:
- Determine the expected DeviceType through an extensible chip switch.
- Mark the probe-time list for extension with DeviceType-capable fuel gauges.
- Link to v6: https://patch.msgid.link/20261019-master-v6-0-c4b36129721e@gmail.com
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 | 67 ++++++++++++++++++++++++++++++
1 file changed, 67 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 v7] power: supply: bq27xxx: detect bq27541 behind bq27411 compatible 2026-10-18 23:03 [PATCH v7] bq27xxx: support interchangeable OnePlus 6/6T fuel gauges Rinat Muhamedgaliev via B4 Relay @ 2026-10-18 23:03 ` Rinat Muhamedgaliev via B4 Relay 2026-10-18 23:47 ` Pali Rohár 0 siblings, 1 reply; 3+ messages in thread From: Rinat Muhamedgaliev via B4 Relay @ 2026-10-18 23:03 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 | 67 ++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 94b00bb89c17..a9982953e4f2 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,56 @@ 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; + + switch (di->chip) { + case BQ27411: + expected_type = BQ27411_DEVICE_TYPE; + break; + case BQ27541: + expected_type = BQ27541_DEVICE_TYPE; + break; + default: + dev_warn(di->dev, "expected DeviceType undefined\n"); + return 0; + } + + 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; + + 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 +224,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; + /* Add fuel gauges with supported DeviceType reporting to this list. */ + 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 [flat|nested] 3+ messages in thread
* Re: [PATCH v7] power: supply: bq27xxx: detect bq27541 behind bq27411 compatible 2026-10-18 23:03 ` [PATCH v7] power: supply: bq27xxx: detect bq27541 behind bq27411 compatible Rinat Muhamedgaliev via B4 Relay @ 2026-10-18 23:47 ` Pali Rohár 0 siblings, 0 replies; 3+ messages in thread From: Pali Rohár @ 2026-10-18 23:47 UTC (permalink / raw) To: Rinat Muhamedgaliev Cc: linux-pm, sre, afd, konrad.dybcio, david, krzk, linux-arm-msm, linux-kernel On Monday 19 October 2026 02:03:39 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 | 67 ++++++++++++++++++++++++++++++ > 1 file changed, 67 insertions(+) > > diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c > index 94b00bb89c17..a9982953e4f2 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,56 @@ 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; > + > + switch (di->chip) { > + case BQ27411: > + expected_type = BQ27411_DEVICE_TYPE; > + break; > + case BQ27541: > + expected_type = BQ27541_DEVICE_TYPE; > + break; > + default: > + dev_warn(di->dev, "expected DeviceType undefined\n"); > + return 0; > + } > + > + 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; > + > + 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 +224,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; > > + /* Add fuel gauges with supported DeviceType reporting to this list. */ > + 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 > > Hello, my understanding is that this whole code is not i2c specific as it uses the bq27xxx_device_info abstraction APIs. Therefore should not be this code rather part of the bus-neutral bq27xxx_battery_setup() function which is in the bq27xxx_battery.c file? Also that file already contains definitions of register maps. This change is adding new register reading/writing which looks to be inconsistent with the way how the whole driver is structured and how it access registers. For example the BQ27XXX_REG_CTRL is already defined in the bq27xxx_battery.c file. And there is also enum /* control register params */ where the BQ27XXX_DEVICE_TYPE constant should belong (as there are all other commands defined). ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-18 23:47 UTC | newest] Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-10-18 23:03 [PATCH v7] bq27xxx: support interchangeable OnePlus 6/6T fuel gauges Rinat Muhamedgaliev via B4 Relay 2026-10-18 23:03 ` [PATCH v7] power: supply: bq27xxx: detect bq27541 behind bq27411 compatible Rinat Muhamedgaliev via B4 Relay 2026-10-18 23:47 ` Pali Rohár
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®