diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2022-02-26 00:27:58 +0100 |
---|---|---|
committer | Sebastian Reichel <sebastian.reichel@collabora.com> | 2022-02-28 11:34:32 +0100 |
commit | e9e7d165b4b0413c5b7db74515e4981a226b78a0 (patch) | |
tree | 4bb2a186091776db007d7d1d833bb52e3e7edf94 /drivers/power | |
parent | 1f918e0fe43ec41d906e2cf96b80b15451fed7ba (diff) |
power: supply: Support VBAT-to-Ri lookup tables
In Samsung devices, the method used to compensate for temperature,
age, load etc is by way of VBAT to Ri tables, which correlates the
battery voltage under load (VBAT) to an internal resistance (Ri).
Using this Ri and a measurement of the current out of the battery
(IBAT) the open circuit voltage (OCV) can be calculated as:
OCV = VBAT - (Ri * IBAT)
The details are described in comments to struct
power_supply_battery_info in the commit.
Since not all batteries supply this VBAT-to-Ri data, the fallback
method to use the temperature-to-Ri lookup table can also be used
as a fallback.
Add two helper functions to check if we have the tables needed for
using power_supply_vbat2ri() or power_supply_temp2resist_simple()
respectively, so capacity estimation code can choose which one
to employ.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/supply/power_supply_core.c | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 3d5047d3fe99..fb0b3870566e 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -814,7 +814,7 @@ EXPORT_SYMBOL_GPL(power_supply_put_battery_info); /** * power_supply_temp2resist_simple() - find the battery internal resistance - * percent + * percent from temperature * @table: Pointer to battery resistance temperature table * @table_len: The table length * @temp: Current temperature @@ -851,6 +851,71 @@ int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *t } EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple); +/** + * power_supply_vbat2ri() - find the battery internal resistance + * from the battery voltage + * @info: The battery information container + * @table: Pointer to battery resistance temperature table + * @vbat_uv: The battery voltage in microvolt + * @charging: If we are charging (true) or not (false) + * + * This helper function is used to look up battery internal resistance + * according to current battery voltage. Depending on whether the battery + * is currently charging or not, different resistance will be returned. + * + * Returns the internal resistance in microohm or negative error code. + */ +int power_supply_vbat2ri(struct power_supply_battery_info *info, + int vbat_uv, bool charging) +{ + struct power_supply_vbat_ri_table *vbat2ri; + int table_len; + int i, high, low; + + /* + * If we are charging, and the battery supplies a separate table + * for this state, we use that in order to compensate for the + * charging voltage. Otherwise we use the main table. + */ + if (charging && info->vbat2ri_charging) { + vbat2ri = info->vbat2ri_charging; + table_len = info->vbat2ri_charging_size; + } else { + vbat2ri = info->vbat2ri_discharging; + table_len = info->vbat2ri_discharging_size; + } + + /* + * If no tables are specified, or if we are above the highest voltage in + * the voltage table, just return the factory specified internal resistance. + */ + if (!vbat2ri || (table_len <= 0) || (vbat_uv > vbat2ri[0].vbat_uv)) { + if (charging && (info->factory_internal_resistance_charging_uohm > 0)) + return info->factory_internal_resistance_charging_uohm; + else + return info->factory_internal_resistance_uohm; + } + + /* Break loop at table_len - 1 because that is the highest index */ + for (i = 0; i < table_len - 1; i++) + if (vbat_uv > vbat2ri[i].vbat_uv) + break; + + /* The library function will deal with high == low */ + if ((i == 0) || (i == (table_len - 1))) + high = i; + else + high = i - 1; + low = i; + + return fixp_linear_interpolate(vbat2ri[low].vbat_uv, + vbat2ri[low].ri_uohm, + vbat2ri[high].vbat_uv, + vbat2ri[high].ri_uohm, + vbat_uv); +} +EXPORT_SYMBOL_GPL(power_supply_vbat2ri); + struct power_supply_maintenance_charge_table * power_supply_get_maintenance_charging_setting(struct power_supply_battery_info *info, int index) |