The battery info functions computing the state-of-charge (SOC) based on open-circuit-voltage (OCV) are returning SOC using units of 1%. Some capacity estimation computations require higher accuracy. Add functions that return SOC using units of 0.1% to reduce rounding error. Signed-off-by: Matti Vaittinen --- RFCv3 changes: - Kerneldoc fixes --- drivers/power/supply/power_supply_core.c | 65 ++++++++++++++++++++++++ include/linux/power_supply.h | 4 ++ 2 files changed, 69 insertions(+) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index ebc961b5aa45..62ea113db3b4 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -1003,6 +1003,45 @@ int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table, } EXPORT_SYMBOL_GPL(power_supply_ocv2cap_simple); +/** + * power_supply_ocv2dcap_simple() - find the battery capacity at 0.1% accuracy + * @table: Pointer to battery OCV lookup table + * @table_len: OCV table length + * @ocv: Current OCV value + * + * This helper function is used to look up battery capacity according to + * current OCV value from one OCV table, and the OCV table must be ordered + * descending. Return the SOC in the units of 0.1% for improved accuracy. + * + * Return: the battery capacity using the unit 0.1%. + */ +int power_supply_ocv2dcap_simple(struct power_supply_battery_ocv_table *table, + int table_len, int ocv) +{ + int i, cap, tmp; + + for (i = 0; i < table_len; i++) + if (ocv > table[i].ocv) + break; + + if (i > 0 && i < table_len) { + tmp = (table[i - 1].capacity - table[i].capacity) * + (ocv - table[i].ocv) * 10; + tmp /= table[i - 1].ocv - table[i].ocv; + cap = tmp + table[i].capacity * 10; + } else if (i == 0) { + cap = table[0].capacity * 10; + } else { + cap = table[table_len - 1].capacity * 10; + } + + if (cap < 0) + cap = 0; + + return cap; +} +EXPORT_SYMBOL_GPL(power_supply_ocv2dcap_simple); + struct power_supply_battery_ocv_table * power_supply_find_ocv2cap_table(struct power_supply_battery_info *info, int temp, int *table_len) @@ -1054,6 +1093,32 @@ int power_supply_batinfo_dcap2ocv(struct power_supply_battery_info *info, } EXPORT_SYMBOL_GPL(power_supply_batinfo_dcap2ocv); +/** + * power_supply_batinfo_ocv2dcap - compute SOC based on OCV and temperature + * @info: pointer to battery information + * @ocv: Open circuit voltage in uV + * @temp: Temperature in Celsius + * + * Use OCV tables in battery info to compute the battery capacity based on + * provided open circuit voltage at given and temperature. + * + * Return: battery capacity correspondinggiven OCV and temperature at 0.1%. + * -EINVAL if OCV table is not present. + */ +int power_supply_batinfo_ocv2dcap(struct power_supply_battery_info *info, + int ocv, int temp) +{ + struct power_supply_battery_ocv_table *table; + int table_len; + + table = power_supply_find_ocv2cap_table(info, temp, &table_len); + if (!table) + return -EINVAL; + + return power_supply_ocv2dcap_simple(table, table_len, ocv); +} +EXPORT_SYMBOL_GPL(power_supply_batinfo_ocv2dcap); + int power_supply_batinfo_ocv2cap(struct power_supply_battery_info *info, int ocv, int temp) { diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index c5118265b3ab..5e6575e97492 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -444,6 +444,10 @@ extern int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *ta int table_len, int ocv); int power_supply_dcap2ocv_simple(struct power_supply_battery_ocv_table *table, int table_len, int dcap); +int power_supply_ocv2dcap_simple(struct power_supply_battery_ocv_table *table, + int table_len, int ocv); +int power_supply_batinfo_ocv2dcap(struct power_supply_battery_info *info, + int ocv, int temp); extern struct power_supply_battery_ocv_table * power_supply_find_ocv2cap_table(struct power_supply_battery_info *info, -- 2.31.1 -- Matti Vaittinen, Linux device drivers ROHM Semiconductors, Finland SWDC Kiviharjunlenkki 1E 90220 OULU FINLAND ~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~ Simon says - in Latin please. ~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~ Thanks to Simon Glass for the translation =]