1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) ST-Ericsson SA 2012
5 * Battery temperature driver for AB8500
8 * Johan Palsson <johan.palsson@stericsson.com>
9 * Karl Komierowski <karl.komierowski@stericsson.com>
10 * Arun R Murthy <arun.murthy@stericsson.com>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/device.h>
16 #include <linux/component.h>
17 #include <linux/interrupt.h>
18 #include <linux/delay.h>
19 #include <linux/slab.h>
20 #include <linux/platform_device.h>
21 #include <linux/power_supply.h>
22 #include <linux/completion.h>
23 #include <linux/workqueue.h>
24 #include <linux/jiffies.h>
26 #include <linux/mfd/core.h>
27 #include <linux/mfd/abx500.h>
28 #include <linux/mfd/abx500/ab8500.h>
29 #include <linux/thermal.h>
30 #include <linux/iio/consumer.h>
31 #include <linux/fixp-arith.h>
33 #include "ab8500-bm.h"
35 #define BTEMP_THERMAL_LOW_LIMIT -10
36 #define BTEMP_THERMAL_MED_LIMIT 0
37 #define BTEMP_THERMAL_HIGH_LIMIT_52 52
38 #define BTEMP_THERMAL_HIGH_LIMIT_57 57
39 #define BTEMP_THERMAL_HIGH_LIMIT_62 62
41 #define BTEMP_BATCTRL_CURR_SRC_7UA 7
42 #define BTEMP_BATCTRL_CURR_SRC_20UA 20
44 #define BTEMP_BATCTRL_CURR_SRC_16UA 16
45 #define BTEMP_BATCTRL_CURR_SRC_18UA 18
47 #define BTEMP_BATCTRL_CURR_SRC_60UA 60
48 #define BTEMP_BATCTRL_CURR_SRC_120UA 120
51 * struct ab8500_btemp_interrupts - ab8500 interrupts
52 * @name: name of the interrupt
53 * @isr function pointer to the isr
55 struct ab8500_btemp_interrupts
{
57 irqreturn_t (*isr
)(int irq
, void *data
);
60 struct ab8500_btemp_events
{
70 struct ab8500_btemp_ranges
{
77 * struct ab8500_btemp - ab8500 BTEMP device information
78 * @dev: Pointer to the structure device
79 * @node: List of AB8500 BTEMPs, hence prepared for reentrance
80 * @curr_source: What current source we use, in uA
81 * @bat_temp: Dispatched battery temperature in degree Celsius
82 * @prev_bat_temp Last measured battery temperature in degree Celsius
83 * @parent: Pointer to the struct ab8500
84 * @tz: Thermal zone for the battery
85 * @adc_bat_ctrl: ADC channel for the battery control
86 * @fg: Pointer to the struct fg
87 * @bm: Platform specific battery management information
88 * @btemp_psy: Structure for BTEMP specific battery properties
89 * @events: Structure for information about events triggered
90 * @btemp_ranges: Battery temperature range structure
91 * @btemp_wq: Work queue for measuring the temperature periodically
92 * @btemp_periodic_work: Work for measuring the temperature periodically
93 * @initialized: True if battery id read.
97 struct list_head node
;
101 struct ab8500
*parent
;
102 struct thermal_zone_device
*tz
;
103 struct iio_channel
*bat_ctrl
;
104 struct ab8500_fg
*fg
;
105 struct ab8500_bm_data
*bm
;
106 struct power_supply
*btemp_psy
;
107 struct ab8500_btemp_events events
;
108 struct ab8500_btemp_ranges btemp_ranges
;
109 struct workqueue_struct
*btemp_wq
;
110 struct delayed_work btemp_periodic_work
;
114 /* BTEMP power supply properties */
115 static enum power_supply_property ab8500_btemp_props
[] = {
116 POWER_SUPPLY_PROP_PRESENT
,
117 POWER_SUPPLY_PROP_ONLINE
,
118 POWER_SUPPLY_PROP_TEMP
,
121 static LIST_HEAD(ab8500_btemp_list
);
124 * ab8500_btemp_batctrl_volt_to_res() - convert batctrl voltage to resistance
125 * @di: pointer to the ab8500_btemp structure
126 * @v_batctrl: measured batctrl voltage
127 * @inst_curr: measured instant current
129 * This function returns the battery resistance that is
130 * derived from the BATCTRL voltage.
131 * Returns value in Ohms.
133 static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp
*di
,
134 int v_batctrl
, int inst_curr
)
136 if (is_ab8500_1p1_or_earlier(di
->parent
)) {
138 * For ABB cut1.0 and 1.1 BAT_CTRL is internally
139 * connected to 1.8V through a 450k resistor
141 return (450000 * (v_batctrl
)) / (1800 - v_batctrl
);
145 * BAT_CTRL is internally
146 * connected to 1.8V through a 80k resistor
148 return (80000 * (v_batctrl
)) / (1800 - v_batctrl
);
152 * ab8500_btemp_read_batctrl_voltage() - measure batctrl voltage
153 * @di: pointer to the ab8500_btemp structure
155 * This function returns the voltage on BATCTRL. Returns value in mV.
157 static int ab8500_btemp_read_batctrl_voltage(struct ab8500_btemp
*di
)
162 ret
= iio_read_channel_processed(di
->bat_ctrl
, &vbtemp
);
165 "%s ADC conversion failed, using previous value",
174 * ab8500_btemp_get_batctrl_res() - get battery resistance
175 * @di: pointer to the ab8500_btemp structure
177 * This function returns the battery pack identification resistance.
178 * Returns value in Ohms.
180 static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp
*di
)
189 di
->fg
= ab8500_fg_get();
191 dev_err(di
->dev
, "No fg found\n");
195 ret
= ab8500_fg_inst_curr_start(di
->fg
);
198 dev_err(di
->dev
, "Failed to start current measurement\n");
204 } while (!ab8500_fg_inst_curr_started(di
->fg
));
209 batctrl
+= ab8500_btemp_read_batctrl_voltage(di
);
212 } while (!ab8500_fg_inst_curr_done(di
->fg
));
215 ret
= ab8500_fg_inst_curr_finalize(di
->fg
, &inst_curr
);
217 dev_err(di
->dev
, "Failed to finalize current measurement\n");
221 res
= ab8500_btemp_batctrl_volt_to_res(di
, batctrl
, inst_curr
);
223 dev_dbg(di
->dev
, "%s batctrl: %d res: %d inst_curr: %d samples: %d\n",
224 __func__
, batctrl
, res
, inst_curr
, i
);
230 * ab8500_btemp_id() - Identify the connected battery
231 * @di: pointer to the ab8500_btemp structure
233 * This function will try to identify the battery by reading the ID
234 * resistor. Some brands use a combined ID resistor with a NTC resistor to
235 * both be able to identify and to read the temperature of it.
237 static int ab8500_btemp_id(struct ab8500_btemp
*di
)
239 struct power_supply_battery_info
*bi
= di
->bm
->bi
;
242 di
->curr_source
= BTEMP_BATCTRL_CURR_SRC_7UA
;
244 res
= ab8500_btemp_get_batctrl_res(di
);
246 dev_err(di
->dev
, "%s get batctrl res failed\n", __func__
);
250 if (power_supply_battery_bti_in_range(bi
, res
)) {
251 dev_info(di
->dev
, "Battery detected on BATCTRL (pin C3)"
252 " resistance %d Ohm = %d Ohm +/- %d%%\n",
253 res
, bi
->bti_resistance_ohm
,
254 bi
->bti_resistance_tolerance
);
256 dev_warn(di
->dev
, "Battery identified as unknown"
257 ", resistance %d Ohm\n", res
);
265 * ab8500_btemp_periodic_work() - Measuring the temperature periodically
266 * @work: pointer to the work_struct structure
268 * Work function for measuring the temperature periodically
270 static void ab8500_btemp_periodic_work(struct work_struct
*work
)
274 struct ab8500_btemp
*di
= container_of(work
,
275 struct ab8500_btemp
, btemp_periodic_work
.work
);
276 /* Assume 25 degrees celsius as start temperature */
277 static int prev
= 25;
280 if (!di
->initialized
) {
281 /* Identify the battery */
282 if (ab8500_btemp_id(di
) < 0)
283 dev_warn(di
->dev
, "failed to identify the battery\n");
286 /* Failover if a reading is erroneous, use last measurement */
287 ret
= thermal_zone_get_temp(di
->tz
, &bat_temp
);
289 dev_err(di
->dev
, "error reading temperature\n");
292 /* Convert from millicentigrades to centigrades */
298 * Filter battery temperature.
299 * Allow direct updates on temperature only if two samples result in
300 * same temperature. Else only allow 1 degree change from previous
301 * reported value in the direction of the new measurement.
303 if ((bat_temp
== di
->prev_bat_temp
) || !di
->initialized
) {
304 if ((di
->bat_temp
!= di
->prev_bat_temp
) || !di
->initialized
) {
305 di
->initialized
= true;
306 di
->bat_temp
= bat_temp
;
307 power_supply_changed(di
->btemp_psy
);
309 } else if (bat_temp
< di
->prev_bat_temp
) {
311 power_supply_changed(di
->btemp_psy
);
312 } else if (bat_temp
> di
->prev_bat_temp
) {
314 power_supply_changed(di
->btemp_psy
);
316 di
->prev_bat_temp
= bat_temp
;
318 if (di
->events
.ac_conn
|| di
->events
.usb_conn
)
319 interval
= di
->bm
->temp_interval_chg
;
321 interval
= di
->bm
->temp_interval_nochg
;
323 /* Schedule a new measurement */
324 queue_delayed_work(di
->btemp_wq
,
325 &di
->btemp_periodic_work
,
326 round_jiffies(interval
* HZ
));
330 * ab8500_btemp_batctrlindb_handler() - battery removal detected
331 * @irq: interrupt number
332 * @_di: void pointer that has to address of ab8500_btemp
334 * Returns IRQ status(IRQ_HANDLED)
336 static irqreturn_t
ab8500_btemp_batctrlindb_handler(int irq
, void *_di
)
338 struct ab8500_btemp
*di
= _di
;
339 dev_err(di
->dev
, "Battery removal detected!\n");
341 di
->events
.batt_rem
= true;
342 power_supply_changed(di
->btemp_psy
);
348 * ab8500_btemp_templow_handler() - battery temp lower than 10 degrees
349 * @irq: interrupt number
350 * @_di: void pointer that has to address of ab8500_btemp
352 * Returns IRQ status(IRQ_HANDLED)
354 static irqreturn_t
ab8500_btemp_templow_handler(int irq
, void *_di
)
356 struct ab8500_btemp
*di
= _di
;
358 if (is_ab8500_3p3_or_earlier(di
->parent
)) {
359 dev_dbg(di
->dev
, "Ignore false btemp low irq"
360 " for ABB cut 1.0, 1.1, 2.0 and 3.3\n");
362 dev_crit(di
->dev
, "Battery temperature lower than -10deg c\n");
364 di
->events
.btemp_low
= true;
365 di
->events
.btemp_high
= false;
366 di
->events
.btemp_medhigh
= false;
367 di
->events
.btemp_lowmed
= false;
368 power_supply_changed(di
->btemp_psy
);
375 * ab8500_btemp_temphigh_handler() - battery temp higher than max temp
376 * @irq: interrupt number
377 * @_di: void pointer that has to address of ab8500_btemp
379 * Returns IRQ status(IRQ_HANDLED)
381 static irqreturn_t
ab8500_btemp_temphigh_handler(int irq
, void *_di
)
383 struct ab8500_btemp
*di
= _di
;
385 dev_crit(di
->dev
, "Battery temperature is higher than MAX temp\n");
387 di
->events
.btemp_high
= true;
388 di
->events
.btemp_medhigh
= false;
389 di
->events
.btemp_lowmed
= false;
390 di
->events
.btemp_low
= false;
391 power_supply_changed(di
->btemp_psy
);
397 * ab8500_btemp_lowmed_handler() - battery temp between low and medium
398 * @irq: interrupt number
399 * @_di: void pointer that has to address of ab8500_btemp
401 * Returns IRQ status(IRQ_HANDLED)
403 static irqreturn_t
ab8500_btemp_lowmed_handler(int irq
, void *_di
)
405 struct ab8500_btemp
*di
= _di
;
407 dev_dbg(di
->dev
, "Battery temperature is between low and medium\n");
409 di
->events
.btemp_lowmed
= true;
410 di
->events
.btemp_medhigh
= false;
411 di
->events
.btemp_high
= false;
412 di
->events
.btemp_low
= false;
413 power_supply_changed(di
->btemp_psy
);
419 * ab8500_btemp_medhigh_handler() - battery temp between medium and high
420 * @irq: interrupt number
421 * @_di: void pointer that has to address of ab8500_btemp
423 * Returns IRQ status(IRQ_HANDLED)
425 static irqreturn_t
ab8500_btemp_medhigh_handler(int irq
, void *_di
)
427 struct ab8500_btemp
*di
= _di
;
429 dev_dbg(di
->dev
, "Battery temperature is between medium and high\n");
431 di
->events
.btemp_medhigh
= true;
432 di
->events
.btemp_lowmed
= false;
433 di
->events
.btemp_high
= false;
434 di
->events
.btemp_low
= false;
435 power_supply_changed(di
->btemp_psy
);
441 * ab8500_btemp_periodic() - Periodic temperature measurements
442 * @di: pointer to the ab8500_btemp structure
443 * @enable: enable or disable periodic temperature measurements
445 * Starts of stops periodic temperature measurements. Periodic measurements
446 * should only be done when a charger is connected.
448 static void ab8500_btemp_periodic(struct ab8500_btemp
*di
,
451 dev_dbg(di
->dev
, "Enable periodic temperature measurements: %d\n",
454 * Make sure a new measurement is done directly by cancelling
457 cancel_delayed_work_sync(&di
->btemp_periodic_work
);
460 queue_delayed_work(di
->btemp_wq
, &di
->btemp_periodic_work
, 0);
464 * ab8500_btemp_get_temp() - get battery temperature
465 * @di: pointer to the ab8500_btemp structure
467 * Returns battery temperature
469 static int ab8500_btemp_get_temp(struct ab8500_btemp
*di
)
474 * The BTEMP events are not reliabe on AB8500 cut3.3
477 if (is_ab8500_3p3_or_earlier(di
->parent
)) {
478 temp
= di
->bat_temp
* 10;
480 if (di
->events
.btemp_low
) {
481 if (temp
> di
->btemp_ranges
.btemp_low_limit
)
482 temp
= di
->btemp_ranges
.btemp_low_limit
* 10;
484 temp
= di
->bat_temp
* 10;
485 } else if (di
->events
.btemp_high
) {
486 if (temp
< di
->btemp_ranges
.btemp_high_limit
)
487 temp
= di
->btemp_ranges
.btemp_high_limit
* 10;
489 temp
= di
->bat_temp
* 10;
490 } else if (di
->events
.btemp_lowmed
) {
491 if (temp
> di
->btemp_ranges
.btemp_med_limit
)
492 temp
= di
->btemp_ranges
.btemp_med_limit
* 10;
494 temp
= di
->bat_temp
* 10;
495 } else if (di
->events
.btemp_medhigh
) {
496 if (temp
< di
->btemp_ranges
.btemp_med_limit
)
497 temp
= di
->btemp_ranges
.btemp_med_limit
* 10;
499 temp
= di
->bat_temp
* 10;
501 temp
= di
->bat_temp
* 10;
507 * ab8500_btemp_get_property() - get the btemp properties
508 * @psy: pointer to the power_supply structure
509 * @psp: pointer to the power_supply_property structure
510 * @val: pointer to the power_supply_propval union
512 * This function gets called when an application tries to get the btemp
513 * properties by reading the sysfs files.
514 * online: presence of the battery
515 * present: presence of the battery
516 * technology: battery technology
517 * temp: battery temperature
518 * Returns error code in case of failure else 0(on success)
520 static int ab8500_btemp_get_property(struct power_supply
*psy
,
521 enum power_supply_property psp
,
522 union power_supply_propval
*val
)
524 struct ab8500_btemp
*di
= power_supply_get_drvdata(psy
);
527 case POWER_SUPPLY_PROP_PRESENT
:
528 case POWER_SUPPLY_PROP_ONLINE
:
529 if (di
->events
.batt_rem
)
534 case POWER_SUPPLY_PROP_TEMP
:
535 val
->intval
= ab8500_btemp_get_temp(di
);
543 static int ab8500_btemp_get_ext_psy_data(struct device
*dev
, void *data
)
545 struct power_supply
*psy
;
546 struct power_supply
*ext
= dev_get_drvdata(dev
);
547 const char **supplicants
= (const char **)ext
->supplied_to
;
548 struct ab8500_btemp
*di
;
549 union power_supply_propval ret
;
552 psy
= (struct power_supply
*)data
;
553 di
= power_supply_get_drvdata(psy
);
556 * For all psy where the name of your driver
557 * appears in any supplied_to
559 j
= match_string(supplicants
, ext
->num_supplicants
, psy
->desc
->name
);
563 /* Go through all properties for the psy */
564 for (j
= 0; j
< ext
->desc
->num_properties
; j
++) {
565 enum power_supply_property prop
;
566 prop
= ext
->desc
->properties
[j
];
568 if (power_supply_get_property(ext
, prop
, &ret
))
572 case POWER_SUPPLY_PROP_PRESENT
:
573 switch (ext
->desc
->type
) {
574 case POWER_SUPPLY_TYPE_MAINS
:
575 /* AC disconnected */
576 if (!ret
.intval
&& di
->events
.ac_conn
) {
577 di
->events
.ac_conn
= false;
580 else if (ret
.intval
&& !di
->events
.ac_conn
) {
581 di
->events
.ac_conn
= true;
582 if (!di
->events
.usb_conn
)
583 ab8500_btemp_periodic(di
, true);
586 case POWER_SUPPLY_TYPE_USB
:
587 /* USB disconnected */
588 if (!ret
.intval
&& di
->events
.usb_conn
) {
589 di
->events
.usb_conn
= false;
592 else if (ret
.intval
&& !di
->events
.usb_conn
) {
593 di
->events
.usb_conn
= true;
594 if (!di
->events
.ac_conn
)
595 ab8500_btemp_periodic(di
, true);
610 * ab8500_btemp_external_power_changed() - callback for power supply changes
611 * @psy: pointer to the structure power_supply
613 * This function is pointing to the function pointer external_power_changed
614 * of the structure power_supply.
615 * This function gets executed when there is a change in the external power
616 * supply to the btemp.
618 static void ab8500_btemp_external_power_changed(struct power_supply
*psy
)
620 power_supply_for_each_device(psy
, ab8500_btemp_get_ext_psy_data
);
623 /* ab8500 btemp driver interrupts and their respective isr */
624 static struct ab8500_btemp_interrupts ab8500_btemp_irq
[] = {
625 {"BAT_CTRL_INDB", ab8500_btemp_batctrlindb_handler
},
626 {"BTEMP_LOW", ab8500_btemp_templow_handler
},
627 {"BTEMP_HIGH", ab8500_btemp_temphigh_handler
},
628 {"BTEMP_LOW_MEDIUM", ab8500_btemp_lowmed_handler
},
629 {"BTEMP_MEDIUM_HIGH", ab8500_btemp_medhigh_handler
},
632 static int __maybe_unused
ab8500_btemp_resume(struct device
*dev
)
634 struct ab8500_btemp
*di
= dev_get_drvdata(dev
);
636 ab8500_btemp_periodic(di
, true);
641 static int __maybe_unused
ab8500_btemp_suspend(struct device
*dev
)
643 struct ab8500_btemp
*di
= dev_get_drvdata(dev
);
645 ab8500_btemp_periodic(di
, false);
650 static char *supply_interface
[] = {
655 static const struct power_supply_desc ab8500_btemp_desc
= {
656 .name
= "ab8500_btemp",
657 .type
= POWER_SUPPLY_TYPE_UNKNOWN
,
658 .properties
= ab8500_btemp_props
,
659 .num_properties
= ARRAY_SIZE(ab8500_btemp_props
),
660 .get_property
= ab8500_btemp_get_property
,
661 .external_power_changed
= ab8500_btemp_external_power_changed
,
664 static int ab8500_btemp_bind(struct device
*dev
, struct device
*master
,
667 struct ab8500_btemp
*di
= dev_get_drvdata(dev
);
669 /* Create a work queue for the btemp */
671 alloc_workqueue("ab8500_btemp_wq", WQ_MEM_RECLAIM
, 0);
672 if (di
->btemp_wq
== NULL
) {
673 dev_err(dev
, "failed to create work queue\n");
677 /* Kick off periodic temperature measurements */
678 ab8500_btemp_periodic(di
, true);
683 static void ab8500_btemp_unbind(struct device
*dev
, struct device
*master
,
686 struct ab8500_btemp
*di
= dev_get_drvdata(dev
);
688 /* Delete the work queue */
689 destroy_workqueue(di
->btemp_wq
);
692 static const struct component_ops ab8500_btemp_component_ops
= {
693 .bind
= ab8500_btemp_bind
,
694 .unbind
= ab8500_btemp_unbind
,
697 static int ab8500_btemp_probe(struct platform_device
*pdev
)
699 struct power_supply_config psy_cfg
= {};
700 struct device
*dev
= &pdev
->dev
;
701 struct ab8500_btemp
*di
;
705 di
= devm_kzalloc(dev
, sizeof(*di
), GFP_KERNEL
);
709 di
->bm
= &ab8500_bm_data
;
711 /* get parent data */
713 di
->parent
= dev_get_drvdata(pdev
->dev
.parent
);
715 /* Get thermal zone and ADC */
716 di
->tz
= thermal_zone_get_zone_by_name("battery-thermal");
717 if (IS_ERR(di
->tz
)) {
718 ret
= PTR_ERR(di
->tz
);
720 * This usually just means we are probing before the thermal
721 * zone, so just defer.
725 return dev_err_probe(dev
, ret
,
726 "failed to get battery thermal zone\n");
728 di
->bat_ctrl
= devm_iio_channel_get(dev
, "bat_ctrl");
729 if (IS_ERR(di
->bat_ctrl
)) {
730 ret
= dev_err_probe(dev
, PTR_ERR(di
->bat_ctrl
),
731 "failed to get BAT CTRL ADC channel\n");
735 di
->initialized
= false;
737 psy_cfg
.supplied_to
= supply_interface
;
738 psy_cfg
.num_supplicants
= ARRAY_SIZE(supply_interface
);
739 psy_cfg
.drv_data
= di
;
741 /* Init work for measuring temperature periodically */
742 INIT_DEFERRABLE_WORK(&di
->btemp_periodic_work
,
743 ab8500_btemp_periodic_work
);
745 /* Set BTEMP thermal limits. Low and Med are fixed */
746 di
->btemp_ranges
.btemp_low_limit
= BTEMP_THERMAL_LOW_LIMIT
;
747 di
->btemp_ranges
.btemp_med_limit
= BTEMP_THERMAL_MED_LIMIT
;
749 ret
= abx500_get_register_interruptible(dev
, AB8500_CHARGER
,
750 AB8500_BTEMP_HIGH_TH
, &val
);
752 dev_err(dev
, "%s ab8500 read failed\n", __func__
);
756 case BTEMP_HIGH_TH_57_0
:
757 case BTEMP_HIGH_TH_57_1
:
758 di
->btemp_ranges
.btemp_high_limit
=
759 BTEMP_THERMAL_HIGH_LIMIT_57
;
761 case BTEMP_HIGH_TH_52
:
762 di
->btemp_ranges
.btemp_high_limit
=
763 BTEMP_THERMAL_HIGH_LIMIT_52
;
765 case BTEMP_HIGH_TH_62
:
766 di
->btemp_ranges
.btemp_high_limit
=
767 BTEMP_THERMAL_HIGH_LIMIT_62
;
771 /* Register BTEMP power supply class */
772 di
->btemp_psy
= devm_power_supply_register(dev
, &ab8500_btemp_desc
,
774 if (IS_ERR(di
->btemp_psy
)) {
775 dev_err(dev
, "failed to register BTEMP psy\n");
776 return PTR_ERR(di
->btemp_psy
);
779 /* Register interrupts */
780 for (i
= 0; i
< ARRAY_SIZE(ab8500_btemp_irq
); i
++) {
781 irq
= platform_get_irq_byname(pdev
, ab8500_btemp_irq
[i
].name
);
785 ret
= devm_request_threaded_irq(dev
, irq
, NULL
,
786 ab8500_btemp_irq
[i
].isr
,
787 IRQF_SHARED
| IRQF_NO_SUSPEND
| IRQF_ONESHOT
,
788 ab8500_btemp_irq
[i
].name
, di
);
791 dev_err(dev
, "failed to request %s IRQ %d: %d\n"
792 , ab8500_btemp_irq
[i
].name
, irq
, ret
);
795 dev_dbg(dev
, "Requested %s IRQ %d: %d\n",
796 ab8500_btemp_irq
[i
].name
, irq
, ret
);
799 platform_set_drvdata(pdev
, di
);
801 list_add_tail(&di
->node
, &ab8500_btemp_list
);
803 return component_add(dev
, &ab8500_btemp_component_ops
);
806 static void ab8500_btemp_remove(struct platform_device
*pdev
)
808 component_del(&pdev
->dev
, &ab8500_btemp_component_ops
);
811 static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops
, ab8500_btemp_suspend
, ab8500_btemp_resume
);
813 static const struct of_device_id ab8500_btemp_match
[] = {
814 { .compatible
= "stericsson,ab8500-btemp", },
817 MODULE_DEVICE_TABLE(of
, ab8500_btemp_match
);
819 struct platform_driver ab8500_btemp_driver
= {
820 .probe
= ab8500_btemp_probe
,
821 .remove
= ab8500_btemp_remove
,
823 .name
= "ab8500-btemp",
824 .of_match_table
= ab8500_btemp_match
,
825 .pm
= &ab8500_btemp_pm_ops
,
828 MODULE_LICENSE("GPL v2");
829 MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
830 MODULE_ALIAS("platform:ab8500-btemp");
831 MODULE_DESCRIPTION("AB8500 battery temperature driver");