Lines Matching +full:resistance +full:- +full:temp +full:- +full:table

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) ST-Ericsson SA 2012
30 #include <linux/fixp-arith.h>
32 #include "ab8500-bm.h"
36 #define BTEMP_THERMAL_LOW_LIMIT -10
52 * struct ab8500_btemp_interrupts - ab8500 interrupts
78 * struct ab8500_btemp - ab8500 BTEMP device information
126 * ab8500_btemp_batctrl_volt_to_res() - convert batctrl voltage to resistance
131 * This function returns the battery resistance that is
140 if (is_ab8500_1p1_or_earlier(di->parent)) { in ab8500_btemp_batctrl_volt_to_res()
145 return (450000 * (v_batctrl)) / (1800 - v_batctrl); in ab8500_btemp_batctrl_volt_to_res()
148 if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) { in ab8500_btemp_batctrl_volt_to_res()
151 * source to calculate the resistance. in ab8500_btemp_batctrl_volt_to_res()
154 - di->bm->gnd_lift_resistance * inst_curr) in ab8500_btemp_batctrl_volt_to_res()
155 / di->curr_source; in ab8500_btemp_batctrl_volt_to_res()
161 rbs = (80000 * (v_batctrl)) / (1800 - v_batctrl); in ab8500_btemp_batctrl_volt_to_res()
168 * ab8500_btemp_read_batctrl_voltage() - measure batctrl voltage
178 ret = iio_read_channel_processed(di->bat_ctrl, &vbtemp); in ab8500_btemp_read_batctrl_voltage()
180 dev_err(di->dev, in ab8500_btemp_read_batctrl_voltage()
190 * ab8500_btemp_curr_source_enable() - enable/disable batctrl current source
206 if (is_ab8500_1p1_or_earlier(di->parent)) in ab8500_btemp_curr_source_enable()
210 if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && enable) { in ab8500_btemp_curr_source_enable()
212 if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA) in ab8500_btemp_curr_source_enable()
217 dev_dbg(di->dev, "Set BATCTRL %duA\n", di->curr_source); in ab8500_btemp_curr_source_enable()
219 ret = abx500_mask_and_set_register_interruptible(di->dev, in ab8500_btemp_curr_source_enable()
223 dev_err(di->dev, "%s failed setting cmp_force\n", in ab8500_btemp_curr_source_enable()
235 ret = abx500_set_register_interruptible(di->dev, in ab8500_btemp_curr_source_enable()
239 dev_err(di->dev, "%s failed enabling current source\n", in ab8500_btemp_curr_source_enable()
243 } else if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && !enable) { in ab8500_btemp_curr_source_enable()
244 dev_dbg(di->dev, "Disable BATCTRL curr source\n"); in ab8500_btemp_curr_source_enable()
248 di->dev, in ab8500_btemp_curr_source_enable()
254 dev_err(di->dev, "%s failed disabling current source\n", in ab8500_btemp_curr_source_enable()
259 /* Enable Pull-Up and comparator */ in ab8500_btemp_curr_source_enable()
260 ret = abx500_mask_and_set_register_interruptible(di->dev, in ab8500_btemp_curr_source_enable()
265 dev_err(di->dev, "%s failed enabling PU and comp\n", in ab8500_btemp_curr_source_enable()
278 ret = abx500_mask_and_set_register_interruptible(di->dev, in ab8500_btemp_curr_source_enable()
282 dev_err(di->dev, "%s failed disabling force comp\n", in ab8500_btemp_curr_source_enable()
295 ret = abx500_mask_and_set_register_interruptible(di->dev, in ab8500_btemp_curr_source_enable()
301 dev_err(di->dev, "%s failed disabling current source\n", in ab8500_btemp_curr_source_enable()
306 /* Enable Pull-Up and comparator */ in ab8500_btemp_curr_source_enable()
307 ret = abx500_mask_and_set_register_interruptible(di->dev, in ab8500_btemp_curr_source_enable()
312 dev_err(di->dev, "%s failed enabling PU and comp\n", in ab8500_btemp_curr_source_enable()
326 ret = abx500_mask_and_set_register_interruptible(di->dev, in ab8500_btemp_curr_source_enable()
330 dev_err(di->dev, "%s failed disabling force comp\n", in ab8500_btemp_curr_source_enable()
339 * ab8500_btemp_get_batctrl_res() - get battery resistance
342 * This function returns the battery pack identification resistance.
359 dev_err(di->dev, "%s curr source enabled failed\n", __func__); in ab8500_btemp_get_batctrl_res()
363 if (!di->fg) in ab8500_btemp_get_batctrl_res()
364 di->fg = ab8500_fg_get(); in ab8500_btemp_get_batctrl_res()
365 if (!di->fg) { in ab8500_btemp_get_batctrl_res()
366 dev_err(di->dev, "No fg found\n"); in ab8500_btemp_get_batctrl_res()
367 return -EINVAL; in ab8500_btemp_get_batctrl_res()
370 ret = ab8500_fg_inst_curr_start(di->fg); in ab8500_btemp_get_batctrl_res()
373 dev_err(di->dev, "Failed to start current measurement\n"); in ab8500_btemp_get_batctrl_res()
379 } while (!ab8500_fg_inst_curr_started(di->fg)); in ab8500_btemp_get_batctrl_res()
387 } while (!ab8500_fg_inst_curr_done(di->fg)); in ab8500_btemp_get_batctrl_res()
390 ret = ab8500_fg_inst_curr_finalize(di->fg, &inst_curr); in ab8500_btemp_get_batctrl_res()
392 dev_err(di->dev, "Failed to finalize current measurement\n"); in ab8500_btemp_get_batctrl_res()
400 dev_err(di->dev, "%s curr source disable failed\n", __func__); in ab8500_btemp_get_batctrl_res()
404 dev_dbg(di->dev, "%s batctrl: %d res: %d inst_curr: %d samples: %d\n", in ab8500_btemp_get_batctrl_res()
411 * ab8500_btemp_res_to_temp() - resistance to temperature
413 * @tbl: pointer to the resiatance to temperature table
414 * @tbl_size: size of the resistance to temperature table
415 * @res: resistance to calculate the temperature from
418 * based on the NTC resistance.
427 * the resistance table limits, extrapolate in ab8500_btemp_res_to_temp()
428 * if resistance is outside the limits. in ab8500_btemp_res_to_temp()
432 else if (res <= tbl[tbl_size - 1].resist) in ab8500_btemp_res_to_temp()
433 i = tbl_size - 2; in ab8500_btemp_res_to_temp()
441 return fixp_linear_interpolate(tbl[i].resist, tbl[i].temp, in ab8500_btemp_res_to_temp()
442 tbl[i + 1].resist, tbl[i + 1].temp, in ab8500_btemp_res_to_temp()
447 * ab8500_btemp_measure_temp() - measure battery temperature
454 int temp, ret; in ab8500_btemp_measure_temp() local
459 id = di->bm->batt_id; in ab8500_btemp_measure_temp()
461 if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && in ab8500_btemp_measure_temp()
466 dev_err(di->dev, "%s get batctrl res failed\n", in ab8500_btemp_measure_temp()
469 * Return out-of-range temperature so that in ab8500_btemp_measure_temp()
475 temp = ab8500_btemp_res_to_temp(di, in ab8500_btemp_measure_temp()
476 di->bm->bat_type[id].r_to_t_tbl, in ab8500_btemp_measure_temp()
477 di->bm->bat_type[id].n_temp_tbl_elements, rbat); in ab8500_btemp_measure_temp()
479 ret = iio_read_channel_processed(di->btemp_ball, &vntc); in ab8500_btemp_measure_temp()
481 dev_err(di->dev, in ab8500_btemp_measure_temp()
490 rntc = 230000 * vntc / (VTVOUT_V - vntc); in ab8500_btemp_measure_temp()
492 temp = ab8500_btemp_res_to_temp(di, in ab8500_btemp_measure_temp()
493 di->bm->bat_type[id].r_to_t_tbl, in ab8500_btemp_measure_temp()
494 di->bm->bat_type[id].n_temp_tbl_elements, rntc); in ab8500_btemp_measure_temp()
495 prev = temp; in ab8500_btemp_measure_temp()
497 dev_dbg(di->dev, "Battery temperature is %d\n", temp); in ab8500_btemp_measure_temp()
498 return temp; in ab8500_btemp_measure_temp()
502 * ab8500_btemp_id() - Identify the connected battery
514 di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA; in ab8500_btemp_id()
515 di->bm->batt_id = BATTERY_UNKNOWN; in ab8500_btemp_id()
519 dev_err(di->dev, "%s get batctrl res failed\n", __func__); in ab8500_btemp_id()
520 return -ENXIO; in ab8500_btemp_id()
524 for (i = BATTERY_UNKNOWN + 1; i < di->bm->n_btypes; i++) { in ab8500_btemp_id()
525 if ((res <= di->bm->bat_type[i].resis_high) && in ab8500_btemp_id()
526 (res >= di->bm->bat_type[i].resis_low)) { in ab8500_btemp_id()
527 dev_dbg(di->dev, "Battery detected on %s" in ab8500_btemp_id()
530 di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ? in ab8500_btemp_id()
532 di->bm->bat_type[i].resis_low, res, in ab8500_btemp_id()
533 di->bm->bat_type[i].resis_high, i); in ab8500_btemp_id()
535 di->bm->batt_id = i; in ab8500_btemp_id()
540 if (di->bm->batt_id == BATTERY_UNKNOWN) { in ab8500_btemp_id()
541 dev_warn(di->dev, "Battery identified as unknown" in ab8500_btemp_id()
542 ", resistance %d Ohm\n", res); in ab8500_btemp_id()
543 return -ENXIO; in ab8500_btemp_id()
550 if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && in ab8500_btemp_id()
551 di->bm->batt_id == 1) { in ab8500_btemp_id()
552 dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); in ab8500_btemp_id()
553 di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; in ab8500_btemp_id()
556 return di->bm->batt_id; in ab8500_btemp_id()
560 * ab8500_btemp_periodic_work() - Measuring the temperature periodically
572 if (!di->initialized) { in ab8500_btemp_periodic_work()
575 dev_warn(di->dev, "failed to identify the battery\n"); in ab8500_btemp_periodic_work()
585 if ((bat_temp == di->prev_bat_temp) || !di->initialized) { in ab8500_btemp_periodic_work()
586 if ((di->bat_temp != di->prev_bat_temp) || !di->initialized) { in ab8500_btemp_periodic_work()
587 di->initialized = true; in ab8500_btemp_periodic_work()
588 di->bat_temp = bat_temp; in ab8500_btemp_periodic_work()
589 power_supply_changed(di->btemp_psy); in ab8500_btemp_periodic_work()
591 } else if (bat_temp < di->prev_bat_temp) { in ab8500_btemp_periodic_work()
592 di->bat_temp--; in ab8500_btemp_periodic_work()
593 power_supply_changed(di->btemp_psy); in ab8500_btemp_periodic_work()
594 } else if (bat_temp > di->prev_bat_temp) { in ab8500_btemp_periodic_work()
595 di->bat_temp++; in ab8500_btemp_periodic_work()
596 power_supply_changed(di->btemp_psy); in ab8500_btemp_periodic_work()
598 di->prev_bat_temp = bat_temp; in ab8500_btemp_periodic_work()
600 if (di->events.ac_conn || di->events.usb_conn) in ab8500_btemp_periodic_work()
601 interval = di->bm->temp_interval_chg; in ab8500_btemp_periodic_work()
603 interval = di->bm->temp_interval_nochg; in ab8500_btemp_periodic_work()
606 queue_delayed_work(di->btemp_wq, in ab8500_btemp_periodic_work()
607 &di->btemp_periodic_work, in ab8500_btemp_periodic_work()
612 * ab8500_btemp_batctrlindb_handler() - battery removal detected
621 dev_err(di->dev, "Battery removal detected!\n"); in ab8500_btemp_batctrlindb_handler()
623 di->events.batt_rem = true; in ab8500_btemp_batctrlindb_handler()
624 power_supply_changed(di->btemp_psy); in ab8500_btemp_batctrlindb_handler()
630 * ab8500_btemp_templow_handler() - battery temp lower than 10 degrees
640 if (is_ab8500_3p3_or_earlier(di->parent)) { in ab8500_btemp_templow_handler()
641 dev_dbg(di->dev, "Ignore false btemp low irq" in ab8500_btemp_templow_handler()
644 dev_crit(di->dev, "Battery temperature lower than -10deg c\n"); in ab8500_btemp_templow_handler()
646 di->events.btemp_low = true; in ab8500_btemp_templow_handler()
647 di->events.btemp_high = false; in ab8500_btemp_templow_handler()
648 di->events.btemp_medhigh = false; in ab8500_btemp_templow_handler()
649 di->events.btemp_lowmed = false; in ab8500_btemp_templow_handler()
650 power_supply_changed(di->btemp_psy); in ab8500_btemp_templow_handler()
657 * ab8500_btemp_temphigh_handler() - battery temp higher than max temp
667 dev_crit(di->dev, "Battery temperature is higher than MAX temp\n"); in ab8500_btemp_temphigh_handler()
669 di->events.btemp_high = true; in ab8500_btemp_temphigh_handler()
670 di->events.btemp_medhigh = false; in ab8500_btemp_temphigh_handler()
671 di->events.btemp_lowmed = false; in ab8500_btemp_temphigh_handler()
672 di->events.btemp_low = false; in ab8500_btemp_temphigh_handler()
673 power_supply_changed(di->btemp_psy); in ab8500_btemp_temphigh_handler()
679 * ab8500_btemp_lowmed_handler() - battery temp between low and medium
689 dev_dbg(di->dev, "Battery temperature is between low and medium\n"); in ab8500_btemp_lowmed_handler()
691 di->events.btemp_lowmed = true; in ab8500_btemp_lowmed_handler()
692 di->events.btemp_medhigh = false; in ab8500_btemp_lowmed_handler()
693 di->events.btemp_high = false; in ab8500_btemp_lowmed_handler()
694 di->events.btemp_low = false; in ab8500_btemp_lowmed_handler()
695 power_supply_changed(di->btemp_psy); in ab8500_btemp_lowmed_handler()
701 * ab8500_btemp_medhigh_handler() - battery temp between medium and high
711 dev_dbg(di->dev, "Battery temperature is between medium and high\n"); in ab8500_btemp_medhigh_handler()
713 di->events.btemp_medhigh = true; in ab8500_btemp_medhigh_handler()
714 di->events.btemp_lowmed = false; in ab8500_btemp_medhigh_handler()
715 di->events.btemp_high = false; in ab8500_btemp_medhigh_handler()
716 di->events.btemp_low = false; in ab8500_btemp_medhigh_handler()
717 power_supply_changed(di->btemp_psy); in ab8500_btemp_medhigh_handler()
723 * ab8500_btemp_periodic() - Periodic temperature measurements
733 dev_dbg(di->dev, "Enable periodic temperature measurements: %d\n", in ab8500_btemp_periodic()
739 cancel_delayed_work_sync(&di->btemp_periodic_work); in ab8500_btemp_periodic()
742 queue_delayed_work(di->btemp_wq, &di->btemp_periodic_work, 0); in ab8500_btemp_periodic()
746 * ab8500_btemp_get_temp() - get battery temperature
753 int temp = 0; in ab8500_btemp_get_temp() local
759 if (is_ab8500_3p3_or_earlier(di->parent)) { in ab8500_btemp_get_temp()
760 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
762 if (di->events.btemp_low) { in ab8500_btemp_get_temp()
763 if (temp > di->btemp_ranges.btemp_low_limit) in ab8500_btemp_get_temp()
764 temp = di->btemp_ranges.btemp_low_limit * 10; in ab8500_btemp_get_temp()
766 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
767 } else if (di->events.btemp_high) { in ab8500_btemp_get_temp()
768 if (temp < di->btemp_ranges.btemp_high_limit) in ab8500_btemp_get_temp()
769 temp = di->btemp_ranges.btemp_high_limit * 10; in ab8500_btemp_get_temp()
771 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
772 } else if (di->events.btemp_lowmed) { in ab8500_btemp_get_temp()
773 if (temp > di->btemp_ranges.btemp_med_limit) in ab8500_btemp_get_temp()
774 temp = di->btemp_ranges.btemp_med_limit * 10; in ab8500_btemp_get_temp()
776 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
777 } else if (di->events.btemp_medhigh) { in ab8500_btemp_get_temp()
778 if (temp < di->btemp_ranges.btemp_med_limit) in ab8500_btemp_get_temp()
779 temp = di->btemp_ranges.btemp_med_limit * 10; in ab8500_btemp_get_temp()
781 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
783 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
785 return temp; in ab8500_btemp_get_temp()
789 * ab8500_btemp_get_property() - get the btemp properties
799 * temp: battery temperature
811 if (di->events.batt_rem) in ab8500_btemp_get_property()
812 val->intval = 0; in ab8500_btemp_get_property()
814 val->intval = 1; in ab8500_btemp_get_property()
817 val->intval = di->bm->bat_type[di->bm->batt_id].name; in ab8500_btemp_get_property()
820 val->intval = ab8500_btemp_get_temp(di); in ab8500_btemp_get_property()
823 return -EINVAL; in ab8500_btemp_get_property()
832 const char **supplicants = (const char **)ext->supplied_to; in ab8500_btemp_get_ext_psy_data()
844 j = match_string(supplicants, ext->num_supplicants, psy->desc->name); in ab8500_btemp_get_ext_psy_data()
849 for (j = 0; j < ext->desc->num_properties; j++) { in ab8500_btemp_get_ext_psy_data()
851 prop = ext->desc->properties[j]; in ab8500_btemp_get_ext_psy_data()
858 switch (ext->desc->type) { in ab8500_btemp_get_ext_psy_data()
861 if (!ret.intval && di->events.ac_conn) { in ab8500_btemp_get_ext_psy_data()
862 di->events.ac_conn = false; in ab8500_btemp_get_ext_psy_data()
865 else if (ret.intval && !di->events.ac_conn) { in ab8500_btemp_get_ext_psy_data()
866 di->events.ac_conn = true; in ab8500_btemp_get_ext_psy_data()
867 if (!di->events.usb_conn) in ab8500_btemp_get_ext_psy_data()
873 if (!ret.intval && di->events.usb_conn) { in ab8500_btemp_get_ext_psy_data()
874 di->events.usb_conn = false; in ab8500_btemp_get_ext_psy_data()
877 else if (ret.intval && !di->events.usb_conn) { in ab8500_btemp_get_ext_psy_data()
878 di->events.usb_conn = true; in ab8500_btemp_get_ext_psy_data()
879 if (!di->events.ac_conn) in ab8500_btemp_get_ext_psy_data()
895 * ab8500_btemp_external_power_changed() - callback for power supply changes
908 di->btemp_psy, ab8500_btemp_get_ext_psy_data); in ab8500_btemp_external_power_changed()
958 di->btemp_wq = in ab8500_btemp_bind()
960 if (di->btemp_wq == NULL) { in ab8500_btemp_bind()
962 return -ENOMEM; in ab8500_btemp_bind()
977 destroy_workqueue(di->btemp_wq); in ab8500_btemp_unbind()
989 struct device *dev = &pdev->dev; in ab8500_btemp_probe()
996 return -ENOMEM; in ab8500_btemp_probe()
998 di->bm = &ab8500_bm_data; in ab8500_btemp_probe()
1001 di->dev = dev; in ab8500_btemp_probe()
1002 di->parent = dev_get_drvdata(pdev->dev.parent); in ab8500_btemp_probe()
1005 di->btemp_ball = devm_iio_channel_get(dev, "btemp_ball"); in ab8500_btemp_probe()
1006 if (IS_ERR(di->btemp_ball)) { in ab8500_btemp_probe()
1007 ret = dev_err_probe(dev, PTR_ERR(di->btemp_ball), in ab8500_btemp_probe()
1011 di->bat_ctrl = devm_iio_channel_get(dev, "bat_ctrl"); in ab8500_btemp_probe()
1012 if (IS_ERR(di->bat_ctrl)) { in ab8500_btemp_probe()
1013 ret = dev_err_probe(dev, PTR_ERR(di->bat_ctrl), in ab8500_btemp_probe()
1018 di->initialized = false; in ab8500_btemp_probe()
1025 INIT_DEFERRABLE_WORK(&di->btemp_periodic_work, in ab8500_btemp_probe()
1029 di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT; in ab8500_btemp_probe()
1030 di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT; in ab8500_btemp_probe()
1041 di->btemp_ranges.btemp_high_limit = in ab8500_btemp_probe()
1045 di->btemp_ranges.btemp_high_limit = in ab8500_btemp_probe()
1049 di->btemp_ranges.btemp_high_limit = in ab8500_btemp_probe()
1055 di->btemp_psy = devm_power_supply_register(dev, &ab8500_btemp_desc, in ab8500_btemp_probe()
1057 if (IS_ERR(di->btemp_psy)) { in ab8500_btemp_probe()
1059 return PTR_ERR(di->btemp_psy); in ab8500_btemp_probe()
1084 list_add_tail(&di->node, &ab8500_btemp_list); in ab8500_btemp_probe()
1091 component_del(&pdev->dev, &ab8500_btemp_component_ops); in ab8500_btemp_remove()
1099 { .compatible = "stericsson,ab8500-btemp", },
1108 .name = "ab8500-btemp",
1115 MODULE_ALIAS("platform:ab8500-btemp");