]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
power: supply: axp288_fuel_gauge: Rework get_status()
authorHans de Goede <hdegoede@redhat.com>
Tue, 26 Dec 2017 12:59:11 +0000 (13:59 +0100)
committerSebastian Reichel <sre@kernel.org>
Tue, 9 Jan 2018 16:41:39 +0000 (17:41 +0100)
Relying on the (dis)charge current reporting for reporting FULL back to
userspace does not work really well and often leads to the reported status
getting stuck at e.g. 98/99% (the fuelgauge is not perfect) for hours.

What happens is that when the battery is full the axp288 keeps charging it
with a very low current. Until it is really really full and once really
really full, some inaccuracies in the adc lead to it then sometimes
reporting a small discharging rate, even though an external pwr source is
used. So we end up with a status of "charging" for hours after the battery
is actually already full and sometimes this then flip-flops to discharging.

This commit fixes this by first checking if a valid Vbus is present and if
it is present using the fuel-gauge's reported percentage to check for a
full battery.

This commit also changes how get_status() determines if the battery is
charging or discharging when not reporting it as full. We still use the
current direction for this, but instead of reading 4 extra registers for
this (2 16 bit regs), simplify things by using the current-direction bit
in the power-status register, which already gets read anyways.

This also reduces the amount of i2c reads to 1 when on battery and 2
when a valid Vbus is present.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
drivers/power/supply/axp288_fuel_gauge.c

index eb60f75f00d7d6da52e83b4db8d72bd6d39fccbe..c0b5e40b23e1087669ac09ee723078fcb9280c31 100644 (file)
 #include <linux/seq_file.h>
 #include <asm/unaligned.h>
 
+#define PS_STAT_VBUS_TRIGGER           (1 << 0)
+#define PS_STAT_BAT_CHRG_DIR           (1 << 2)
+#define PS_STAT_VBAT_ABOVE_VHOLD       (1 << 3)
+#define PS_STAT_VBUS_VALID             (1 << 4)
+#define PS_STAT_VBUS_PRESENT           (1 << 5)
+
 #define CHRG_STAT_BAT_SAFE_MODE                (1 << 3)
 #define CHRG_STAT_BAT_VALID                    (1 << 4)
 #define CHRG_STAT_BAT_PRESENT          (1 << 5)
@@ -336,8 +342,7 @@ static inline void fuel_gauge_remove_debugfs(struct axp288_fg_info *info)
 
 static void fuel_gauge_get_status(struct axp288_fg_info *info)
 {
-       int pwr_stat, ret;
-       int charge, discharge;
+       int pwr_stat, fg_res;
 
        pwr_stat = fuel_gauge_reg_readb(info, AXP20X_PWR_INPUT_STATUS);
        if (pwr_stat < 0) {
@@ -345,29 +350,25 @@ static void fuel_gauge_get_status(struct axp288_fg_info *info)
                        "PWR STAT read failed:%d\n", pwr_stat);
                return;
        }
-       ret = iio_read_channel_raw(info->iio_channel[BAT_CHRG_CURR], &charge);
-       if (ret < 0) {
-               dev_err(&info->pdev->dev,
-                       "ADC charge current read failed:%d\n", ret);
-               return;
-       }
-       ret = iio_read_channel_raw(info->iio_channel[BAT_D_CURR], &discharge);
-       if (ret < 0) {
-               dev_err(&info->pdev->dev,
-                       "ADC discharge current read failed:%d\n", ret);
-               return;
+
+       /* Report full if Vbus is valid and the reported capacity is 100% */
+       if (pwr_stat & PS_STAT_VBUS_VALID) {
+               fg_res = fuel_gauge_reg_readb(info, AXP20X_FG_RES);
+               if (fg_res < 0) {
+                       dev_err(&info->pdev->dev,
+                               "FG RES read failed: %d\n", fg_res);
+                       return;
+               }
+               if (fg_res == (FG_REP_CAP_VALID | 100)) {
+                       info->status = POWER_SUPPLY_STATUS_FULL;
+                       return;
+               }
        }
 
-       if (charge > 0)
+       if (pwr_stat & PS_STAT_BAT_CHRG_DIR)
                info->status = POWER_SUPPLY_STATUS_CHARGING;
-       else if (discharge > 0)
+       else
                info->status = POWER_SUPPLY_STATUS_DISCHARGING;
-       else {
-               if (pwr_stat & CHRG_STAT_BAT_PRESENT)
-                       info->status = POWER_SUPPLY_STATUS_FULL;
-               else
-                       info->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-       }
 }
 
 static int fuel_gauge_get_vbatt(struct axp288_fg_info *info, int *vbatt)