summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorArthur Demchenkov <spinal.by@gmail.com>2021-01-10 21:54:00 +0200
committerSebastian Reichel <sre@kernel.org>2021-01-14 23:42:42 +0100
commitfaf6e9008114f105353f7b8391efdda40633adf9 (patch)
treebb92f4830f898eaaf86e853cfaf39fac96d20fd8 /drivers/power
parent4fb0357c6d57bc8c6fc517e66ece290965e73b11 (diff)
power: supply: cpcap-battery: Keep track of state for capacity reporting
Save the battery empty and full states so we can use those to estimate the battery capacity in the following patches. If the user provides us with charge_full value (which it could save in a permanent storage between reboots), initialize low and high counter_uah with calculated values. If we hit battery low once, we should stick on reporting it until the charger is connected. This way low->counter_uah will be updated properly, and that will allow us to get more accurate charge_full value. Based on an earlier patch by Tony Lindgren with charge_full usage and other improvments done by Arthur Demchenkov. Cc: Arthur Demchenkov <spinal.by@gmail.com> Cc: Carl Philipp Klemm <philipp@uvos.xyz> Cc: Merlijn Wajer <merlijn@wizzup.org> Cc: Pavel Machek <pavel@ucw.cz> Co-developed-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Arthur Demchenkov <spinal.by@gmail.com> [tony@atomide.com: combined earlier patches, updated comments] Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/supply/cpcap-battery.c56
1 files changed, 55 insertions, 1 deletions
diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c
index 25b520e15380..bd89e5043484 100644
--- a/drivers/power/supply/cpcap-battery.c
+++ b/drivers/power/supply/cpcap-battery.c
@@ -111,6 +111,8 @@ struct cpcap_coulomb_counter_data {
enum cpcap_battery_state {
CPCAP_BATTERY_STATE_PREVIOUS,
CPCAP_BATTERY_STATE_LATEST,
+ CPCAP_BATTERY_STATE_EMPTY,
+ CPCAP_BATTERY_STATE_FULL,
CPCAP_BATTERY_STATE_NR,
};
@@ -166,6 +168,18 @@ cpcap_battery_previous(struct cpcap_battery_ddata *ddata)
return cpcap_battery_get_state(ddata, CPCAP_BATTERY_STATE_PREVIOUS);
}
+static struct cpcap_battery_state_data *
+cpcap_battery_get_empty(struct cpcap_battery_ddata *ddata)
+{
+ return cpcap_battery_get_state(ddata, CPCAP_BATTERY_STATE_EMPTY);
+}
+
+static struct cpcap_battery_state_data *
+cpcap_battery_get_full(struct cpcap_battery_ddata *ddata)
+{
+ return cpcap_battery_get_state(ddata, CPCAP_BATTERY_STATE_FULL);
+}
+
static int cpcap_charger_battery_temperature(struct cpcap_battery_ddata *ddata,
int *value)
{
@@ -431,9 +445,23 @@ static bool cpcap_battery_full(struct cpcap_battery_ddata *ddata)
return ddata->is_full;
}
+static bool cpcap_battery_low(struct cpcap_battery_ddata *ddata)
+{
+ struct cpcap_battery_state_data *state = cpcap_battery_latest(ddata);
+ static bool is_low;
+
+ if (state->current_ua > 0 && (state->voltage <= 3350000 || is_low))
+ is_low = true;
+ else
+ is_low = false;
+
+ return is_low;
+}
+
static int cpcap_battery_update_status(struct cpcap_battery_ddata *ddata)
{
- struct cpcap_battery_state_data state, *latest, *previous;
+ struct cpcap_battery_state_data state, *latest, *previous,
+ *empty, *full;
ktime_t now;
int error;
@@ -462,6 +490,32 @@ static int cpcap_battery_update_status(struct cpcap_battery_ddata *ddata)
memcpy(previous, latest, sizeof(*previous));
memcpy(latest, &state, sizeof(*latest));
+ if (cpcap_battery_full(ddata)) {
+ full = cpcap_battery_get_full(ddata);
+ memcpy(full, latest, sizeof(*full));
+
+ empty = cpcap_battery_get_empty(ddata);
+ if (empty->voltage && empty->voltage != -1) {
+ empty->voltage = -1;
+ ddata->charge_full =
+ empty->counter_uah - full->counter_uah;
+ } else if (ddata->charge_full) {
+ empty->voltage = -1;
+ empty->counter_uah =
+ full->counter_uah + ddata->charge_full;
+ }
+ } else if (cpcap_battery_low(ddata)) {
+ empty = cpcap_battery_get_empty(ddata);
+ memcpy(empty, latest, sizeof(*empty));
+
+ full = cpcap_battery_get_full(ddata);
+ if (full->voltage) {
+ full->voltage = 0;
+ ddata->charge_full =
+ empty->counter_uah - full->counter_uah;
+ }
+ }
+
return 0;
}