Commit 939a1161 authored by Hans de Goede's avatar Hans de Goede Committed by Sebastian Reichel

power: supply: bq27xxx: Ensure power_supply_changed() is called on current sign changes

On gauges where the current register is signed, there is no charging
flag in the flags register. So only checking flags will not result
in power_supply_changed() getting called when e.g. a charger is plugged
in and the current sign changes from negative (discharging) to
positive (charging).

This causes userspace's notion of the status to lag until userspace
does a poll.

And when a power_supply_leds.c LED trigger is used to indicate charging
status with a LED, this LED will lag until the capacity percentage
changes, which may take many minutes (because the LED trigger only is
updated on power_supply_changed() calls).

Fix this by calling bq27xxx_battery_current_and_status() on gauges with
a signed current register and checking if the status has changed.

Fixes: 297a533b ("bq27x00: Cache battery registers")
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
parent ff4c4a2a
...@@ -1836,6 +1836,7 @@ static int bq27xxx_battery_current_and_status( ...@@ -1836,6 +1836,7 @@ static int bq27xxx_battery_current_and_status(
static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di)
{ {
union power_supply_propval status = di->last_status;
struct bq27xxx_reg_cache cache = {0, }; struct bq27xxx_reg_cache cache = {0, };
bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; bool has_singe_flag = di->opts & BQ27XXX_O_ZERO;
...@@ -1860,14 +1861,24 @@ static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) ...@@ -1860,14 +1861,24 @@ static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di)
if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR)
cache.cycle_count = bq27xxx_battery_read_cyct(di); cache.cycle_count = bq27xxx_battery_read_cyct(di);
/*
* On gauges with signed current reporting the current must be
* checked to detect charging <-> discharging status changes.
*/
if (!(di->opts & BQ27XXX_O_ZERO))
bq27xxx_battery_current_and_status(di, NULL, &status, &cache);
/* We only have to read charge design full once */ /* We only have to read charge design full once */
if (di->charge_design_full <= 0) if (di->charge_design_full <= 0)
di->charge_design_full = bq27xxx_battery_read_dcap(di); di->charge_design_full = bq27xxx_battery_read_dcap(di);
} }
if ((di->cache.capacity != cache.capacity) || if ((di->cache.capacity != cache.capacity) ||
(di->cache.flags != cache.flags)) (di->cache.flags != cache.flags) ||
(di->last_status.intval != status.intval)) {
di->last_status.intval = status.intval;
power_supply_changed(di->bat); power_supply_changed(di->bat);
}
if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) if (memcmp(&di->cache, &cache, sizeof(cache)) != 0)
di->cache = cache; di->cache = cache;
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#ifndef __LINUX_BQ27X00_BATTERY_H__ #ifndef __LINUX_BQ27X00_BATTERY_H__
#define __LINUX_BQ27X00_BATTERY_H__ #define __LINUX_BQ27X00_BATTERY_H__
#include <linux/power_supply.h>
enum bq27xxx_chip { enum bq27xxx_chip {
BQ27000 = 1, /* bq27000, bq27200 */ BQ27000 = 1, /* bq27000, bq27200 */
BQ27010, /* bq27010, bq27210 */ BQ27010, /* bq27010, bq27210 */
...@@ -70,6 +72,7 @@ struct bq27xxx_device_info { ...@@ -70,6 +72,7 @@ struct bq27xxx_device_info {
int charge_design_full; int charge_design_full;
bool removed; bool removed;
unsigned long last_update; unsigned long last_update;
union power_supply_propval last_status;
struct delayed_work work; struct delayed_work work;
struct power_supply *bat; struct power_supply *bat;
struct list_head list; struct list_head list;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment