The status reported directly by the battery controller is not always
reliable and should be corrected based on the current draw information.

This implements such a correction with a dedicated function, called
when retrieving the supply status.

Signed-off-by: Paul Kocialkowski <cont...@paulk.fr>
---
 drivers/power/supply/bq27xxx_battery.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/power/supply/bq27xxx_battery.c 
b/drivers/power/supply/bq27xxx_battery.c
index cade00df6162..f7694e775e68 100644
--- a/drivers/power/supply/bq27xxx_battery.c
+++ b/drivers/power/supply/bq27xxx_battery.c
@@ -1171,8 +1171,22 @@ static int bq27xxx_battery_status(struct 
bq27xxx_device_info *di,
                                  union power_supply_propval *val)
 {
        int status;
+       int curr;
+       int flags;
+
+       curr = bq27xxx_read(di, BQ27XXX_REG_AI, false);
+       if (curr < 0) {
+               dev_err(di->dev, "error reading current\n");
+               return curr;
+       }
 
        if (di->chip == BQ27000 || di->chip == BQ27010) {
+               flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true);
+               if (flags & BQ27000_FLAG_CHGS) {
+                       dev_dbg(di->dev, "negative current!\n");
+                       curr = -curr;
+               }
+
                if (di->cache.flags & BQ27000_FLAG_FC)
                        status = POWER_SUPPLY_STATUS_FULL;
                else if (di->cache.flags & BQ27000_FLAG_CHGS)
@@ -1182,6 +1196,8 @@ static int bq27xxx_battery_status(struct 
bq27xxx_device_info *di,
                else
                        status = POWER_SUPPLY_STATUS_DISCHARGING;
        } else {
+               curr = (int)((s16)curr) * 1000;
+
                if (di->cache.flags & BQ27XXX_FLAG_FC)
                        status = POWER_SUPPLY_STATUS_FULL;
                else if (di->cache.flags & BQ27XXX_FLAG_DSC)
@@ -1190,6 +1206,18 @@ static int bq27xxx_battery_status(struct 
bq27xxx_device_info *di,
                        status = POWER_SUPPLY_STATUS_CHARGING;
        }
 
+
+       if (curr == 0 && status != POWER_SUPPLY_STATUS_NOT_CHARGING)
+               status = POWER_SUPPLY_STATUS_FULL;
+
+       if (status == POWER_SUPPLY_STATUS_FULL) {
+               /* Drawing or providing current when full */
+               if (curr > 0)
+                       status = POWER_SUPPLY_STATUS_CHARGING;
+               else if (curr < 0)
+                       status = POWER_SUPPLY_STATUS_DISCHARGING;
+       }
+
        if (di->status_retry == 0 && di->status_change_reference != status) {
                di->status_change_reference = status;
                power_supply_changed(di->bat);
-- 
2.12.2

Reply via email to