power: supply: cpcap-battery: Keep track of state for capacity reporting
authorArthur Demchenkov <spinal.by@gmail.com>
Sun, 10 Jan 2021 19:54:00 +0000 (21:54 +0200)
committerSebastian Reichel <sre@kernel.org>
Thu, 14 Jan 2021 22:42:42 +0000 (23:42 +0100)
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>
drivers/power/supply/cpcap-battery.c

index 25b520e..bd89e50 100644 (file)
@@ -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;
 }