]> www.infradead.org Git - linux.git/commitdiff
power: supply: bq27xxx: Retrieve again when busy
authorJerry Lv <Jerry.Lv@axis.com>
Tue, 15 Apr 2025 03:40:47 +0000 (11:40 +0800)
committerSebastian Reichel <sebastian.reichel@collabora.com>
Sun, 27 Apr 2025 22:24:52 +0000 (00:24 +0200)
Multiple applications may access the battery gauge at the same time, so
the gauge may be busy and EBUSY will be returned. The driver will set a
flag to record the EBUSY state, and this flag will be kept until the next
periodic update. When this flag is set, bq27xxx_battery_get_property()
will just return ENODEV until the flag is updated.

Even if the gauge was busy during the last accessing attempt, returning
ENODEV is not ideal, and can cause confusion in the applications layer.

Instead, retry accessing the I2C to update the flag is as expected, for
the gauge typically recovers from busy state within a few milliseconds.
If still failed to access the gauge, the real error code would be returned
instead of ENODEV (as suggested by Pali Rohár).

Reviewed-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Jerry Lv <Jerry.Lv@axis.com>
Link: https://lore.kernel.org/r/20250415-foo-fix-v2-1-5b45a395e4cc@axis.com
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
drivers/power/supply/bq27xxx_battery.c
drivers/power/supply/bq27xxx_battery_i2c.c

index 2f31d750a4c1e3fe4273e9a010936e7446bee9ea..93dcebbe1141751b9ab32b5fdf6bf4b7f619c12a 100644 (file)
@@ -2131,7 +2131,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy,
        mutex_unlock(&di->lock);
 
        if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0)
-               return -ENODEV;
+               return di->cache.flags;
 
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
index ba0d22d904295060966f0f678d5e648e8cf8bf18..868e95f0887e11f32cdbf11c404abcb551285874 100644 (file)
@@ -6,6 +6,7 @@
  *     Andrew F. Davis <afd@ti.com>
  */
 
+#include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
@@ -31,6 +32,7 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
        struct i2c_msg msg[2];
        u8 data[2];
        int ret;
+       int retry = 0;
 
        if (!client->adapter)
                return -ENODEV;
@@ -47,7 +49,16 @@ static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
        else
                msg[1].len = 2;
 
-       ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+       do {
+               ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+               if (ret == -EBUSY && ++retry < 3) {
+                       /* sleep 10 milliseconds when busy */
+                       usleep_range(10000, 11000);
+                       continue;
+               }
+               break;
+       } while (1);
+
        if (ret < 0)
                return ret;