summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2022-02-26 02:27:58 +0300
committerSebastian Reichel <sebastian.reichel@collabora.com>2022-02-28 13:34:32 +0300
commite9e7d165b4b0413c5b7db74515e4981a226b78a0 (patch)
tree4bb2a186091776db007d7d1d833bb52e3e7edf94 /drivers/power
parent1f918e0fe43ec41d906e2cf96b80b15451fed7ba (diff)
downloadlinux-e9e7d165b4b0413c5b7db74515e4981a226b78a0.tar.xz
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.c67
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)