From patchwork Sun Jan 19 20:11:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 11340739 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7FA8292A for ; Sun, 19 Jan 2020 20:11:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5ED6E2071C for ; Sun, 19 Jan 2020 20:11:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728682AbgASULe (ORCPT ); Sun, 19 Jan 2020 15:11:34 -0500 Received: from muru.com ([72.249.23.125]:51782 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727138AbgASULe (ORCPT ); Sun, 19 Jan 2020 15:11:34 -0500 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id 8E361804F; Sun, 19 Jan 2020 20:12:15 +0000 (UTC) From: Tony Lindgren To: Sebastian Reichel Cc: linux-pm@vger.kernel.org, linux-omap@vger.kernel.org, Merlijn Wajer , Pavel Machek Subject: [PATCH 1/3] RFC: power: supply: cpcap-battery: Add helper for rough capacity Date: Sun, 19 Jan 2020 12:11:22 -0800 Message-Id: <20200119201124.29620-1-tony@atomide.com> X-Mailer: git-send-email 2.24.1 MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Get a rough battery charge estimate until we've seen a high or low battery level. After that we can use the coulomb counter to calculate the battery capacity. Note that I should probably update this to support ocv-capacity-table before this makes sense to apply. With ocv-capacity-table we should be able to estimate battery state as described in the documentation for Documentation/devicetree/bindings/power/supply/battery.txt. We do have some unknown battery data available over 1-wire, but the format is unkonwn. If somebody ever figures out that format, we can then switch to use the real battery data instead of ocv-capacity-table. Cc: Merlijn Wajer Cc: Pavel Machek Not-yet-Signed-off-by: Tony Lindgren --- drivers/power/supply/cpcap-battery.c | 70 +++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -136,6 +136,29 @@ struct cpcap_battery_ddata { u16 vendor; }; +struct cpcap_battery_capacity { + int capacity; + int voltage; + int percentage; +}; + +#define CPCAP_CAP(l, v, p) \ +{ \ + .capacity = (l), \ + .voltage = (v), \ + .percentage = (p), \ +}, + +/* Pessimistic battery capacity mapping before high or low value is seen */ +static const struct cpcap_battery_capacity cpcap_battery_cap[] = { + CPCAP_CAP(POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN, 0, 0) + CPCAP_CAP(POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL, 3100000, 0) + CPCAP_CAP(POWER_SUPPLY_CAPACITY_LEVEL_LOW, 3300000, 2) + CPCAP_CAP(POWER_SUPPLY_CAPACITY_LEVEL_NORMAL, 3700000, 50) + CPCAP_CAP(POWER_SUPPLY_CAPACITY_LEVEL_HIGH, 4000000, 75) + CPCAP_CAP(POWER_SUPPLY_CAPACITY_LEVEL_FULL, 4200000 - 18000, 100) +}; + #define CPCAP_NO_BATTERY -400 static struct cpcap_battery_state_data * @@ -411,6 +434,40 @@ static int cpcap_battery_update_status(struct cpcap_battery_ddata *ddata) return 0; } +static void cpcap_battery_get_rough(struct cpcap_battery_ddata *ddata, + int *level, int *percentage) +{ + struct cpcap_battery_state_data *latest; + const struct cpcap_battery_capacity *cap = NULL; + int voltage, i; + + latest = cpcap_battery_latest(ddata); + voltage = latest->voltage; + + for (i = ARRAY_SIZE(cpcap_battery_cap) - 1; i >=0; i--) { + cap = &cpcap_battery_cap[i]; + if (voltage >= cap->voltage) + break; + } + + if (!cap) + return; + + if (level) + *level = cap->capacity; + if (percentage) + *percentage = cap->percentage; +} + +static int cpcap_battery_get_rough_capacity(struct cpcap_battery_ddata *ddata) +{ + int capacity = 0; + + cpcap_battery_get_rough(ddata, &capacity, NULL); + + return capacity; +} + static enum power_supply_property cpcap_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, @@ -516,18 +573,7 @@ static int cpcap_battery_get_property(struct power_supply *psy, val->intval = div64_s64(tmp, 100); break; case POWER_SUPPLY_PROP_CAPACITY_LEVEL: - if (cpcap_battery_full(ddata)) - val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; - else if (latest->voltage >= 3750000) - val->intval = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; - else if (latest->voltage >= 3300000) - val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; - else if (latest->voltage > 3100000) - val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; - else if (latest->voltage <= 3100000) - val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; - else - val->intval = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; + val->intval = cpcap_battery_get_rough_capacity(ddata); break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: val->intval = ddata->config.info.charge_full_design; From patchwork Sun Jan 19 20:11:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 11340743 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B7B26188B for ; Sun, 19 Jan 2020 20:11:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A11A8206B7 for ; Sun, 19 Jan 2020 20:11:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728712AbgASULe (ORCPT ); Sun, 19 Jan 2020 15:11:34 -0500 Received: from muru.com ([72.249.23.125]:51790 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727138AbgASULe (ORCPT ); Sun, 19 Jan 2020 15:11:34 -0500 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id A0DDC80F6; Sun, 19 Jan 2020 20:12:16 +0000 (UTC) From: Tony Lindgren To: Sebastian Reichel Cc: linux-pm@vger.kernel.org, linux-omap@vger.kernel.org, Merlijn Wajer , Pavel Machek Subject: [PATCH 2/3] RFC: power: supply: cpcap-battery: Save high and low states Date: Sun, 19 Jan 2020 12:11:23 -0800 Message-Id: <20200119201124.29620-2-tony@atomide.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200119201124.29620-1-tony@atomide.com> References: <20200119201124.29620-1-tony@atomide.com> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org If we save the battery high and low states, we can use those to estimate the battery capacity in the following patch. Note that this too should probably use ocv-capacity-table as AFAIK that has already similar data structures needed. Cc: Merlijn Wajer Cc: Pavel Machek Not-yet-Signed-off-by: Tony Lindgren --- drivers/power/supply/cpcap-battery.c | 38 +++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -110,6 +110,8 @@ struct cpcap_coulomb_counter_data { enum cpcap_battery_state { CPCAP_BATTERY_STATE_PREVIOUS, CPCAP_BATTERY_STATE_LATEST, + CPCAP_BATTERY_STATE_LOW, + CPCAP_BATTERY_STATE_HIGH, CPCAP_BATTERY_STATE_NR, }; @@ -183,6 +185,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_lowest(struct cpcap_battery_ddata *ddata) +{ + return cpcap_battery_get_state(ddata, CPCAP_BATTERY_STATE_LOW); +} + +static struct cpcap_battery_state_data * +cpcap_battery_get_highest(struct cpcap_battery_ddata *ddata) +{ + return cpcap_battery_get_state(ddata, CPCAP_BATTERY_STATE_HIGH); +} + static int cpcap_charger_battery_temperature(struct cpcap_battery_ddata *ddata, int *value) { @@ -400,9 +414,19 @@ static bool cpcap_battery_full(struct cpcap_battery_ddata *ddata) return false; } +static bool cpcap_battery_low(struct cpcap_battery_ddata *ddata) +{ + struct cpcap_battery_state_data *state = cpcap_battery_latest(ddata); + + if (state->current_ua && state->voltage <= 3300000) + return true; + + return false; +} + 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, *tmp; ktime_t now; int error; @@ -431,6 +455,18 @@ 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)) { + tmp = cpcap_battery_get_highest(ddata); + /* Update highest charge seen? */ + if (latest->counter_uah <= tmp->counter_uah) + memcpy(tmp, latest, sizeof(*tmp)); + } else if (cpcap_battery_low(ddata)) { + tmp = cpcap_battery_get_lowest(ddata); + /* Update lowest charge seen? */ + if (latest->counter_uah >= tmp->counter_uah) + memcpy(tmp, latest, sizeof(*tmp)); + } + return 0; } From patchwork Sun Jan 19 20:11:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 11340747 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C71DC109A for ; Sun, 19 Jan 2020 20:11:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B05552073A for ; Sun, 19 Jan 2020 20:11:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728733AbgASULg (ORCPT ); Sun, 19 Jan 2020 15:11:36 -0500 Received: from muru.com ([72.249.23.125]:51796 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727138AbgASULf (ORCPT ); Sun, 19 Jan 2020 15:11:35 -0500 Received: from hillo.muru.com (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id CB9FF8132; Sun, 19 Jan 2020 20:12:17 +0000 (UTC) From: Tony Lindgren To: Sebastian Reichel Cc: linux-pm@vger.kernel.org, linux-omap@vger.kernel.org, Merlijn Wajer , Pavel Machek Subject: [PATCH 3/3] RFC: power: supply: cpcap-battery: Implement capacity percentage Date: Sun, 19 Jan 2020 12:11:24 -0800 Message-Id: <20200119201124.29620-3-tony@atomide.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200119201124.29620-1-tony@atomide.com> References: <20200119201124.29620-1-tony@atomide.com> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Based on the saved high and low states, we can estimate battery state based on the coulomb counter: # cat /sys/class/power_supply/battery/capacity ... Note that this too should probably be updated to use ocv-capacity-table. Also note that I have not verified the shown capacity is very accurate. Cc: Merlijn Wajer Cc: Pavel Machek Not-yet-Signed-off-by: Tony Lindgren --- drivers/power/supply/cpcap-battery.c | 35 ++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -504,6 +504,15 @@ static int cpcap_battery_get_rough_capacity(struct cpcap_battery_ddata *ddata) return capacity; } +static int cpcap_battery_get_rough_percentage(struct cpcap_battery_ddata *ddata) +{ + int percentage = 0; + + cpcap_battery_get_rough(ddata, NULL, &percentage); + + return percentage; +} + static enum power_supply_property cpcap_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, @@ -518,6 +527,7 @@ static enum power_supply_property cpcap_battery_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_POWER_NOW, POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_TEMP, @@ -528,10 +538,10 @@ static int cpcap_battery_get_property(struct power_supply *psy, union power_supply_propval *val) { struct cpcap_battery_ddata *ddata = power_supply_get_drvdata(psy); - struct cpcap_battery_state_data *latest, *previous; + struct cpcap_battery_state_data *latest, *previous, *low, *high; u32 sample; s32 accumulator; - int cached; + int cached, delta, est; s64 tmp; cached = cpcap_battery_update_status(ddata); @@ -608,6 +618,27 @@ static int cpcap_battery_get_property(struct power_supply *psy, tmp *= ((latest->voltage + previous->voltage) / 20000); val->intval = div64_s64(tmp, 100); break; + case POWER_SUPPLY_PROP_CAPACITY: + est = cpcap_battery_get_rough_percentage(ddata); + high = cpcap_battery_get_highest(ddata); + if (high->voltage) { + delta = latest->counter_uah - high->counter_uah; + val->intval = (ddata->config.info.charge_full_design - + delta) * 100; + val->intval /= ddata->config.info.charge_full_design; + delta = abs(val->intval - est); + break; + } + low = cpcap_battery_get_lowest(ddata); + if (low->voltage) { + delta = low->counter_uah - latest->counter_uah; + val->intval = (delta * 100) / + ddata->config.info.charge_full_design; + delta = abs(val->intval - est); + break; + } + val->intval = est; + break; case POWER_SUPPLY_PROP_CAPACITY_LEVEL: val->intval = cpcap_battery_get_rough_capacity(ddata); break;