diff options
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) |