| // SPDX-License-Identifier: GPL-2.0 |
| #include <linux/export.h> |
| #include <linux/power_supply.h> |
| #include <linux/of.h> |
| |
| #include "ab8500-bm.h" |
| |
| /* |
| * 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, |
| }; |
| |
| /* |
| * This array maps the raw hex value to charger output current used by the |
| * AB8500 values |
| */ |
| static int ab8500_charge_output_curr_map[] = { |
| 100, 200, 300, 400, 500, 600, 700, 800, |
| 900, 1000, 1100, 1200, 1300, 1400, 1500, 1500, |
| }; |
| |
| /* |
| * This array maps the raw hex value to charger input current used by the |
| * AB8500 values |
| */ |
| static int ab8500_charge_input_curr_map[] = { |
| 50, 98, 193, 290, 380, 450, 500, 600, |
| 700, 800, 900, 1000, 1100, 1300, 1400, 1500, |
| }; |
| |
| struct ab8500_bm_data ab8500_bm_data = { |
| .temp_under = 3, |
| .temp_low = 8, |
| .temp_high = 43, |
| .temp_over = 48, |
| .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, |
| .temp_hysteresis = 3, |
| .gnd_lift_resistance = 34, |
| .chg_output_curr = ab8500_charge_output_curr_map, |
| .n_chg_out_curr = ARRAY_SIZE(ab8500_charge_output_curr_map), |
| .maxi = &ab8500_maxi_params, |
| .chg_params = &chg, |
| .fg_params = &fg, |
| .chg_input_curr = ab8500_charge_input_curr_map, |
| .n_chg_in_curr = ARRAY_SIZE(ab8500_charge_input_curr_map), |
| }; |
| |
| int ab8500_bm_of_probe(struct device *dev, |
| struct device_node *np, |
| struct ab8500_bm_data *bm) |
| { |
| const struct batres_vs_temp *tmp_batres_tbl; |
| struct device_node *battery_node; |
| const char *btech; |
| int i; |
| |
| battery_node = of_parse_phandle(np, "monitored-battery", 0); |
| if (!battery_node) { |
| dev_err(dev, "battery node or reference missing\n"); |
| return -EINVAL; |
| } |
| |
| btech = of_get_property(battery_node, "stericsson,battery-type", NULL); |
| if (!btech) { |
| dev_warn(dev, "missing property battery-name/type\n"); |
| of_node_put(battery_node); |
| return -EINVAL; |
| } |
| |
| if (strncmp(btech, "LION", 4) == 0) { |
| 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(battery_node, "thermistor-on-batctrl")) { |
| if (strncmp(btech, "LION", 4) == 0) |
| 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; |
| |
| of_node_put(battery_node); |
| |
| return 0; |
| } |