Instead of storing the temperature limits in our custom struct struct ab8500_bm_data, make struct power_supply_battery_info a member of this and store the min and max temperatures inside that struct as the temp_min/temp_max and temp_alert_min/temp_alert_max respectively. The values can be assigned from the device tree, but if not present will be set to the same defaults as are currently in the code. This way we start to move over to using struct power_supply_battery_info and make it possible to move the data over to the device tree and we will move piece by piece toward using the standard info struct. Temperature hysteresis is currently not supported by the standard struct but we move the assignment here as well so that we have all parameterization in one spot. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
535 lines
13 KiB
C
535 lines
13 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <linux/export.h>
|
|
#include <linux/power_supply.h>
|
|
#include <linux/of.h>
|
|
|
|
#include "ab8500-bm.h"
|
|
|
|
/* Default: under this temperature, charging is stopped */
|
|
#define AB8500_TEMP_UNDER 3
|
|
/* Default: between this temp and AB8500_TEMP_UNDER charging is reduced */
|
|
#define AB8500_TEMP_LOW 8
|
|
/* Default: between this temp and AB8500_TEMP_OVER charging is reduced */
|
|
#define AB8500_TEMP_HIGH 43
|
|
/* Default: over this temp, charging is stopped */
|
|
#define AB8500_TEMP_OVER 48
|
|
/* Default: temperature hysteresis */
|
|
#define AB8500_TEMP_HYSTERESIS 3
|
|
|
|
/*
|
|
* These are the defined batteries that uses a NTC and ID resistor placed
|
|
* inside of the battery pack.
|
|
* Note that the res_to_temp table must be strictly sorted by falling resistance
|
|
* values to work.
|
|
*/
|
|
const struct ab8500_res_to_temp ab8500_temp_tbl_a_thermistor[] = {
|
|
{-5, 53407},
|
|
{ 0, 48594},
|
|
{ 5, 43804},
|
|
{10, 39188},
|
|
{15, 34870},
|
|
{20, 30933},
|
|
{25, 27422},
|
|
{30, 24347},
|
|
{35, 21694},
|
|
{40, 19431},
|
|
{45, 17517},
|
|
{50, 15908},
|
|
{55, 14561},
|
|
{60, 13437},
|
|
{65, 12500},
|
|
};
|
|
EXPORT_SYMBOL(ab8500_temp_tbl_a_thermistor);
|
|
|
|
const int ab8500_temp_tbl_a_size = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor);
|
|
EXPORT_SYMBOL(ab8500_temp_tbl_a_size);
|
|
|
|
const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = {
|
|
{-5, 200000},
|
|
{ 0, 159024},
|
|
{ 5, 151921},
|
|
{10, 144300},
|
|
{15, 136424},
|
|
{20, 128565},
|
|
{25, 120978},
|
|
{30, 113875},
|
|
{35, 107397},
|
|
{40, 101629},
|
|
{45, 96592},
|
|
{50, 92253},
|
|
{55, 88569},
|
|
{60, 85461},
|
|
{65, 82869},
|
|
};
|
|
EXPORT_SYMBOL(ab8500_temp_tbl_b_thermistor);
|
|
|
|
const int ab8500_temp_tbl_b_size = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor);
|
|
EXPORT_SYMBOL(ab8500_temp_tbl_b_size);
|
|
|
|
static const struct ab8500_v_to_cap cap_tbl_a_thermistor[] = {
|
|
{4171, 100},
|
|
{4114, 95},
|
|
{4009, 83},
|
|
{3947, 74},
|
|
{3907, 67},
|
|
{3863, 59},
|
|
{3830, 56},
|
|
{3813, 53},
|
|
{3791, 46},
|
|
{3771, 33},
|
|
{3754, 25},
|
|
{3735, 20},
|
|
{3717, 17},
|
|
{3681, 13},
|
|
{3664, 8},
|
|
{3651, 6},
|
|
{3635, 5},
|
|
{3560, 3},
|
|
{3408, 1},
|
|
{3247, 0},
|
|
};
|
|
|
|
static const struct ab8500_v_to_cap cap_tbl_b_thermistor[] = {
|
|
{4161, 100},
|
|
{4124, 98},
|
|
{4044, 90},
|
|
{4003, 85},
|
|
{3966, 80},
|
|
{3933, 75},
|
|
{3888, 67},
|
|
{3849, 60},
|
|
{3813, 55},
|
|
{3787, 47},
|
|
{3772, 30},
|
|
{3751, 25},
|
|
{3718, 20},
|
|
{3681, 16},
|
|
{3660, 14},
|
|
{3589, 10},
|
|
{3546, 7},
|
|
{3495, 4},
|
|
{3404, 2},
|
|
{3250, 0},
|
|
};
|
|
|
|
static const struct ab8500_v_to_cap cap_tbl[] = {
|
|
{4186, 100},
|
|
{4163, 99},
|
|
{4114, 95},
|
|
{4068, 90},
|
|
{3990, 80},
|
|
{3926, 70},
|
|
{3898, 65},
|
|
{3866, 60},
|
|
{3833, 55},
|
|
{3812, 50},
|
|
{3787, 40},
|
|
{3768, 30},
|
|
{3747, 25},
|
|
{3730, 20},
|
|
{3705, 15},
|
|
{3699, 14},
|
|
{3684, 12},
|
|
{3672, 9},
|
|
{3657, 7},
|
|
{3638, 6},
|
|
{3556, 4},
|
|
{3424, 2},
|
|
{3317, 1},
|
|
{3094, 0},
|
|
};
|
|
|
|
/*
|
|
* Note that the res_to_temp 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},
|
|
};
|
|
|
|
/*
|
|
* Note that the batres_vs_temp table must be strictly sorted by falling
|
|
* temperature values to work.
|
|
*/
|
|
static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
|
|
{ 40, 120},
|
|
{ 30, 135},
|
|
{ 20, 165},
|
|
{ 10, 230},
|
|
{ 00, 325},
|
|
{-10, 445},
|
|
{-20, 595},
|
|
};
|
|
|
|
/*
|
|
* Note that the batres_vs_temp table must be strictly sorted by falling
|
|
* temperature values to work.
|
|
*/
|
|
static const struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
|
|
{ 60, 300},
|
|
{ 30, 300},
|
|
{ 20, 300},
|
|
{ 10, 300},
|
|
{ 00, 300},
|
|
{-10, 300},
|
|
{-20, 300},
|
|
};
|
|
|
|
/* battery resistance table for LI ION 9100 battery */
|
|
static const struct batres_vs_temp temp_to_batres_tbl_9100[] = {
|
|
{ 60, 180},
|
|
{ 30, 180},
|
|
{ 20, 180},
|
|
{ 10, 180},
|
|
{ 00, 180},
|
|
{-10, 180},
|
|
{-20, 180},
|
|
};
|
|
|
|
static struct ab8500_battery_type bat_type_thermistor[] = {
|
|
[BATTERY_UNKNOWN] = {
|
|
/* First element always represent the UNKNOWN battery */
|
|
.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
|
|
.resis_high = 0,
|
|
.resis_low = 0,
|
|
.battery_resistance = 300,
|
|
.charge_full_design = 612,
|
|
.nominal_voltage = 3700,
|
|
.termination_vol = 4050,
|
|
.termination_curr = 200,
|
|
.recharge_cap = 95,
|
|
.normal_cur_lvl = 400,
|
|
.normal_vol_lvl = 4100,
|
|
.maint_a_cur_lvl = 400,
|
|
.maint_a_vol_lvl = 4050,
|
|
.maint_a_chg_timer_h = 60,
|
|
.maint_b_cur_lvl = 400,
|
|
.maint_b_vol_lvl = 4000,
|
|
.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,
|
|
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
|
.v_to_cap_tbl = cap_tbl,
|
|
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
|
.batres_tbl = temp_to_batres_tbl_thermistor,
|
|
},
|
|
{
|
|
.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
|
|
.resis_high = 53407,
|
|
.resis_low = 12500,
|
|
.battery_resistance = 300,
|
|
.charge_full_design = 900,
|
|
.nominal_voltage = 3600,
|
|
.termination_vol = 4150,
|
|
.termination_curr = 80,
|
|
.recharge_cap = 95,
|
|
.normal_cur_lvl = 700,
|
|
.normal_vol_lvl = 4200,
|
|
.maint_a_cur_lvl = 600,
|
|
.maint_a_vol_lvl = 4150,
|
|
.maint_a_chg_timer_h = 60,
|
|
.maint_b_cur_lvl = 600,
|
|
.maint_b_vol_lvl = 4100,
|
|
.maint_b_chg_timer_h = 200,
|
|
.low_high_cur_lvl = 300,
|
|
.low_high_vol_lvl = 4000,
|
|
.n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor),
|
|
.r_to_t_tbl = ab8500_temp_tbl_a_thermistor,
|
|
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_a_thermistor),
|
|
.v_to_cap_tbl = cap_tbl_a_thermistor,
|
|
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
|
.batres_tbl = temp_to_batres_tbl_thermistor,
|
|
|
|
},
|
|
{
|
|
.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
|
|
.resis_high = 200000,
|
|
.resis_low = 82869,
|
|
.battery_resistance = 300,
|
|
.charge_full_design = 900,
|
|
.nominal_voltage = 3600,
|
|
.termination_vol = 4150,
|
|
.termination_curr = 80,
|
|
.recharge_cap = 95,
|
|
.normal_cur_lvl = 700,
|
|
.normal_vol_lvl = 4200,
|
|
.maint_a_cur_lvl = 600,
|
|
.maint_a_vol_lvl = 4150,
|
|
.maint_a_chg_timer_h = 60,
|
|
.maint_b_cur_lvl = 600,
|
|
.maint_b_vol_lvl = 4100,
|
|
.maint_b_chg_timer_h = 200,
|
|
.low_high_cur_lvl = 300,
|
|
.low_high_vol_lvl = 4000,
|
|
.n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor),
|
|
.r_to_t_tbl = ab8500_temp_tbl_b_thermistor,
|
|
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_b_thermistor),
|
|
.v_to_cap_tbl = cap_tbl_b_thermistor,
|
|
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
|
.batres_tbl = temp_to_batres_tbl_thermistor,
|
|
},
|
|
};
|
|
|
|
static struct ab8500_battery_type bat_type_ext_thermistor[] = {
|
|
[BATTERY_UNKNOWN] = {
|
|
/* First element always represent the UNKNOWN battery */
|
|
.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
|
|
.resis_high = 0,
|
|
.resis_low = 0,
|
|
.battery_resistance = 300,
|
|
.charge_full_design = 612,
|
|
.nominal_voltage = 3700,
|
|
.termination_vol = 4050,
|
|
.termination_curr = 200,
|
|
.recharge_cap = 95,
|
|
.normal_cur_lvl = 400,
|
|
.normal_vol_lvl = 4100,
|
|
.maint_a_cur_lvl = 400,
|
|
.maint_a_vol_lvl = 4050,
|
|
.maint_a_chg_timer_h = 60,
|
|
.maint_b_cur_lvl = 400,
|
|
.maint_b_vol_lvl = 4000,
|
|
.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,
|
|
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
|
.v_to_cap_tbl = cap_tbl,
|
|
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
|
.batres_tbl = temp_to_batres_tbl_thermistor,
|
|
},
|
|
/*
|
|
* These are the batteries that doesn't have an internal NTC resistor to measure
|
|
* its temperature. The temperature in this case is measure with a NTC placed
|
|
* near the battery but on the PCB.
|
|
*/
|
|
{
|
|
.name = POWER_SUPPLY_TECHNOLOGY_LIPO,
|
|
.resis_high = 76000,
|
|
.resis_low = 53000,
|
|
.battery_resistance = 300,
|
|
.charge_full_design = 900,
|
|
.nominal_voltage = 3700,
|
|
.termination_vol = 4150,
|
|
.termination_curr = 100,
|
|
.recharge_cap = 95,
|
|
.normal_cur_lvl = 700,
|
|
.normal_vol_lvl = 4200,
|
|
.maint_a_cur_lvl = 600,
|
|
.maint_a_vol_lvl = 4150,
|
|
.maint_a_chg_timer_h = 60,
|
|
.maint_b_cur_lvl = 600,
|
|
.maint_b_vol_lvl = 4100,
|
|
.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,
|
|
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
|
.v_to_cap_tbl = cap_tbl,
|
|
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
|
.batres_tbl = temp_to_batres_tbl_thermistor,
|
|
},
|
|
{
|
|
.name = POWER_SUPPLY_TECHNOLOGY_LION,
|
|
.resis_high = 30000,
|
|
.resis_low = 10000,
|
|
.battery_resistance = 300,
|
|
.charge_full_design = 950,
|
|
.nominal_voltage = 3700,
|
|
.termination_vol = 4150,
|
|
.termination_curr = 100,
|
|
.recharge_cap = 95,
|
|
.normal_cur_lvl = 700,
|
|
.normal_vol_lvl = 4200,
|
|
.maint_a_cur_lvl = 600,
|
|
.maint_a_vol_lvl = 4150,
|
|
.maint_a_chg_timer_h = 60,
|
|
.maint_b_cur_lvl = 600,
|
|
.maint_b_vol_lvl = 4100,
|
|
.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,
|
|
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
|
.v_to_cap_tbl = cap_tbl,
|
|
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
|
.batres_tbl = temp_to_batres_tbl_thermistor,
|
|
},
|
|
{
|
|
.name = POWER_SUPPLY_TECHNOLOGY_LION,
|
|
.resis_high = 95000,
|
|
.resis_low = 76001,
|
|
.battery_resistance = 300,
|
|
.charge_full_design = 950,
|
|
.nominal_voltage = 3700,
|
|
.termination_vol = 4150,
|
|
.termination_curr = 100,
|
|
.recharge_cap = 95,
|
|
.normal_cur_lvl = 700,
|
|
.normal_vol_lvl = 4200,
|
|
.maint_a_cur_lvl = 600,
|
|
.maint_a_vol_lvl = 4150,
|
|
.maint_a_chg_timer_h = 60,
|
|
.maint_b_cur_lvl = 600,
|
|
.maint_b_vol_lvl = 4100,
|
|
.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,
|
|
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl),
|
|
.v_to_cap_tbl = cap_tbl,
|
|
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
|
|
.batres_tbl = temp_to_batres_tbl_thermistor,
|
|
},
|
|
};
|
|
|
|
static const struct ab8500_bm_capacity_levels cap_levels = {
|
|
.critical = 2,
|
|
.low = 10,
|
|
.normal = 70,
|
|
.high = 95,
|
|
.full = 100,
|
|
};
|
|
|
|
static const struct ab8500_fg_parameters fg = {
|
|
.recovery_sleep_timer = 10,
|
|
.recovery_total_time = 100,
|
|
.init_timer = 1,
|
|
.init_discard_time = 5,
|
|
.init_total_time = 40,
|
|
.high_curr_time = 60,
|
|
.accu_charging = 30,
|
|
.accu_high_curr = 30,
|
|
.high_curr_threshold = 50,
|
|
.lowbat_threshold = 3100,
|
|
.battok_falling_th_sel0 = 2860,
|
|
.battok_raising_th_sel1 = 2860,
|
|
.maint_thres = 95,
|
|
.user_cap_limit = 15,
|
|
.pcut_enable = 1,
|
|
.pcut_max_time = 127,
|
|
.pcut_flag_time = 112,
|
|
.pcut_max_restart = 15,
|
|
.pcut_debounce_time = 2,
|
|
};
|
|
|
|
static const struct ab8500_maxim_parameters ab8500_maxi_params = {
|
|
.ena_maxi = true,
|
|
.chg_curr = 910,
|
|
.wait_cycles = 10,
|
|
.charger_curr_step = 100,
|
|
};
|
|
|
|
static const struct ab8500_bm_charger_parameters chg = {
|
|
.usb_volt_max = 5500,
|
|
.usb_curr_max = 1500,
|
|
.ac_volt_max = 7500,
|
|
.ac_curr_max = 1500,
|
|
};
|
|
|
|
struct ab8500_bm_data ab8500_bm_data = {
|
|
.main_safety_tmr_h = 4,
|
|
.temp_interval_chg = 20,
|
|
.temp_interval_nochg = 120,
|
|
.usb_safety_tmr_h = 4,
|
|
.bkup_bat_v = BUP_VCH_SEL_2P6V,
|
|
.bkup_bat_i = BUP_ICH_SEL_150UA,
|
|
.no_maintenance = false,
|
|
.capacity_scaling = false,
|
|
.adc_therm = AB8500_ADC_THERM_BATCTRL,
|
|
.chg_unknown_bat = false,
|
|
.enable_overshoot = false,
|
|
.fg_res = 100,
|
|
.cap_levels = &cap_levels,
|
|
.bat_type = bat_type_thermistor,
|
|
.n_btypes = ARRAY_SIZE(bat_type_thermistor),
|
|
.batt_id = 0,
|
|
.interval_charging = 5,
|
|
.interval_not_charging = 120,
|
|
.gnd_lift_resistance = 34,
|
|
.maxi = &ab8500_maxi_params,
|
|
.chg_params = &chg,
|
|
.fg_params = &fg,
|
|
};
|
|
|
|
int ab8500_bm_of_probe(struct power_supply *psy,
|
|
struct ab8500_bm_data *bm)
|
|
{
|
|
const struct batres_vs_temp *tmp_batres_tbl;
|
|
struct power_supply_battery_info *bi = &bm->bi;
|
|
struct device *dev = &psy->dev;
|
|
int ret;
|
|
int i;
|
|
|
|
ret = power_supply_get_battery_info(psy, bi);
|
|
if (ret) {
|
|
dev_err(dev, "cannot retrieve battery info\n");
|
|
return ret;
|
|
}
|
|
|
|
if (bi->temp_min == INT_MIN)
|
|
bi->temp_min = AB8500_TEMP_UNDER;
|
|
if (bi->temp_max == INT_MAX)
|
|
bi->temp_max = AB8500_TEMP_OVER;
|
|
if (bi->temp_alert_min == INT_MIN)
|
|
bi->temp_alert_min = AB8500_TEMP_LOW;
|
|
if (bi->temp_alert_max == INT_MAX)
|
|
bi->temp_alert_max = AB8500_TEMP_HIGH;
|
|
bm->temp_hysteresis = AB8500_TEMP_HYSTERESIS;
|
|
|
|
|
|
if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION) {
|
|
bm->no_maintenance = true;
|
|
bm->chg_unknown_bat = true;
|
|
bm->bat_type[BATTERY_UNKNOWN].charge_full_design = 2600;
|
|
bm->bat_type[BATTERY_UNKNOWN].termination_vol = 4150;
|
|
bm->bat_type[BATTERY_UNKNOWN].recharge_cap = 95;
|
|
bm->bat_type[BATTERY_UNKNOWN].normal_cur_lvl = 520;
|
|
bm->bat_type[BATTERY_UNKNOWN].normal_vol_lvl = 4200;
|
|
}
|
|
|
|
if (of_property_read_bool(psy->of_node, "thermistor-on-batctrl")) {
|
|
if (bi->technology == POWER_SUPPLY_TECHNOLOGY_LION)
|
|
tmp_batres_tbl = temp_to_batres_tbl_9100;
|
|
else
|
|
tmp_batres_tbl = temp_to_batres_tbl_thermistor;
|
|
} else {
|
|
bm->n_btypes = 4;
|
|
bm->bat_type = bat_type_ext_thermistor;
|
|
bm->adc_therm = AB8500_ADC_THERM_BATTEMP;
|
|
tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor;
|
|
}
|
|
|
|
/* select the battery resolution table */
|
|
for (i = 0; i < bm->n_btypes; ++i)
|
|
bm->bat_type[i].batres_tbl = tmp_batres_tbl;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ab8500_bm_of_remove(struct power_supply *psy,
|
|
struct ab8500_bm_data *bm)
|
|
{
|
|
power_supply_put_battery_info(psy, &bm->bi);
|
|
}
|