Hi, On Tue, Nov 23, 2021 at 12:41:40AM +0100, Linus Walleij wrote: > Several batteries monitor the temperature of the battery using > an NTC resistor. Add an NTC resistor resistance to temperature > look-up table to struct power_supply_battery_info and use this > in the AB8500 battery temperature driver to look up the battery > temperature. > > Add a helper function in the power supply core: > power_supply_ntc_resist2temp_simple(), which can use the > NTC resistance table to look up and interpolate a temperature > from the table. > > Fix up some of the confusing wording on the temperature to > internal resistance table, and clarify what each resistance > table is for. > > The AB8500 default NTC resistor is 47KOhm at 25 degrees > Celsius and serves as a good example of how this usually works. > > Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> > --- This LGTM, but let's wait a bit to synchronize with the work happening in the AXP driver. -- Sebastian > drivers/power/supply/ab8500-bm.h | 16 -------- > drivers/power/supply/ab8500_bmdata.c | 41 ++++++++++--------- > drivers/power/supply/ab8500_btemp.c | 45 ++------------------ > drivers/power/supply/power_supply_core.c | 52 ++++++++++++++++++++++++ > include/linux/power_supply.h | 34 ++++++++++++++++ > 5 files changed, 111 insertions(+), 77 deletions(-) > > diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h > index 57e1a8e27e51..90397f2a731f 100644 > --- a/drivers/power/supply/ab8500-bm.h > +++ b/drivers/power/supply/ab8500-bm.h > @@ -272,18 +272,6 @@ enum ab8500_adc_therm { > AB8500_ADC_THERM_BATTEMP, > }; > > -/** > - * struct ab8500_res_to_temp - defines one point in a temp to res curve. To > - * be used in battery packs that combines the identification resistor with a > - * NTC resistor. > - * @temp: battery pack temperature in Celsius > - * @resist: NTC resistor net total resistance > - */ > -struct ab8500_res_to_temp { > - int temp; > - int resist; > -}; > - > /* Forward declaration */ > struct ab8500_fg; > > @@ -363,8 +351,6 @@ struct ab8500_maxim_parameters { > * @maint_b_chg_timer_h: charge time in maintenance B state > * @low_high_cur_lvl: charger current in temp low/high state in mA > * @low_high_vol_lvl: charger voltage in temp low/high state in mV' > - * @n_r_t_tbl_elements: number of elements in r_to_t_tbl > - * @r_to_t_tbl: table containing resistance to temp points > */ > struct ab8500_battery_type { > int resis_high; > @@ -377,8 +363,6 @@ struct ab8500_battery_type { > int maint_b_chg_timer_h; > int low_high_cur_lvl; > int low_high_vol_lvl; > - int n_temp_tbl_elements; > - const struct ab8500_res_to_temp *r_to_t_tbl; > }; > > /** > diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c > index 62953f9cb85a..aba459393ee6 100644 > --- a/drivers/power/supply/ab8500_bmdata.c > +++ b/drivers/power/supply/ab8500_bmdata.c > @@ -44,25 +44,25 @@ static struct power_supply_battery_ocv_table ocv_cap_tbl[] = { > }; > > /* > - * Note that the res_to_temp table must be strictly sorted by falling > + * Note that the ntc_res_to_temp_tbl table must be strictly sorted by falling > * resistance values to work. > */ > -static const struct ab8500_res_to_temp temp_tbl[] = { > - {-5, 214834}, > - { 0, 162943}, > - { 5, 124820}, > - {10, 96520}, > - {15, 75306}, > - {20, 59254}, > - {25, 47000}, > - {30, 37566}, > - {35, 30245}, > - {40, 24520}, > - {45, 20010}, > - {50, 16432}, > - {55, 13576}, > - {60, 11280}, > - {65, 9425}, > +static struct power_supply_ntc_resistance_temp_table ntc_res_to_temp_tbl[] = { > + { .resistance_ohm = 214834, .temp = -5}, > + { .resistance_ohm = 162943, .temp = 0}, > + { .resistance_ohm = 124820, .temp = 5}, > + { .resistance_ohm = 96520, .temp = 10}, > + { .resistance_ohm = 75306, .temp = 15}, > + { .resistance_ohm = 59254, .temp = 20}, > + { .resistance_ohm = 47000, .temp = 25}, > + { .resistance_ohm = 37566, .temp = 30}, > + { .resistance_ohm = 30245, .temp = 35}, > + { .resistance_ohm = 24520, .temp = 40}, > + { .resistance_ohm = 20010, .temp = 45}, > + { .resistance_ohm = 16432, .temp = 50}, > + { .resistance_ohm = 13576, .temp = 55}, > + { .resistance_ohm = 11280, .temp = 60}, > + { .resistance_ohm = 9425, .temp = 65}, > }; > > /* > @@ -92,8 +92,6 @@ static struct ab8500_battery_type bat_type_thermistor_unknown = { > .maint_b_chg_timer_h = 200, > .low_high_cur_lvl = 300, > .low_high_vol_lvl = 4000, > - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl), > - .r_to_t_tbl = temp_tbl, > }; > > static const struct ab8500_bm_capacity_levels cap_levels = { > @@ -217,6 +215,11 @@ int ab8500_bm_of_probe(struct power_supply *psy, > bi->resist_table_size = ARRAY_SIZE(temp_to_batres_tbl_thermistor); > } > > + if (!bi->ntc_resist_table) { > + bi->ntc_resist_table = ntc_res_to_temp_tbl; > + bi->ntc_resist_table_size = ARRAY_SIZE(ntc_res_to_temp_tbl); > + } > + > if (!bi->ocv_table[0]) { > /* Default capacity table at say 25 degrees Celsius */ > bi->ocv_temp[0] = 25; > diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c > index 20253b8a7fe9..79528c18618d 100644 > --- a/drivers/power/supply/ab8500_btemp.c > +++ b/drivers/power/supply/ab8500_btemp.c > @@ -407,42 +407,6 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di) > return res; > } > > -/** > - * ab8500_btemp_res_to_temp() - resistance to temperature > - * @di: pointer to the ab8500_btemp structure > - * @tbl: pointer to the resiatance to temperature table > - * @tbl_size: size of the resistance to temperature table > - * @res: resistance to calculate the temperature from > - * > - * This function returns the battery temperature in degrees Celsius > - * based on the NTC resistance. > - */ > -static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di, > - const struct ab8500_res_to_temp *tbl, int tbl_size, int res) > -{ > - int i; > - /* > - * Calculate the formula for the straight line > - * Simple interpolation if we are within > - * the resistance table limits, extrapolate > - * if resistance is outside the limits. > - */ > - if (res > tbl[0].resist) > - i = 0; > - else if (res <= tbl[tbl_size - 1].resist) > - i = tbl_size - 2; > - else { > - i = 0; > - while (!(res <= tbl[i].resist && > - res > tbl[i + 1].resist)) > - i++; > - } > - > - return fixp_linear_interpolate(tbl[i].resist, tbl[i].temp, > - tbl[i + 1].resist, tbl[i + 1].temp, > - res); > -} > - > /** > * ab8500_btemp_measure_temp() - measure battery temperature > * @di: pointer to the ab8500_btemp structure > @@ -451,6 +415,7 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di, > */ > static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) > { > + struct power_supply_battery_info *bi = &di->bm->bi; > int temp, ret; > static int prev; > int rbat, rntc, vntc; > @@ -469,9 +434,7 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) > return BTEMP_THERMAL_LOW_LIMIT; > } > > - temp = ab8500_btemp_res_to_temp(di, > - di->bm->bat_type->r_to_t_tbl, > - di->bm->bat_type->n_temp_tbl_elements, rbat); > + temp = power_supply_ntc_resist2temp_simple(bi, rbat); > } else { > ret = iio_read_channel_processed(di->btemp_ball, &vntc); > if (ret < 0) { > @@ -486,9 +449,7 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) > */ > rntc = 230000 * vntc / (VTVOUT_V - vntc); > > - temp = ab8500_btemp_res_to_temp(di, > - di->bm->bat_type->r_to_t_tbl, > - di->bm->bat_type->n_temp_tbl_elements, rntc); > + temp = power_supply_ntc_resist2temp_simple(bi, rntc); > prev = temp; > } > dev_dbg(di->dev, "Battery temperature is %d\n", temp); > diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c > index 2723d7d0ced3..a870c3fe032c 100644 > --- a/drivers/power/supply/power_supply_core.c > +++ b/drivers/power/supply/power_supply_core.c > @@ -589,6 +589,7 @@ int power_supply_get_battery_info(struct power_supply *psy, > info->temp_max = INT_MAX; > info->factory_internal_resistance_uohm = -EINVAL; > info->resist_table = NULL; > + info->ntc_resist_table = NULL; > > for (index = 0; index < POWER_SUPPLY_OCV_TEMP_MAX; index++) { > info->ocv_table[index] = NULL; > @@ -806,6 +807,57 @@ int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *t > } > EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple); > > +/** > + * power_supply_ntc_resist2temp_simple() - find the battery temperature > + * @info: battery information > + * @resistance_ohm: Current NTC resistance value in microohm > + * > + * This helper function is used to look up battery internal temperature > + * according to current NTC resistance value from one NTC resistance table. > + * The NTC resistance table must be ordered descending by resistance: > + * largest resistance with lowest temperature first, lowest resistance with > + * highest temperature last. The function will interpolate to find the > + * corresponding temperature. > + * > + * Return: the battery temperature. > + */ > +int power_supply_ntc_resist2temp_simple(struct power_supply_battery_info *info, > + int resistance_ohm) > +{ > + struct power_supply_ntc_resistance_temp_table *table; > + int i, high, low; > + int table_len; > + > + table = info->ntc_resist_table; > + table_len = info->ntc_resist_table_size; > + > + if (!table || !table_len) { > + pr_err("Empty battery NTC resistance table, assume 25 degrees\n"); > + return 25; > + } > + if (!resistance_ohm) > + pr_info("Battery NTC resistance 0, this is unlikely\n"); > + > + /* Break loop at table_len - 1 because that is the highest index */ > + for (i = 0; i < table_len - 1; i++) > + if (resistance_ohm > table[i].resistance_ohm) > + 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(table[low].resistance_ohm, > + table[low].temp, > + table[high].resistance_ohm, > + table[high].temp, > + resistance_ohm); > +} > +EXPORT_SYMBOL_GPL(power_supply_ntc_resist2temp_simple); > + > /** > * power_supply_ocv2cap_simple() - find the battery capacity > * @table: Pointer to battery OCV lookup table > diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h > index b5079109ac00..a0da806185b5 100644 > --- a/include/linux/power_supply.h > +++ b/include/linux/power_supply.h > @@ -335,11 +335,29 @@ struct power_supply_battery_ocv_table { > int capacity; /* percent */ > }; > > +/** > + * struct power_supply_resistance_temp_table - correlate temperature to resistance > + * @temp: the internal temperature of the battery in degrees Celsius > + * @resistance: the percentage of the factory internal resistance at this > + * temperature, usually nomimal factory resistance is 100 percent at 25 > + * degrees Celsius, lower at higher temperature and higher at lower > + * temperature. > + */ > struct power_supply_resistance_temp_table { > int temp; /* celsius */ > int resistance; /* internal resistance percent */ > }; > > +/** > + * struct power_supply_ntc_resistance_temp_table - correlate NTC to temp > + * @resistance: the NTC resistance in ohm > + * @temp: the corresponding temperature in degrees Celsius > + */ > +struct power_supply_ntc_resistance_temp_table { > + int resistance_ohm; > + int temp; > +}; > + > #define POWER_SUPPLY_OCV_TEMP_MAX 20 > > /** > @@ -426,6 +444,18 @@ struct power_supply_resistance_temp_table { > * by temperature: highest temperature with lowest resistance first, lowest > * temperature with highest resistance last. > * @resist_table_size: the number of items in the resist_table. > + * @ntc_resist_table: this is a table that correlates a resistance of a negative > + * temperature coefficient (NTC) resistor to an internal temperature of a > + * battery. This can be achieved by a separate thermistor to > + * supply voltage on a third terminal on a battery which is the most > + * reliable. An external thermistor can also be used sometimes. Knowing the > + * temperature of the battery is usually necessary to perform a lookup in the > + * resist_table to determine the internal resistance of the battery, and > + * to find the right ocv_table to determine the capacity of the battery. > + * The NTC resistance table must be ordered descending by resistance: > + * largest resistance with lowest temperature first, lowest resistance with > + * highest temperature last. > + * @ntc_resist_table_size: the number of items in the ntc_resist_table. > * > * This is the recommended struct to manage static battery parameters, > * populated by power_supply_get_battery_info(). Most platform drivers should > @@ -546,6 +576,8 @@ struct power_supply_battery_info { > int ocv_table_size[POWER_SUPPLY_OCV_TEMP_MAX]; > struct power_supply_resistance_temp_table *resist_table; > int resist_table_size; > + struct power_supply_ntc_resistance_temp_table *ntc_resist_table; > + int ntc_resist_table_size; > }; > > extern struct atomic_notifier_head power_supply_notifier; > @@ -587,6 +619,8 @@ extern int power_supply_batinfo_ocv2cap(struct power_supply_battery_info *info, > extern int > power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *table, > int table_len, int temp); > +extern int power_supply_ntc_resist2temp_simple(struct power_supply_battery_info *info, > + int resistance_ohm); > extern void power_supply_changed(struct power_supply *psy); > extern int power_supply_am_i_supplied(struct power_supply *psy); > extern int power_supply_set_input_current_limit_from_supplier( > -- > 2.31.1 >
Attachment:
signature.asc
Description: PGP signature