Lines Matching +full:ext +full:- +full:irq +full:- +full:range

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) ST-Ericsson SA 2012
31 #include <linux/fixp-arith.h>
33 #include "ab8500-bm.h"
35 #define BTEMP_THERMAL_LOW_LIMIT -10
51 * struct ab8500_btemp_interrupts - ab8500 interrupts
57 irqreturn_t (*isr)(int irq, void *data);
77 * struct ab8500_btemp - ab8500 BTEMP device information
90 * @btemp_ranges: Battery temperature range structure
124 * ab8500_btemp_batctrl_volt_to_res() - convert batctrl voltage to resistance
136 if (is_ab8500_1p1_or_earlier(di->parent)) { in ab8500_btemp_batctrl_volt_to_res()
141 return (450000 * (v_batctrl)) / (1800 - v_batctrl); in ab8500_btemp_batctrl_volt_to_res()
148 return (80000 * (v_batctrl)) / (1800 - v_batctrl); in ab8500_btemp_batctrl_volt_to_res()
152 * ab8500_btemp_read_batctrl_voltage() - measure batctrl voltage
162 ret = iio_read_channel_processed(di->bat_ctrl, &vbtemp); in ab8500_btemp_read_batctrl_voltage()
164 dev_err(di->dev, in ab8500_btemp_read_batctrl_voltage()
174 * ab8500_btemp_get_batctrl_res() - get battery resistance
188 if (!di->fg) in ab8500_btemp_get_batctrl_res()
189 di->fg = ab8500_fg_get(); in ab8500_btemp_get_batctrl_res()
190 if (!di->fg) { in ab8500_btemp_get_batctrl_res()
191 dev_err(di->dev, "No fg found\n"); in ab8500_btemp_get_batctrl_res()
192 return -EINVAL; in ab8500_btemp_get_batctrl_res()
195 ret = ab8500_fg_inst_curr_start(di->fg); in ab8500_btemp_get_batctrl_res()
198 dev_err(di->dev, "Failed to start current measurement\n"); in ab8500_btemp_get_batctrl_res()
204 } while (!ab8500_fg_inst_curr_started(di->fg)); in ab8500_btemp_get_batctrl_res()
212 } while (!ab8500_fg_inst_curr_done(di->fg)); in ab8500_btemp_get_batctrl_res()
215 ret = ab8500_fg_inst_curr_finalize(di->fg, &inst_curr); in ab8500_btemp_get_batctrl_res()
217 dev_err(di->dev, "Failed to finalize current measurement\n"); in ab8500_btemp_get_batctrl_res()
223 dev_dbg(di->dev, "%s batctrl: %d res: %d inst_curr: %d samples: %d\n", in ab8500_btemp_get_batctrl_res()
230 * ab8500_btemp_id() - Identify the connected battery
239 struct power_supply_battery_info *bi = di->bm->bi; in ab8500_btemp_id()
242 di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA; in ab8500_btemp_id()
246 dev_err(di->dev, "%s get batctrl res failed\n", __func__); in ab8500_btemp_id()
247 return -ENXIO; in ab8500_btemp_id()
251 dev_info(di->dev, "Battery detected on BATCTRL (pin C3)" in ab8500_btemp_id()
252 " resistance %d Ohm = %d Ohm +/- %d%%\n", in ab8500_btemp_id()
253 res, bi->bti_resistance_ohm, in ab8500_btemp_id()
254 bi->bti_resistance_tolerance); in ab8500_btemp_id()
256 dev_warn(di->dev, "Battery identified as unknown" in ab8500_btemp_id()
258 return -ENXIO; in ab8500_btemp_id()
265 * ab8500_btemp_periodic_work() - Measuring the temperature periodically
280 if (!di->initialized) { in ab8500_btemp_periodic_work()
283 dev_warn(di->dev, "failed to identify the battery\n"); in ab8500_btemp_periodic_work()
287 ret = thermal_zone_get_temp(di->tz, &bat_temp); in ab8500_btemp_periodic_work()
289 dev_err(di->dev, "error reading temperature\n"); in ab8500_btemp_periodic_work()
303 if ((bat_temp == di->prev_bat_temp) || !di->initialized) { in ab8500_btemp_periodic_work()
304 if ((di->bat_temp != di->prev_bat_temp) || !di->initialized) { in ab8500_btemp_periodic_work()
305 di->initialized = true; in ab8500_btemp_periodic_work()
306 di->bat_temp = bat_temp; in ab8500_btemp_periodic_work()
307 power_supply_changed(di->btemp_psy); in ab8500_btemp_periodic_work()
309 } else if (bat_temp < di->prev_bat_temp) { in ab8500_btemp_periodic_work()
310 di->bat_temp--; in ab8500_btemp_periodic_work()
311 power_supply_changed(di->btemp_psy); in ab8500_btemp_periodic_work()
312 } else if (bat_temp > di->prev_bat_temp) { in ab8500_btemp_periodic_work()
313 di->bat_temp++; in ab8500_btemp_periodic_work()
314 power_supply_changed(di->btemp_psy); in ab8500_btemp_periodic_work()
316 di->prev_bat_temp = bat_temp; in ab8500_btemp_periodic_work()
318 if (di->events.ac_conn || di->events.usb_conn) in ab8500_btemp_periodic_work()
319 interval = di->bm->temp_interval_chg; in ab8500_btemp_periodic_work()
321 interval = di->bm->temp_interval_nochg; in ab8500_btemp_periodic_work()
324 queue_delayed_work(di->btemp_wq, in ab8500_btemp_periodic_work()
325 &di->btemp_periodic_work, in ab8500_btemp_periodic_work()
330 * ab8500_btemp_batctrlindb_handler() - battery removal detected
331 * @irq: interrupt number
334 * Returns IRQ status(IRQ_HANDLED)
336 static irqreturn_t ab8500_btemp_batctrlindb_handler(int irq, void *_di) in ab8500_btemp_batctrlindb_handler() argument
339 dev_err(di->dev, "Battery removal detected!\n"); in ab8500_btemp_batctrlindb_handler()
341 di->events.batt_rem = true; in ab8500_btemp_batctrlindb_handler()
342 power_supply_changed(di->btemp_psy); in ab8500_btemp_batctrlindb_handler()
348 * ab8500_btemp_templow_handler() - battery temp lower than 10 degrees
349 * @irq: interrupt number
352 * Returns IRQ status(IRQ_HANDLED)
354 static irqreturn_t ab8500_btemp_templow_handler(int irq, void *_di) in ab8500_btemp_templow_handler() argument
358 if (is_ab8500_3p3_or_earlier(di->parent)) { in ab8500_btemp_templow_handler()
359 dev_dbg(di->dev, "Ignore false btemp low irq" in ab8500_btemp_templow_handler()
362 dev_crit(di->dev, "Battery temperature lower than -10deg c\n"); in ab8500_btemp_templow_handler()
364 di->events.btemp_low = true; in ab8500_btemp_templow_handler()
365 di->events.btemp_high = false; in ab8500_btemp_templow_handler()
366 di->events.btemp_medhigh = false; in ab8500_btemp_templow_handler()
367 di->events.btemp_lowmed = false; in ab8500_btemp_templow_handler()
368 power_supply_changed(di->btemp_psy); in ab8500_btemp_templow_handler()
375 * ab8500_btemp_temphigh_handler() - battery temp higher than max temp
376 * @irq: interrupt number
379 * Returns IRQ status(IRQ_HANDLED)
381 static irqreturn_t ab8500_btemp_temphigh_handler(int irq, void *_di) in ab8500_btemp_temphigh_handler() argument
385 dev_crit(di->dev, "Battery temperature is higher than MAX temp\n"); in ab8500_btemp_temphigh_handler()
387 di->events.btemp_high = true; in ab8500_btemp_temphigh_handler()
388 di->events.btemp_medhigh = false; in ab8500_btemp_temphigh_handler()
389 di->events.btemp_lowmed = false; in ab8500_btemp_temphigh_handler()
390 di->events.btemp_low = false; in ab8500_btemp_temphigh_handler()
391 power_supply_changed(di->btemp_psy); in ab8500_btemp_temphigh_handler()
397 * ab8500_btemp_lowmed_handler() - battery temp between low and medium
398 * @irq: interrupt number
401 * Returns IRQ status(IRQ_HANDLED)
403 static irqreturn_t ab8500_btemp_lowmed_handler(int irq, void *_di) in ab8500_btemp_lowmed_handler() argument
407 dev_dbg(di->dev, "Battery temperature is between low and medium\n"); in ab8500_btemp_lowmed_handler()
409 di->events.btemp_lowmed = true; in ab8500_btemp_lowmed_handler()
410 di->events.btemp_medhigh = false; in ab8500_btemp_lowmed_handler()
411 di->events.btemp_high = false; in ab8500_btemp_lowmed_handler()
412 di->events.btemp_low = false; in ab8500_btemp_lowmed_handler()
413 power_supply_changed(di->btemp_psy); in ab8500_btemp_lowmed_handler()
419 * ab8500_btemp_medhigh_handler() - battery temp between medium and high
420 * @irq: interrupt number
423 * Returns IRQ status(IRQ_HANDLED)
425 static irqreturn_t ab8500_btemp_medhigh_handler(int irq, void *_di) in ab8500_btemp_medhigh_handler() argument
429 dev_dbg(di->dev, "Battery temperature is between medium and high\n"); in ab8500_btemp_medhigh_handler()
431 di->events.btemp_medhigh = true; in ab8500_btemp_medhigh_handler()
432 di->events.btemp_lowmed = false; in ab8500_btemp_medhigh_handler()
433 di->events.btemp_high = false; in ab8500_btemp_medhigh_handler()
434 di->events.btemp_low = false; in ab8500_btemp_medhigh_handler()
435 power_supply_changed(di->btemp_psy); in ab8500_btemp_medhigh_handler()
441 * ab8500_btemp_periodic() - Periodic temperature measurements
451 dev_dbg(di->dev, "Enable periodic temperature measurements: %d\n", in ab8500_btemp_periodic()
457 cancel_delayed_work_sync(&di->btemp_periodic_work); in ab8500_btemp_periodic()
460 queue_delayed_work(di->btemp_wq, &di->btemp_periodic_work, 0); in ab8500_btemp_periodic()
464 * ab8500_btemp_get_temp() - get battery temperature
477 if (is_ab8500_3p3_or_earlier(di->parent)) { in ab8500_btemp_get_temp()
478 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
480 if (di->events.btemp_low) { in ab8500_btemp_get_temp()
481 if (temp > di->btemp_ranges.btemp_low_limit) in ab8500_btemp_get_temp()
482 temp = di->btemp_ranges.btemp_low_limit * 10; in ab8500_btemp_get_temp()
484 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
485 } else if (di->events.btemp_high) { in ab8500_btemp_get_temp()
486 if (temp < di->btemp_ranges.btemp_high_limit) in ab8500_btemp_get_temp()
487 temp = di->btemp_ranges.btemp_high_limit * 10; in ab8500_btemp_get_temp()
489 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
490 } else if (di->events.btemp_lowmed) { in ab8500_btemp_get_temp()
491 if (temp > di->btemp_ranges.btemp_med_limit) in ab8500_btemp_get_temp()
492 temp = di->btemp_ranges.btemp_med_limit * 10; in ab8500_btemp_get_temp()
494 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
495 } else if (di->events.btemp_medhigh) { in ab8500_btemp_get_temp()
496 if (temp < di->btemp_ranges.btemp_med_limit) in ab8500_btemp_get_temp()
497 temp = di->btemp_ranges.btemp_med_limit * 10; in ab8500_btemp_get_temp()
499 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
501 temp = di->bat_temp * 10; in ab8500_btemp_get_temp()
507 * ab8500_btemp_get_property() - get the btemp properties
529 if (di->events.batt_rem) in ab8500_btemp_get_property()
530 val->intval = 0; in ab8500_btemp_get_property()
532 val->intval = 1; in ab8500_btemp_get_property()
535 val->intval = ab8500_btemp_get_temp(di); in ab8500_btemp_get_property()
538 return -EINVAL; in ab8500_btemp_get_property()
546 struct power_supply *ext = dev_get_drvdata(dev); in ab8500_btemp_get_ext_psy_data() local
547 const char **supplicants = (const char **)ext->supplied_to; in ab8500_btemp_get_ext_psy_data()
559 j = match_string(supplicants, ext->num_supplicants, psy->desc->name); in ab8500_btemp_get_ext_psy_data()
564 for (j = 0; j < ext->desc->num_properties; j++) { in ab8500_btemp_get_ext_psy_data()
566 prop = ext->desc->properties[j]; in ab8500_btemp_get_ext_psy_data()
568 if (power_supply_get_property(ext, prop, &ret)) in ab8500_btemp_get_ext_psy_data()
573 switch (ext->desc->type) { in ab8500_btemp_get_ext_psy_data()
576 if (!ret.intval && di->events.ac_conn) { in ab8500_btemp_get_ext_psy_data()
577 di->events.ac_conn = false; in ab8500_btemp_get_ext_psy_data()
580 else if (ret.intval && !di->events.ac_conn) { in ab8500_btemp_get_ext_psy_data()
581 di->events.ac_conn = true; in ab8500_btemp_get_ext_psy_data()
582 if (!di->events.usb_conn) in ab8500_btemp_get_ext_psy_data()
588 if (!ret.intval && di->events.usb_conn) { in ab8500_btemp_get_ext_psy_data()
589 di->events.usb_conn = false; in ab8500_btemp_get_ext_psy_data()
592 else if (ret.intval && !di->events.usb_conn) { in ab8500_btemp_get_ext_psy_data()
593 di->events.usb_conn = true; in ab8500_btemp_get_ext_psy_data()
594 if (!di->events.ac_conn) in ab8500_btemp_get_ext_psy_data()
610 * ab8500_btemp_external_power_changed() - callback for power supply changes
670 di->btemp_wq = in ab8500_btemp_bind()
672 if (di->btemp_wq == NULL) { in ab8500_btemp_bind()
674 return -ENOMEM; in ab8500_btemp_bind()
689 destroy_workqueue(di->btemp_wq); in ab8500_btemp_unbind()
700 struct device *dev = &pdev->dev; in ab8500_btemp_probe()
702 int irq, i, ret = 0; in ab8500_btemp_probe() local
707 return -ENOMEM; in ab8500_btemp_probe()
709 di->bm = &ab8500_bm_data; in ab8500_btemp_probe()
712 di->dev = dev; in ab8500_btemp_probe()
713 di->parent = dev_get_drvdata(pdev->dev.parent); in ab8500_btemp_probe()
716 di->tz = thermal_zone_get_zone_by_name("battery-thermal"); in ab8500_btemp_probe()
717 if (IS_ERR(di->tz)) { in ab8500_btemp_probe()
718 ret = PTR_ERR(di->tz); in ab8500_btemp_probe()
723 if (ret == -ENODEV) in ab8500_btemp_probe()
724 ret = -EPROBE_DEFER; in ab8500_btemp_probe()
728 di->bat_ctrl = devm_iio_channel_get(dev, "bat_ctrl"); in ab8500_btemp_probe()
729 if (IS_ERR(di->bat_ctrl)) { in ab8500_btemp_probe()
730 ret = dev_err_probe(dev, PTR_ERR(di->bat_ctrl), in ab8500_btemp_probe()
735 di->initialized = false; in ab8500_btemp_probe()
742 INIT_DEFERRABLE_WORK(&di->btemp_periodic_work, in ab8500_btemp_probe()
746 di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT; in ab8500_btemp_probe()
747 di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT; in ab8500_btemp_probe()
758 di->btemp_ranges.btemp_high_limit = in ab8500_btemp_probe()
762 di->btemp_ranges.btemp_high_limit = in ab8500_btemp_probe()
766 di->btemp_ranges.btemp_high_limit = in ab8500_btemp_probe()
772 di->btemp_psy = devm_power_supply_register(dev, &ab8500_btemp_desc, in ab8500_btemp_probe()
774 if (IS_ERR(di->btemp_psy)) { in ab8500_btemp_probe()
776 return PTR_ERR(di->btemp_psy); in ab8500_btemp_probe()
781 irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); in ab8500_btemp_probe()
782 if (irq < 0) in ab8500_btemp_probe()
783 return irq; in ab8500_btemp_probe()
785 ret = devm_request_threaded_irq(dev, irq, NULL, in ab8500_btemp_probe()
791 dev_err(dev, "failed to request %s IRQ %d: %d\n" in ab8500_btemp_probe()
792 , ab8500_btemp_irq[i].name, irq, ret); in ab8500_btemp_probe()
795 dev_dbg(dev, "Requested %s IRQ %d: %d\n", in ab8500_btemp_probe()
796 ab8500_btemp_irq[i].name, irq, ret); in ab8500_btemp_probe()
801 list_add_tail(&di->node, &ab8500_btemp_list); in ab8500_btemp_probe()
808 component_del(&pdev->dev, &ab8500_btemp_component_ops); in ab8500_btemp_remove()
814 { .compatible = "stericsson,ab8500-btemp", },
823 .name = "ab8500-btemp",
830 MODULE_ALIAS("platform:ab8500-btemp");