aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorArun Murthy <arun.murthy@stericsson.com>2012-02-29 11:24:28 -0500
committerAnton Vorontsov <anton.vorontsov@linaro.org>2012-03-26 12:41:06 -0400
commit1f855824757efab36e08f8fc640f4d9fd1d3d1ab (patch)
tree1ee096578f33d235f0088bd430b8d79eb3da5926 /drivers/power
parent13151631b5bd06a1511353bb221079bbd76606c3 (diff)
ab8500-btemp: AB8500 battery temperature driver
This driver is responsible for battery detection, obtaining battery temperature and monitor the battery temperature by taking precautionary measurements when battery temperature goes beyond or below the thresholds. Signed-off-by: Arun Murthy <arun.murthy@stericsson.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/Kconfig12
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/ab8500_btemp.c1123
3 files changed, 1136 insertions, 0 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index c728d26dca6c..11f928e4e5b5 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -281,4 +281,16 @@ config CHARGER_SMB347
281 Say Y to include support for Summit Microelectronics SMB347 281 Say Y to include support for Summit Microelectronics SMB347
282 Battery Charger. 282 Battery Charger.
283 283
284config AB8500_BM
285 bool "AB8500 Battery Management Driver"
286 depends on AB8500_CORE && AB8500_GPADC
287 help
288 Say Y to include support for AB5500 battery management.
289
290config AB8500_BATTERY_THERM_ON_BATCTRL
291 bool "Thermistor connected on BATCTRL ADC"
292 depends on AB8500_BM
293 help
294 Say Y to enable battery temperature measurements using
295 thermistor connected on BATCTRL ADC.
284endif # POWER_SUPPLY 296endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 894710e336f0..27d470d65685 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
33obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o 33obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
34obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o 34obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
35obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o 35obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
36obj-$(CONFIG_AB8500_BM) += ab8500_charger.o ab8500_btemp.o ab8500_fg.o abx500_chargalg.o
36obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o 37obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
37obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o 38obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
38obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o 39obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
new file mode 100644
index 000000000000..443bc7db30a0
--- /dev/null
+++ b/drivers/power/ab8500_btemp.c
@@ -0,0 +1,1123 @@
1/*
2 * Copyright (C) ST-Ericsson SA 2012
3 *
4 * Battery temperature driver for AB8500
5 *
6 * License Terms: GNU General Public License v2
7 * Author:
8 * Johan Palsson <johan.palsson@stericsson.com>
9 * Karl Komierowski <karl.komierowski@stericsson.com>
10 * Arun R Murthy <arun.murthy@stericsson.com>
11 */
12
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/interrupt.h>
17#include <linux/delay.h>
18#include <linux/slab.h>
19#include <linux/platform_device.h>
20#include <linux/power_supply.h>
21#include <linux/completion.h>
22#include <linux/workqueue.h>
23#include <linux/mfd/abx500/ab8500.h>
24#include <linux/mfd/abx500.h>
25#include <linux/mfd/abx500/ab8500-bm.h>
26#include <linux/mfd/abx500/ab8500-gpadc.h>
27#include <linux/jiffies.h>
28
29#define VTVOUT_V 1800
30
31#define BTEMP_THERMAL_LOW_LIMIT -10
32#define BTEMP_THERMAL_MED_LIMIT 0
33#define BTEMP_THERMAL_HIGH_LIMIT_52 52
34#define BTEMP_THERMAL_HIGH_LIMIT_57 57
35#define BTEMP_THERMAL_HIGH_LIMIT_62 62
36
37#define BTEMP_BATCTRL_CURR_SRC_7UA 7
38#define BTEMP_BATCTRL_CURR_SRC_20UA 20
39
40#define to_ab8500_btemp_device_info(x) container_of((x), \
41 struct ab8500_btemp, btemp_psy);
42
43/**
44 * struct ab8500_btemp_interrupts - ab8500 interrupts
45 * @name: name of the interrupt
46 * @isr function pointer to the isr
47 */
48struct ab8500_btemp_interrupts {
49 char *name;
50 irqreturn_t (*isr)(int irq, void *data);
51};
52
53struct ab8500_btemp_events {
54 bool batt_rem;
55 bool btemp_high;
56 bool btemp_medhigh;
57 bool btemp_lowmed;
58 bool btemp_low;
59 bool ac_conn;
60 bool usb_conn;
61};
62
63struct ab8500_btemp_ranges {
64 int btemp_high_limit;
65 int btemp_med_limit;
66 int btemp_low_limit;
67};
68
69/**
70 * struct ab8500_btemp - ab8500 BTEMP device information
71 * @dev: Pointer to the structure device
72 * @node: List of AB8500 BTEMPs, hence prepared for reentrance
73 * @curr_source: What current source we use, in uA
74 * @bat_temp: Battery temperature in degree Celcius
75 * @prev_bat_temp Last dispatched battery temperature
76 * @parent: Pointer to the struct ab8500
77 * @gpadc: Pointer to the struct gpadc
78 * @fg: Pointer to the struct fg
79 * @pdata: Pointer to the abx500_btemp platform data
80 * @bat: Pointer to the abx500_bm platform data
81 * @btemp_psy: Structure for BTEMP specific battery properties
82 * @events: Structure for information about events triggered
83 * @btemp_ranges: Battery temperature range structure
84 * @btemp_wq: Work queue for measuring the temperature periodically
85 * @btemp_periodic_work: Work for measuring the temperature periodically
86 */
87struct ab8500_btemp {
88 struct device *dev;
89 struct list_head node;
90 int curr_source;
91 int bat_temp;
92 int prev_bat_temp;
93 struct ab8500 *parent;
94 struct ab8500_gpadc *gpadc;
95 struct ab8500_fg *fg;
96 struct abx500_btemp_platform_data *pdata;
97 struct abx500_bm_data *bat;
98 struct power_supply btemp_psy;
99 struct ab8500_btemp_events events;
100 struct ab8500_btemp_ranges btemp_ranges;
101 struct workqueue_struct *btemp_wq;
102 struct delayed_work btemp_periodic_work;
103};
104
105/* BTEMP power supply properties */
106static enum power_supply_property ab8500_btemp_props[] = {
107 POWER_SUPPLY_PROP_PRESENT,
108 POWER_SUPPLY_PROP_ONLINE,
109 POWER_SUPPLY_PROP_TECHNOLOGY,
110 POWER_SUPPLY_PROP_TEMP,
111};
112
113static LIST_HEAD(ab8500_btemp_list);
114
115/**
116 * ab8500_btemp_get() - returns a reference to the primary AB8500 BTEMP
117 * (i.e. the first BTEMP in the instance list)
118 */
119struct ab8500_btemp *ab8500_btemp_get(void)
120{
121 struct ab8500_btemp *btemp;
122 btemp = list_first_entry(&ab8500_btemp_list, struct ab8500_btemp, node);
123
124 return btemp;
125}
126
127/**
128 * ab8500_btemp_batctrl_volt_to_res() - convert batctrl voltage to resistance
129 * @di: pointer to the ab8500_btemp structure
130 * @v_batctrl: measured batctrl voltage
131 * @inst_curr: measured instant current
132 *
133 * This function returns the battery resistance that is
134 * derived from the BATCTRL voltage.
135 * Returns value in Ohms.
136 */
137static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di,
138 int v_batctrl, int inst_curr)
139{
140 int rbs;
141
142 if (is_ab8500_1p1_or_earlier(di->parent)) {
143 /*
144 * For ABB cut1.0 and 1.1 BAT_CTRL is internally
145 * connected to 1.8V through a 450k resistor
146 */
147 return (450000 * (v_batctrl)) / (1800 - v_batctrl);
148 }
149
150 if (di->bat->adc_therm == ADC_THERM_BATCTRL) {
151 /*
152 * If the battery has internal NTC, we use the current
153 * source to calculate the resistance, 7uA or 20uA
154 */
155 rbs = (v_batctrl * 1000
156 - di->bat->gnd_lift_resistance * inst_curr)
157 / di->curr_source;
158 } else {
159 /*
160 * BAT_CTRL is internally
161 * connected to 1.8V through a 80k resistor
162 */
163 rbs = (80000 * (v_batctrl)) / (1800 - v_batctrl);
164 }
165
166 return rbs;
167}
168
169/**
170 * ab8500_btemp_read_batctrl_voltage() - measure batctrl voltage
171 * @di: pointer to the ab8500_btemp structure
172 *
173 * This function returns the voltage on BATCTRL. Returns value in mV.
174 */
175static int ab8500_btemp_read_batctrl_voltage(struct ab8500_btemp *di)
176{
177 int vbtemp;
178 static int prev;
179
180 vbtemp = ab8500_gpadc_convert(di->gpadc, BAT_CTRL);
181 if (vbtemp < 0) {
182 dev_err(di->dev,
183 "%s gpadc conversion failed, using previous value",
184 __func__);
185 return prev;
186 }
187 prev = vbtemp;
188 return vbtemp;
189}
190
191/**
192 * ab8500_btemp_curr_source_enable() - enable/disable batctrl current source
193 * @di: pointer to the ab8500_btemp structure
194 * @enable: enable or disable the current source
195 *
196 * Enable or disable the current sources for the BatCtrl AD channel
197 */
198static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
199 bool enable)
200{
201 int curr;
202 int ret = 0;
203
204 /*
205 * BATCTRL current sources are included on AB8500 cut2.0
206 * and future versions
207 */
208 if (is_ab8500_1p1_or_earlier(di->parent))
209 return 0;
210
211 /* Only do this for batteries with internal NTC */
212 if (di->bat->adc_therm == ADC_THERM_BATCTRL && enable) {
213 if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
214 curr = BAT_CTRL_7U_ENA;
215 else
216 curr = BAT_CTRL_20U_ENA;
217
218 dev_dbg(di->dev, "Set BATCTRL %duA\n", di->curr_source);
219
220 ret = abx500_mask_and_set_register_interruptible(di->dev,
221 AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
222 FORCE_BAT_CTRL_CMP_HIGH, FORCE_BAT_CTRL_CMP_HIGH);
223 if (ret) {
224 dev_err(di->dev, "%s failed setting cmp_force\n",
225 __func__);
226 return ret;
227 }
228
229 /*
230 * We have to wait one 32kHz cycle before enabling
231 * the current source, since ForceBatCtrlCmpHigh needs
232 * to be written in a separate cycle
233 */
234 udelay(32);
235
236 ret = abx500_set_register_interruptible(di->dev,
237 AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
238 FORCE_BAT_CTRL_CMP_HIGH | curr);
239 if (ret) {
240 dev_err(di->dev, "%s failed enabling current source\n",
241 __func__);
242 goto disable_curr_source;
243 }
244 } else if (di->bat->adc_therm == ADC_THERM_BATCTRL && !enable) {
245 dev_dbg(di->dev, "Disable BATCTRL curr source\n");
246
247 /* Write 0 to the curr bits */
248 ret = abx500_mask_and_set_register_interruptible(di->dev,
249 AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
250 BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
251 ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
252 if (ret) {
253 dev_err(di->dev, "%s failed disabling current source\n",
254 __func__);
255 goto disable_curr_source;
256 }
257
258 /* Enable Pull-Up and comparator */
259 ret = abx500_mask_and_set_register_interruptible(di->dev,
260 AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
261 BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA,
262 BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA);
263 if (ret) {
264 dev_err(di->dev, "%s failed enabling PU and comp\n",
265 __func__);
266 goto enable_pu_comp;
267 }
268
269 /*
270 * We have to wait one 32kHz cycle before disabling
271 * ForceBatCtrlCmpHigh since this needs to be written
272 * in a separate cycle
273 */
274 udelay(32);
275
276 /* Disable 'force comparator' */
277 ret = abx500_mask_and_set_register_interruptible(di->dev,
278 AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
279 FORCE_BAT_CTRL_CMP_HIGH, ~FORCE_BAT_CTRL_CMP_HIGH);
280 if (ret) {
281 dev_err(di->dev, "%s failed disabling force comp\n",
282 __func__);
283 goto disable_force_comp;
284 }
285 }
286 return ret;
287
288 /*
289 * We have to try unsetting FORCE_BAT_CTRL_CMP_HIGH one more time
290 * if we got an error above
291 */
292disable_curr_source:
293 /* Write 0 to the curr bits */
294 ret = abx500_mask_and_set_register_interruptible(di->dev,
295 AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
296 BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
297 ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
298 if (ret) {
299 dev_err(di->dev, "%s failed disabling current source\n",
300 __func__);
301 return ret;
302 }
303enable_pu_comp:
304 /* Enable Pull-Up and comparator */
305 ret = abx500_mask_and_set_register_interruptible(di->dev,
306 AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
307 BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA,
308 BAT_CTRL_PULL_UP_ENA | BAT_CTRL_CMP_ENA);
309 if (ret) {
310 dev_err(di->dev, "%s failed enabling PU and comp\n",
311 __func__);
312 return ret;
313 }
314
315disable_force_comp:
316 /*
317 * We have to wait one 32kHz cycle before disabling
318 * ForceBatCtrlCmpHigh since this needs to be written
319 * in a separate cycle
320 */
321 udelay(32);
322
323 /* Disable 'force comparator' */
324 ret = abx500_mask_and_set_register_interruptible(di->dev,
325 AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
326 FORCE_BAT_CTRL_CMP_HIGH, ~FORCE_BAT_CTRL_CMP_HIGH);
327 if (ret) {
328 dev_err(di->dev, "%s failed disabling force comp\n",
329 __func__);
330 return ret;
331 }
332
333 return ret;
334}
335
336/**
337 * ab8500_btemp_get_batctrl_res() - get battery resistance
338 * @di: pointer to the ab8500_btemp structure
339 *
340 * This function returns the battery pack identification resistance.
341 * Returns value in Ohms.
342 */
343static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di)
344{
345 int ret;
346 int batctrl = 0;
347 int res;
348 int inst_curr;
349 int i;
350
351 /*
352 * BATCTRL current sources are included on AB8500 cut2.0
353 * and future versions
354 */
355 ret = ab8500_btemp_curr_source_enable(di, true);
356 if (ret) {
357 dev_err(di->dev, "%s curr source enabled failed\n", __func__);
358 return ret;
359 }
360
361 if (!di->fg)
362 di->fg = ab8500_fg_get();
363 if (!di->fg) {
364 dev_err(di->dev, "No fg found\n");
365 return -EINVAL;
366 }
367
368 ret = ab8500_fg_inst_curr_start(di->fg);
369
370 if (ret) {
371 dev_err(di->dev, "Failed to start current measurement\n");
372 return ret;
373 }
374
375 /*
376 * Since there is no interrupt when current measurement is done,
377 * loop for over 250ms (250ms is one sample conversion time
378 * with 32.768 Khz RTC clock). Note that a stop time must be set
379 * since the ab8500_btemp_read_batctrl_voltage call can block and
380 * take an unknown amount of time to complete.
381 */
382 i = 0;
383
384 do {
385 batctrl += ab8500_btemp_read_batctrl_voltage(di);
386 i++;
387 msleep(20);
388 } while (!ab8500_fg_inst_curr_done(di->fg));
389 batctrl /= i;
390
391 ret = ab8500_fg_inst_curr_finalize(di->fg, &inst_curr);
392 if (ret) {
393 dev_err(di->dev, "Failed to finalize current measurement\n");
394 return ret;
395 }
396
397 res = ab8500_btemp_batctrl_volt_to_res(di, batctrl, inst_curr);
398
399 ret = ab8500_btemp_curr_source_enable(di, false);
400 if (ret) {
401 dev_err(di->dev, "%s curr source disable failed\n", __func__);
402 return ret;
403 }
404
405 dev_dbg(di->dev, "%s batctrl: %d res: %d inst_curr: %d samples: %d\n",
406 __func__, batctrl, res, inst_curr, i);
407
408 return res;
409}
410
411/**
412 * ab8500_btemp_res_to_temp() - resistance to temperature
413 * @di: pointer to the ab8500_btemp structure
414 * @tbl: pointer to the resiatance to temperature table
415 * @tbl_size: size of the resistance to temperature table
416 * @res: resistance to calculate the temperature from
417 *
418 * This function returns the battery temperature in degrees Celcius
419 * based on the NTC resistance.
420 */
421static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
422 const struct abx500_res_to_temp *tbl, int tbl_size, int res)
423{
424 int i, temp;
425 /*
426 * Calculate the formula for the straight line
427 * Simple interpolation if we are within
428 * the resistance table limits, extrapolate
429 * if resistance is outside the limits.
430 */
431 if (res > tbl[0].resist)
432 i = 0;
433 else if (res <= tbl[tbl_size - 1].resist)
434 i = tbl_size - 2;
435 else {
436 i = 0;
437 while (!(res <= tbl[i].resist &&
438 res > tbl[i + 1].resist))
439 i++;
440 }
441
442 temp = tbl[i].temp + ((tbl[i + 1].temp - tbl[i].temp) *
443 (res - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist);
444 return temp;
445}
446
447/**
448 * ab8500_btemp_measure_temp() - measure battery temperature
449 * @di: pointer to the ab8500_btemp structure
450 *
451 * Returns battery temperature (on success) else the previous temperature
452 */
453static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
454{
455 int temp;
456 static int prev;
457 int rbat, rntc, vntc;
458 u8 id;
459
460 id = di->bat->batt_id;
461
462 if (di->bat->adc_therm == ADC_THERM_BATCTRL &&
463 id != BATTERY_UNKNOWN) {
464
465 rbat = ab8500_btemp_get_batctrl_res(di);
466 if (rbat < 0) {
467 dev_err(di->dev, "%s get batctrl res failed\n",
468 __func__);
469 /*
470 * Return out-of-range temperature so that
471 * charging is stopped
472 */
473 return BTEMP_THERMAL_LOW_LIMIT;
474 }
475
476 temp = ab8500_btemp_res_to_temp(di,
477 di->bat->bat_type[id].r_to_t_tbl,
478 di->bat->bat_type[id].n_temp_tbl_elements, rbat);
479 } else {
480 vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL);
481 if (vntc < 0) {
482 dev_err(di->dev,
483 "%s gpadc conversion failed,"
484 " using previous value\n", __func__);
485 return prev;
486 }
487 /*
488 * The PCB NTC is sourced from VTVOUT via a 230kOhm
489 * resistor.
490 */
491 rntc = 230000 * vntc / (VTVOUT_V - vntc);
492
493 temp = ab8500_btemp_res_to_temp(di,
494 di->bat->bat_type[id].r_to_t_tbl,
495 di->bat->bat_type[id].n_temp_tbl_elements, rntc);
496 prev = temp;
497 }
498 dev_dbg(di->dev, "Battery temperature is %d\n", temp);
499 return temp;
500}
501
502/**
503 * ab8500_btemp_id() - Identify the connected battery
504 * @di: pointer to the ab8500_btemp structure
505 *
506 * This function will try to identify the battery by reading the ID
507 * resistor. Some brands use a combined ID resistor with a NTC resistor to
508 * both be able to identify and to read the temperature of it.
509 */
510static int ab8500_btemp_id(struct ab8500_btemp *di)
511{
512 int res;
513 u8 i;
514
515 di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;
516 di->bat->batt_id = BATTERY_UNKNOWN;
517
518 res = ab8500_btemp_get_batctrl_res(di);
519 if (res < 0) {
520 dev_err(di->dev, "%s get batctrl res failed\n", __func__);
521 return -ENXIO;
522 }
523
524 /* BATTERY_UNKNOWN is defined on position 0, skip it! */
525 for (i = BATTERY_UNKNOWN + 1; i < di->bat->n_btypes; i++) {
526 if ((res <= di->bat->bat_type[i].resis_high) &&
527 (res >= di->bat->bat_type[i].resis_low)) {
528 dev_dbg(di->dev, "Battery detected on %s"
529 " low %d < res %d < high: %d"
530 " index: %d\n",
531 di->bat->adc_therm == ADC_THERM_BATCTRL ?
532 "BATCTRL" : "BATTEMP",
533 di->bat->bat_type[i].resis_low, res,
534 di->bat->bat_type[i].resis_high, i);
535
536 di->bat->batt_id = i;
537 break;
538 }
539 }
540
541 if (di->bat->batt_id == BATTERY_UNKNOWN) {
542 dev_warn(di->dev, "Battery identified as unknown"
543 ", resistance %d Ohm\n", res);
544 return -ENXIO;
545 }
546
547 /*
548 * We only have to change current source if the
549 * detected type is Type 1, else we use the 7uA source
550 */
551 if (di->bat->adc_therm == ADC_THERM_BATCTRL && di->bat->batt_id == 1) {
552 dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
553 di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA;
554 }
555
556 return di->bat->batt_id;
557}
558
559/**
560 * ab8500_btemp_periodic_work() - Measuring the temperature periodically
561 * @work: pointer to the work_struct structure
562 *
563 * Work function for measuring the temperature periodically
564 */
565static void ab8500_btemp_periodic_work(struct work_struct *work)
566{
567 int interval;
568 struct ab8500_btemp *di = container_of(work,
569 struct ab8500_btemp, btemp_periodic_work.work);
570
571 di->bat_temp = ab8500_btemp_measure_temp(di);
572
573 if (di->bat_temp != di->prev_bat_temp) {
574 di->prev_bat_temp = di->bat_temp;
575 power_supply_changed(&di->btemp_psy);
576 }
577
578 if (di->events.ac_conn || di->events.usb_conn)
579 interval = di->bat->temp_interval_chg;
580 else
581 interval = di->bat->temp_interval_nochg;
582
583 /* Schedule a new measurement */
584 queue_delayed_work(di->btemp_wq,
585 &di->btemp_periodic_work,
586 round_jiffies(interval * HZ));
587}
588
589/**
590 * ab8500_btemp_batctrlindb_handler() - battery removal detected
591 * @irq: interrupt number
592 * @_di: void pointer that has to address of ab8500_btemp
593 *
594 * Returns IRQ status(IRQ_HANDLED)
595 */
596static irqreturn_t ab8500_btemp_batctrlindb_handler(int irq, void *_di)
597{
598 struct ab8500_btemp *di = _di;
599 dev_err(di->dev, "Battery removal detected!\n");
600
601 di->events.batt_rem = true;
602 power_supply_changed(&di->btemp_psy);
603
604 return IRQ_HANDLED;
605}
606
607/**
608 * ab8500_btemp_templow_handler() - battery temp lower than 10 degrees
609 * @irq: interrupt number
610 * @_di: void pointer that has to address of ab8500_btemp
611 *
612 * Returns IRQ status(IRQ_HANDLED)
613 */
614static irqreturn_t ab8500_btemp_templow_handler(int irq, void *_di)
615{
616 struct ab8500_btemp *di = _di;
617
618 if (is_ab8500_2p0_or_earlier(di->parent)) {
619 dev_dbg(di->dev, "Ignore false btemp low irq"
620 " for ABB cut 1.0, 1.1 and 2.0\n");
621 } else {
622 dev_crit(di->dev, "Battery temperature lower than -10deg c\n");
623
624 di->events.btemp_low = true;
625 di->events.btemp_high = false;
626 di->events.btemp_medhigh = false;
627 di->events.btemp_lowmed = false;
628 power_supply_changed(&di->btemp_psy);
629 }
630
631 return IRQ_HANDLED;
632}
633
634/**
635 * ab8500_btemp_temphigh_handler() - battery temp higher than max temp
636 * @irq: interrupt number
637 * @_di: void pointer that has to address of ab8500_btemp
638 *
639 * Returns IRQ status(IRQ_HANDLED)
640 */
641static irqreturn_t ab8500_btemp_temphigh_handler(int irq, void *_di)
642{
643 struct ab8500_btemp *di = _di;
644
645 dev_crit(di->dev, "Battery temperature is higher than MAX temp\n");
646
647 di->events.btemp_high = true;
648 di->events.btemp_medhigh = false;
649 di->events.btemp_lowmed = false;
650 di->events.btemp_low = false;
651 power_supply_changed(&di->btemp_psy);
652
653 return IRQ_HANDLED;
654}
655
656/**
657 * ab8500_btemp_lowmed_handler() - battery temp between low and medium
658 * @irq: interrupt number
659 * @_di: void pointer that has to address of ab8500_btemp
660 *
661 * Returns IRQ status(IRQ_HANDLED)
662 */
663static irqreturn_t ab8500_btemp_lowmed_handler(int irq, void *_di)
664{
665 struct ab8500_btemp *di = _di;
666
667 dev_dbg(di->dev, "Battery temperature is between low and medium\n");
668
669 di->events.btemp_lowmed = true;
670 di->events.btemp_medhigh = false;
671 di->events.btemp_high = false;
672 di->events.btemp_low = false;
673 power_supply_changed(&di->btemp_psy);
674
675 return IRQ_HANDLED;
676}
677
678/**
679 * ab8500_btemp_medhigh_handler() - battery temp between medium and high
680 * @irq: interrupt number
681 * @_di: void pointer that has to address of ab8500_btemp
682 *
683 * Returns IRQ status(IRQ_HANDLED)
684 */
685static irqreturn_t ab8500_btemp_medhigh_handler(int irq, void *_di)
686{
687 struct ab8500_btemp *di = _di;
688
689 dev_dbg(di->dev, "Battery temperature is between medium and high\n");
690
691 di->events.btemp_medhigh = true;
692 di->events.btemp_lowmed = false;
693 di->events.btemp_high = false;
694 di->events.btemp_low = false;
695 power_supply_changed(&di->btemp_psy);
696
697 return IRQ_HANDLED;
698}
699
700/**
701 * ab8500_btemp_periodic() - Periodic temperature measurements
702 * @di: pointer to the ab8500_btemp structure
703 * @enable: enable or disable periodic temperature measurements
704 *
705 * Starts of stops periodic temperature measurements. Periodic measurements
706 * should only be done when a charger is connected.
707 */
708static void ab8500_btemp_periodic(struct ab8500_btemp *di,
709 bool enable)
710{
711 dev_dbg(di->dev, "Enable periodic temperature measurements: %d\n",
712 enable);
713 /*
714 * Make sure a new measurement is done directly by cancelling
715 * any pending work
716 */
717 cancel_delayed_work_sync(&di->btemp_periodic_work);
718
719 if (enable)
720 queue_delayed_work(di->btemp_wq, &di->btemp_periodic_work, 0);
721}
722
723/**
724 * ab8500_btemp_get_temp() - get battery temperature
725 * @di: pointer to the ab8500_btemp structure
726 *
727 * Returns battery temperature
728 */
729static int ab8500_btemp_get_temp(struct ab8500_btemp *di)
730{
731 int temp = 0;
732
733 /*
734 * The BTEMP events are not reliabe on AB8500 cut2.0
735 * and prior versions
736 */
737 if (is_ab8500_2p0_or_earlier(di->parent)) {
738 temp = di->bat_temp * 10;
739 } else {
740 if (di->events.btemp_low) {
741 if (temp > di->btemp_ranges.btemp_low_limit)
742 temp = di->btemp_ranges.btemp_low_limit;
743 else
744 temp = di->bat_temp * 10;
745 } else if (di->events.btemp_high) {
746 if (temp < di->btemp_ranges.btemp_high_limit)
747 temp = di->btemp_ranges.btemp_high_limit;
748 else
749 temp = di->bat_temp * 10;
750 } else if (di->events.btemp_lowmed) {
751 if (temp > di->btemp_ranges.btemp_med_limit)
752 temp = di->btemp_ranges.btemp_med_limit;
753 else
754 temp = di->bat_temp * 10;
755 } else if (di->events.btemp_medhigh) {
756 if (temp < di->btemp_ranges.btemp_med_limit)
757 temp = di->btemp_ranges.btemp_med_limit;
758 else
759 temp = di->bat_temp * 10;
760 } else
761 temp = di->bat_temp * 10;
762 }
763 return temp;
764}
765
766/**
767 * ab8500_btemp_get_batctrl_temp() - get the temperature
768 * @btemp: pointer to the btemp structure
769 *
770 * Returns the batctrl temperature in millidegrees
771 */
772int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp)
773{
774 return btemp->bat_temp * 1000;
775}
776
777/**
778 * ab8500_btemp_get_property() - get the btemp properties
779 * @psy: pointer to the power_supply structure
780 * @psp: pointer to the power_supply_property structure
781 * @val: pointer to the power_supply_propval union
782 *
783 * This function gets called when an application tries to get the btemp
784 * properties by reading the sysfs files.
785 * online: presence of the battery
786 * present: presence of the battery
787 * technology: battery technology
788 * temp: battery temperature
789 * Returns error code in case of failure else 0(on success)
790 */
791static int ab8500_btemp_get_property(struct power_supply *psy,
792 enum power_supply_property psp,
793 union power_supply_propval *val)
794{
795 struct ab8500_btemp *di;
796
797 di = to_ab8500_btemp_device_info(psy);
798
799 switch (psp) {
800 case POWER_SUPPLY_PROP_PRESENT:
801 case POWER_SUPPLY_PROP_ONLINE:
802 if (di->events.batt_rem)
803 val->intval = 0;
804 else
805 val->intval = 1;
806 break;
807 case POWER_SUPPLY_PROP_TECHNOLOGY:
808 val->intval = di->bat->bat_type[di->bat->batt_id].name;
809 break;
810 case POWER_SUPPLY_PROP_TEMP:
811 val->intval = ab8500_btemp_get_temp(di);
812 break;
813 default:
814 return -EINVAL;
815 }
816 return 0;
817}
818
819static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data)
820{
821 struct power_supply *psy;
822 struct power_supply *ext;
823 struct ab8500_btemp *di;
824 union power_supply_propval ret;
825 int i, j;
826 bool psy_found = false;
827
828 psy = (struct power_supply *)data;
829 ext = dev_get_drvdata(dev);
830 di = to_ab8500_btemp_device_info(psy);
831
832 /*
833 * For all psy where the name of your driver
834 * appears in any supplied_to
835 */
836 for (i = 0; i < ext->num_supplicants; i++) {
837 if (!strcmp(ext->supplied_to[i], psy->name))
838 psy_found = true;
839 }
840
841 if (!psy_found)
842 return 0;
843
844 /* Go through all properties for the psy */
845 for (j = 0; j < ext->num_properties; j++) {
846 enum power_supply_property prop;
847 prop = ext->properties[j];
848
849 if (ext->get_property(ext, prop, &ret))
850 continue;
851
852 switch (prop) {
853 case POWER_SUPPLY_PROP_PRESENT:
854 switch (ext->type) {
855 case POWER_SUPPLY_TYPE_MAINS:
856 /* AC disconnected */
857 if (!ret.intval && di->events.ac_conn) {
858 di->events.ac_conn = false;
859 }
860 /* AC connected */
861 else if (ret.intval && !di->events.ac_conn) {
862 di->events.ac_conn = true;
863 if (!di->events.usb_conn)
864 ab8500_btemp_periodic(di, true);
865 }
866 break;
867 case POWER_SUPPLY_TYPE_USB:
868 /* USB disconnected */
869 if (!ret.intval && di->events.usb_conn) {
870 di->events.usb_conn = false;
871 }
872 /* USB connected */
873 else if (ret.intval && !di->events.usb_conn) {
874 di->events.usb_conn = true;
875 if (!di->events.ac_conn)
876 ab8500_btemp_periodic(di, true);
877 }
878 break;
879 default:
880 break;
881 }
882 break;
883 default:
884 break;
885 }
886 }
887 return 0;
888}
889
890/**
891 * ab8500_btemp_external_power_changed() - callback for power supply changes
892 * @psy: pointer to the structure power_supply
893 *
894 * This function is pointing to the function pointer external_power_changed
895 * of the structure power_supply.
896 * This function gets executed when there is a change in the external power
897 * supply to the btemp.
898 */
899static void ab8500_btemp_external_power_changed(struct power_supply *psy)
900{
901 struct ab8500_btemp *di = to_ab8500_btemp_device_info(psy);
902
903 class_for_each_device(power_supply_class, NULL,
904 &di->btemp_psy, ab8500_btemp_get_ext_psy_data);
905}
906
907/* ab8500 btemp driver interrupts and their respective isr */
908static struct ab8500_btemp_interrupts ab8500_btemp_irq[] = {
909 {"BAT_CTRL_INDB", ab8500_btemp_batctrlindb_handler},
910 {"BTEMP_LOW", ab8500_btemp_templow_handler},
911 {"BTEMP_HIGH", ab8500_btemp_temphigh_handler},
912 {"BTEMP_LOW_MEDIUM", ab8500_btemp_lowmed_handler},
913 {"BTEMP_MEDIUM_HIGH", ab8500_btemp_medhigh_handler},
914};
915
916#if defined(CONFIG_PM)
917static int ab8500_btemp_resume(struct platform_device *pdev)
918{
919 struct ab8500_btemp *di = platform_get_drvdata(pdev);
920
921 ab8500_btemp_periodic(di, true);
922
923 return 0;
924}
925
926static int ab8500_btemp_suspend(struct platform_device *pdev,
927 pm_message_t state)
928{
929 struct ab8500_btemp *di = platform_get_drvdata(pdev);
930
931 ab8500_btemp_periodic(di, false);
932
933 return 0;
934}
935#else
936#define ab8500_btemp_suspend NULL
937#define ab8500_btemp_resume NULL
938#endif
939
940static int __devexit ab8500_btemp_remove(struct platform_device *pdev)
941{
942 struct ab8500_btemp *di = platform_get_drvdata(pdev);
943 int i, irq;
944
945 /* Disable interrupts */
946 for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
947 irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
948 free_irq(irq, di);
949 }
950
951 /* Delete the work queue */
952 destroy_workqueue(di->btemp_wq);
953
954 flush_scheduled_work();
955 power_supply_unregister(&di->btemp_psy);
956 platform_set_drvdata(pdev, NULL);
957 kfree(di);
958
959 return 0;
960}
961
962static int __devinit ab8500_btemp_probe(struct platform_device *pdev)
963{
964 int irq, i, ret = 0;
965 u8 val;
966 struct abx500_bm_plat_data *plat_data;
967
968 struct ab8500_btemp *di =
969 kzalloc(sizeof(struct ab8500_btemp), GFP_KERNEL);
970 if (!di)
971 return -ENOMEM;
972
973 /* get parent data */
974 di->dev = &pdev->dev;
975 di->parent = dev_get_drvdata(pdev->dev.parent);
976 di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
977
978 /* get btemp specific platform data */
979 plat_data = pdev->dev.platform_data;
980 di->pdata = plat_data->btemp;
981 if (!di->pdata) {
982 dev_err(di->dev, "no btemp platform data supplied\n");
983 ret = -EINVAL;
984 goto free_device_info;
985 }
986
987 /* get battery specific platform data */
988 di->bat = plat_data->battery;
989 if (!di->bat) {
990 dev_err(di->dev, "no battery platform data supplied\n");
991 ret = -EINVAL;
992 goto free_device_info;
993 }
994
995 /* BTEMP supply */
996 di->btemp_psy.name = "ab8500_btemp";
997 di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY;
998 di->btemp_psy.properties = ab8500_btemp_props;
999 di->btemp_psy.num_properties = ARRAY_SIZE(ab8500_btemp_props);
1000 di->btemp_psy.get_property = ab8500_btemp_get_property;
1001 di->btemp_psy.supplied_to = di->pdata->supplied_to;
1002 di->btemp_psy.num_supplicants = di->pdata->num_supplicants;
1003 di->btemp_psy.external_power_changed =
1004 ab8500_btemp_external_power_changed;
1005
1006
1007 /* Create a work queue for the btemp */
1008 di->btemp_wq =
1009 create_singlethread_workqueue("ab8500_btemp_wq");
1010 if (di->btemp_wq == NULL) {
1011 dev_err(di->dev, "failed to create work queue\n");
1012 goto free_device_info;
1013 }
1014
1015 /* Init work for measuring temperature periodically */
1016 INIT_DELAYED_WORK_DEFERRABLE(&di->btemp_periodic_work,
1017 ab8500_btemp_periodic_work);
1018
1019 /* Identify the battery */
1020 if (ab8500_btemp_id(di) < 0)
1021 dev_warn(di->dev, "failed to identify the battery\n");
1022
1023 /* Set BTEMP thermal limits. Low and Med are fixed */
1024 di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
1025 di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
1026
1027 ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
1028 AB8500_BTEMP_HIGH_TH, &val);
1029 if (ret < 0) {
1030 dev_err(di->dev, "%s ab8500 read failed\n", __func__);
1031 goto free_btemp_wq;
1032 }
1033 switch (val) {
1034 case BTEMP_HIGH_TH_57_0:
1035 case BTEMP_HIGH_TH_57_1:
1036 di->btemp_ranges.btemp_high_limit =
1037 BTEMP_THERMAL_HIGH_LIMIT_57;
1038 break;
1039 case BTEMP_HIGH_TH_52:
1040 di->btemp_ranges.btemp_high_limit =
1041 BTEMP_THERMAL_HIGH_LIMIT_52;
1042 break;
1043 case BTEMP_HIGH_TH_62:
1044 di->btemp_ranges.btemp_high_limit =
1045 BTEMP_THERMAL_HIGH_LIMIT_62;
1046 break;
1047 }
1048
1049 /* Register BTEMP power supply class */
1050 ret = power_supply_register(di->dev, &di->btemp_psy);
1051 if (ret) {
1052 dev_err(di->dev, "failed to register BTEMP psy\n");
1053 goto free_btemp_wq;
1054 }
1055
1056 /* Register interrupts */
1057 for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
1058 irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
1059 ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr,
1060 IRQF_SHARED | IRQF_NO_SUSPEND,
1061 ab8500_btemp_irq[i].name, di);
1062
1063 if (ret) {
1064 dev_err(di->dev, "failed to request %s IRQ %d: %d\n"
1065 , ab8500_btemp_irq[i].name, irq, ret);
1066 goto free_irq;
1067 }
1068 dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
1069 ab8500_btemp_irq[i].name, irq, ret);
1070 }
1071
1072 platform_set_drvdata(pdev, di);
1073
1074 /* Kick off periodic temperature measurements */
1075 ab8500_btemp_periodic(di, true);
1076 list_add_tail(&di->node, &ab8500_btemp_list);
1077
1078 return ret;
1079
1080free_irq:
1081 power_supply_unregister(&di->btemp_psy);
1082
1083 /* We also have to free all successfully registered irqs */
1084 for (i = i - 1; i >= 0; i--) {
1085 irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
1086 free_irq(irq, di);
1087 }
1088free_btemp_wq:
1089 destroy_workqueue(di->btemp_wq);
1090free_device_info:
1091 kfree(di);
1092
1093 return ret;
1094}
1095
1096static struct platform_driver ab8500_btemp_driver = {
1097 .probe = ab8500_btemp_probe,
1098 .remove = __devexit_p(ab8500_btemp_remove),
1099 .suspend = ab8500_btemp_suspend,
1100 .resume = ab8500_btemp_resume,
1101 .driver = {
1102 .name = "ab8500-btemp",
1103 .owner = THIS_MODULE,
1104 },
1105};
1106
1107static int __init ab8500_btemp_init(void)
1108{
1109 return platform_driver_register(&ab8500_btemp_driver);
1110}
1111
1112static void __exit ab8500_btemp_exit(void)
1113{
1114 platform_driver_unregister(&ab8500_btemp_driver);
1115}
1116
1117subsys_initcall_sync(ab8500_btemp_init);
1118module_exit(ab8500_btemp_exit);
1119
1120MODULE_LICENSE("GPL v2");
1121MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy");
1122MODULE_ALIAS("platform:ab8500-btemp");
1123MODULE_DESCRIPTION("AB8500 battery temperature driver");