aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2017-12-26 07:59:11 -0500
committerSebastian Reichel <sre@kernel.org>2018-01-09 11:41:39 -0500
commit2b5a4b4bf2224f4f6b6631091bd51cb08d3094be (patch)
tree106d05c3511243dc552c9129b0e5c4a37c1c2c60
parent8eb96f136fe12c3c475326a581098ff3a590acbb (diff)
power: supply: axp288_fuel_gauge: Rework get_status()
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>
-rw-r--r--drivers/power/supply/axp288_fuel_gauge.c43
1 files changed, 22 insertions, 21 deletions
diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c
index eb60f75f00d7..c0b5e40b23e1 100644
--- a/drivers/power/supply/axp288_fuel_gauge.c
+++ b/drivers/power/supply/axp288_fuel_gauge.c
@@ -32,6 +32,12 @@
32#include <linux/seq_file.h> 32#include <linux/seq_file.h>
33#include <asm/unaligned.h> 33#include <asm/unaligned.h>
34 34
35#define PS_STAT_VBUS_TRIGGER (1 << 0)
36#define PS_STAT_BAT_CHRG_DIR (1 << 2)
37#define PS_STAT_VBAT_ABOVE_VHOLD (1 << 3)
38#define PS_STAT_VBUS_VALID (1 << 4)
39#define PS_STAT_VBUS_PRESENT (1 << 5)
40
35#define CHRG_STAT_BAT_SAFE_MODE (1 << 3) 41#define CHRG_STAT_BAT_SAFE_MODE (1 << 3)
36#define CHRG_STAT_BAT_VALID (1 << 4) 42#define CHRG_STAT_BAT_VALID (1 << 4)
37#define CHRG_STAT_BAT_PRESENT (1 << 5) 43#define CHRG_STAT_BAT_PRESENT (1 << 5)
@@ -336,8 +342,7 @@ static inline void fuel_gauge_remove_debugfs(struct axp288_fg_info *info)
336 342
337static void fuel_gauge_get_status(struct axp288_fg_info *info) 343static void fuel_gauge_get_status(struct axp288_fg_info *info)
338{ 344{
339 int pwr_stat, ret; 345 int pwr_stat, fg_res;
340 int charge, discharge;
341 346
342 pwr_stat = fuel_gauge_reg_readb(info, AXP20X_PWR_INPUT_STATUS); 347 pwr_stat = fuel_gauge_reg_readb(info, AXP20X_PWR_INPUT_STATUS);
343 if (pwr_stat < 0) { 348 if (pwr_stat < 0) {
@@ -345,29 +350,25 @@ static void fuel_gauge_get_status(struct axp288_fg_info *info)
345 "PWR STAT read failed:%d\n", pwr_stat); 350 "PWR STAT read failed:%d\n", pwr_stat);
346 return; 351 return;
347 } 352 }
348 ret = iio_read_channel_raw(info->iio_channel[BAT_CHRG_CURR], &charge); 353
349 if (ret < 0) { 354 /* Report full if Vbus is valid and the reported capacity is 100% */
350 dev_err(&info->pdev->dev, 355 if (pwr_stat & PS_STAT_VBUS_VALID) {
351 "ADC charge current read failed:%d\n", ret); 356 fg_res = fuel_gauge_reg_readb(info, AXP20X_FG_RES);
352 return; 357 if (fg_res < 0) {
353 } 358 dev_err(&info->pdev->dev,
354 ret = iio_read_channel_raw(info->iio_channel[BAT_D_CURR], &discharge); 359 "FG RES read failed: %d\n", fg_res);
355 if (ret < 0) { 360 return;
356 dev_err(&info->pdev->dev, 361 }
357 "ADC discharge current read failed:%d\n", ret); 362 if (fg_res == (FG_REP_CAP_VALID | 100)) {
358 return; 363 info->status = POWER_SUPPLY_STATUS_FULL;
364 return;
365 }
359 } 366 }
360 367
361 if (charge > 0) 368 if (pwr_stat & PS_STAT_BAT_CHRG_DIR)
362 info->status = POWER_SUPPLY_STATUS_CHARGING; 369 info->status = POWER_SUPPLY_STATUS_CHARGING;
363 else if (discharge > 0) 370 else
364 info->status = POWER_SUPPLY_STATUS_DISCHARGING; 371 info->status = POWER_SUPPLY_STATUS_DISCHARGING;
365 else {
366 if (pwr_stat & CHRG_STAT_BAT_PRESENT)
367 info->status = POWER_SUPPLY_STATUS_FULL;
368 else
369 info->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
370 }
371} 372}
372 373
373static int fuel_gauge_get_vbatt(struct axp288_fg_info *info, int *vbatt) 374static int fuel_gauge_get_vbatt(struct axp288_fg_info *info, int *vbatt)