diff options
Diffstat (limited to 'drivers/power/ab8500_btemp.c')
-rw-r--r-- | drivers/power/ab8500_btemp.c | 1124 |
1 files changed, 1124 insertions, 0 deletions
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c new file mode 100644 index 000000000000..d8bb99394ac0 --- /dev/null +++ b/drivers/power/ab8500_btemp.c | |||
@@ -0,0 +1,1124 @@ | |||
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 | */ | ||
48 | struct ab8500_btemp_interrupts { | ||
49 | char *name; | ||
50 | irqreturn_t (*isr)(int irq, void *data); | ||
51 | }; | ||
52 | |||
53 | struct 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 | |||
63 | struct 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 | */ | ||
87 | struct 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 */ | ||
106 | static 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 | |||
113 | static 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 | */ | ||
119 | struct 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 | */ | ||
137 | static 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 == ABx500_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 | */ | ||
175 | static 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 | */ | ||
198 | static 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 == ABx500_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 == ABx500_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 | */ | ||
292 | disable_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 | } | ||
303 | enable_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 | |||
315 | disable_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 | */ | ||
343 | static 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 | */ | ||
421 | static 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 | */ | ||
453 | static 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 == ABx500_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 | */ | ||
510 | static 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 == ABx500_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 == ABx500_ADC_THERM_BATCTRL && | ||
552 | di->bat->batt_id == 1) { | ||
553 | dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); | ||
554 | di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; | ||
555 | } | ||
556 | |||
557 | return di->bat->batt_id; | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * ab8500_btemp_periodic_work() - Measuring the temperature periodically | ||
562 | * @work: pointer to the work_struct structure | ||
563 | * | ||
564 | * Work function for measuring the temperature periodically | ||
565 | */ | ||
566 | static void ab8500_btemp_periodic_work(struct work_struct *work) | ||
567 | { | ||
568 | int interval; | ||
569 | struct ab8500_btemp *di = container_of(work, | ||
570 | struct ab8500_btemp, btemp_periodic_work.work); | ||
571 | |||
572 | di->bat_temp = ab8500_btemp_measure_temp(di); | ||
573 | |||
574 | if (di->bat_temp != di->prev_bat_temp) { | ||
575 | di->prev_bat_temp = di->bat_temp; | ||
576 | power_supply_changed(&di->btemp_psy); | ||
577 | } | ||
578 | |||
579 | if (di->events.ac_conn || di->events.usb_conn) | ||
580 | interval = di->bat->temp_interval_chg; | ||
581 | else | ||
582 | interval = di->bat->temp_interval_nochg; | ||
583 | |||
584 | /* Schedule a new measurement */ | ||
585 | queue_delayed_work(di->btemp_wq, | ||
586 | &di->btemp_periodic_work, | ||
587 | round_jiffies(interval * HZ)); | ||
588 | } | ||
589 | |||
590 | /** | ||
591 | * ab8500_btemp_batctrlindb_handler() - battery removal detected | ||
592 | * @irq: interrupt number | ||
593 | * @_di: void pointer that has to address of ab8500_btemp | ||
594 | * | ||
595 | * Returns IRQ status(IRQ_HANDLED) | ||
596 | */ | ||
597 | static irqreturn_t ab8500_btemp_batctrlindb_handler(int irq, void *_di) | ||
598 | { | ||
599 | struct ab8500_btemp *di = _di; | ||
600 | dev_err(di->dev, "Battery removal detected!\n"); | ||
601 | |||
602 | di->events.batt_rem = true; | ||
603 | power_supply_changed(&di->btemp_psy); | ||
604 | |||
605 | return IRQ_HANDLED; | ||
606 | } | ||
607 | |||
608 | /** | ||
609 | * ab8500_btemp_templow_handler() - battery temp lower than 10 degrees | ||
610 | * @irq: interrupt number | ||
611 | * @_di: void pointer that has to address of ab8500_btemp | ||
612 | * | ||
613 | * Returns IRQ status(IRQ_HANDLED) | ||
614 | */ | ||
615 | static irqreturn_t ab8500_btemp_templow_handler(int irq, void *_di) | ||
616 | { | ||
617 | struct ab8500_btemp *di = _di; | ||
618 | |||
619 | if (is_ab8500_2p0_or_earlier(di->parent)) { | ||
620 | dev_dbg(di->dev, "Ignore false btemp low irq" | ||
621 | " for ABB cut 1.0, 1.1 and 2.0\n"); | ||
622 | } else { | ||
623 | dev_crit(di->dev, "Battery temperature lower than -10deg c\n"); | ||
624 | |||
625 | di->events.btemp_low = true; | ||
626 | di->events.btemp_high = false; | ||
627 | di->events.btemp_medhigh = false; | ||
628 | di->events.btemp_lowmed = false; | ||
629 | power_supply_changed(&di->btemp_psy); | ||
630 | } | ||
631 | |||
632 | return IRQ_HANDLED; | ||
633 | } | ||
634 | |||
635 | /** | ||
636 | * ab8500_btemp_temphigh_handler() - battery temp higher than max temp | ||
637 | * @irq: interrupt number | ||
638 | * @_di: void pointer that has to address of ab8500_btemp | ||
639 | * | ||
640 | * Returns IRQ status(IRQ_HANDLED) | ||
641 | */ | ||
642 | static irqreturn_t ab8500_btemp_temphigh_handler(int irq, void *_di) | ||
643 | { | ||
644 | struct ab8500_btemp *di = _di; | ||
645 | |||
646 | dev_crit(di->dev, "Battery temperature is higher than MAX temp\n"); | ||
647 | |||
648 | di->events.btemp_high = true; | ||
649 | di->events.btemp_medhigh = false; | ||
650 | di->events.btemp_lowmed = false; | ||
651 | di->events.btemp_low = false; | ||
652 | power_supply_changed(&di->btemp_psy); | ||
653 | |||
654 | return IRQ_HANDLED; | ||
655 | } | ||
656 | |||
657 | /** | ||
658 | * ab8500_btemp_lowmed_handler() - battery temp between low and medium | ||
659 | * @irq: interrupt number | ||
660 | * @_di: void pointer that has to address of ab8500_btemp | ||
661 | * | ||
662 | * Returns IRQ status(IRQ_HANDLED) | ||
663 | */ | ||
664 | static irqreturn_t ab8500_btemp_lowmed_handler(int irq, void *_di) | ||
665 | { | ||
666 | struct ab8500_btemp *di = _di; | ||
667 | |||
668 | dev_dbg(di->dev, "Battery temperature is between low and medium\n"); | ||
669 | |||
670 | di->events.btemp_lowmed = true; | ||
671 | di->events.btemp_medhigh = false; | ||
672 | di->events.btemp_high = false; | ||
673 | di->events.btemp_low = false; | ||
674 | power_supply_changed(&di->btemp_psy); | ||
675 | |||
676 | return IRQ_HANDLED; | ||
677 | } | ||
678 | |||
679 | /** | ||
680 | * ab8500_btemp_medhigh_handler() - battery temp between medium and high | ||
681 | * @irq: interrupt number | ||
682 | * @_di: void pointer that has to address of ab8500_btemp | ||
683 | * | ||
684 | * Returns IRQ status(IRQ_HANDLED) | ||
685 | */ | ||
686 | static irqreturn_t ab8500_btemp_medhigh_handler(int irq, void *_di) | ||
687 | { | ||
688 | struct ab8500_btemp *di = _di; | ||
689 | |||
690 | dev_dbg(di->dev, "Battery temperature is between medium and high\n"); | ||
691 | |||
692 | di->events.btemp_medhigh = true; | ||
693 | di->events.btemp_lowmed = false; | ||
694 | di->events.btemp_high = false; | ||
695 | di->events.btemp_low = false; | ||
696 | power_supply_changed(&di->btemp_psy); | ||
697 | |||
698 | return IRQ_HANDLED; | ||
699 | } | ||
700 | |||
701 | /** | ||
702 | * ab8500_btemp_periodic() - Periodic temperature measurements | ||
703 | * @di: pointer to the ab8500_btemp structure | ||
704 | * @enable: enable or disable periodic temperature measurements | ||
705 | * | ||
706 | * Starts of stops periodic temperature measurements. Periodic measurements | ||
707 | * should only be done when a charger is connected. | ||
708 | */ | ||
709 | static void ab8500_btemp_periodic(struct ab8500_btemp *di, | ||
710 | bool enable) | ||
711 | { | ||
712 | dev_dbg(di->dev, "Enable periodic temperature measurements: %d\n", | ||
713 | enable); | ||
714 | /* | ||
715 | * Make sure a new measurement is done directly by cancelling | ||
716 | * any pending work | ||
717 | */ | ||
718 | cancel_delayed_work_sync(&di->btemp_periodic_work); | ||
719 | |||
720 | if (enable) | ||
721 | queue_delayed_work(di->btemp_wq, &di->btemp_periodic_work, 0); | ||
722 | } | ||
723 | |||
724 | /** | ||
725 | * ab8500_btemp_get_temp() - get battery temperature | ||
726 | * @di: pointer to the ab8500_btemp structure | ||
727 | * | ||
728 | * Returns battery temperature | ||
729 | */ | ||
730 | static int ab8500_btemp_get_temp(struct ab8500_btemp *di) | ||
731 | { | ||
732 | int temp = 0; | ||
733 | |||
734 | /* | ||
735 | * The BTEMP events are not reliabe on AB8500 cut2.0 | ||
736 | * and prior versions | ||
737 | */ | ||
738 | if (is_ab8500_2p0_or_earlier(di->parent)) { | ||
739 | temp = di->bat_temp * 10; | ||
740 | } else { | ||
741 | if (di->events.btemp_low) { | ||
742 | if (temp > di->btemp_ranges.btemp_low_limit) | ||
743 | temp = di->btemp_ranges.btemp_low_limit; | ||
744 | else | ||
745 | temp = di->bat_temp * 10; | ||
746 | } else if (di->events.btemp_high) { | ||
747 | if (temp < di->btemp_ranges.btemp_high_limit) | ||
748 | temp = di->btemp_ranges.btemp_high_limit; | ||
749 | else | ||
750 | temp = di->bat_temp * 10; | ||
751 | } else if (di->events.btemp_lowmed) { | ||
752 | if (temp > di->btemp_ranges.btemp_med_limit) | ||
753 | temp = di->btemp_ranges.btemp_med_limit; | ||
754 | else | ||
755 | temp = di->bat_temp * 10; | ||
756 | } else if (di->events.btemp_medhigh) { | ||
757 | if (temp < di->btemp_ranges.btemp_med_limit) | ||
758 | temp = di->btemp_ranges.btemp_med_limit; | ||
759 | else | ||
760 | temp = di->bat_temp * 10; | ||
761 | } else | ||
762 | temp = di->bat_temp * 10; | ||
763 | } | ||
764 | return temp; | ||
765 | } | ||
766 | |||
767 | /** | ||
768 | * ab8500_btemp_get_batctrl_temp() - get the temperature | ||
769 | * @btemp: pointer to the btemp structure | ||
770 | * | ||
771 | * Returns the batctrl temperature in millidegrees | ||
772 | */ | ||
773 | int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp) | ||
774 | { | ||
775 | return btemp->bat_temp * 1000; | ||
776 | } | ||
777 | |||
778 | /** | ||
779 | * ab8500_btemp_get_property() - get the btemp properties | ||
780 | * @psy: pointer to the power_supply structure | ||
781 | * @psp: pointer to the power_supply_property structure | ||
782 | * @val: pointer to the power_supply_propval union | ||
783 | * | ||
784 | * This function gets called when an application tries to get the btemp | ||
785 | * properties by reading the sysfs files. | ||
786 | * online: presence of the battery | ||
787 | * present: presence of the battery | ||
788 | * technology: battery technology | ||
789 | * temp: battery temperature | ||
790 | * Returns error code in case of failure else 0(on success) | ||
791 | */ | ||
792 | static int ab8500_btemp_get_property(struct power_supply *psy, | ||
793 | enum power_supply_property psp, | ||
794 | union power_supply_propval *val) | ||
795 | { | ||
796 | struct ab8500_btemp *di; | ||
797 | |||
798 | di = to_ab8500_btemp_device_info(psy); | ||
799 | |||
800 | switch (psp) { | ||
801 | case POWER_SUPPLY_PROP_PRESENT: | ||
802 | case POWER_SUPPLY_PROP_ONLINE: | ||
803 | if (di->events.batt_rem) | ||
804 | val->intval = 0; | ||
805 | else | ||
806 | val->intval = 1; | ||
807 | break; | ||
808 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
809 | val->intval = di->bat->bat_type[di->bat->batt_id].name; | ||
810 | break; | ||
811 | case POWER_SUPPLY_PROP_TEMP: | ||
812 | val->intval = ab8500_btemp_get_temp(di); | ||
813 | break; | ||
814 | default: | ||
815 | return -EINVAL; | ||
816 | } | ||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static int ab8500_btemp_get_ext_psy_data(struct device *dev, void *data) | ||
821 | { | ||
822 | struct power_supply *psy; | ||
823 | struct power_supply *ext; | ||
824 | struct ab8500_btemp *di; | ||
825 | union power_supply_propval ret; | ||
826 | int i, j; | ||
827 | bool psy_found = false; | ||
828 | |||
829 | psy = (struct power_supply *)data; | ||
830 | ext = dev_get_drvdata(dev); | ||
831 | di = to_ab8500_btemp_device_info(psy); | ||
832 | |||
833 | /* | ||
834 | * For all psy where the name of your driver | ||
835 | * appears in any supplied_to | ||
836 | */ | ||
837 | for (i = 0; i < ext->num_supplicants; i++) { | ||
838 | if (!strcmp(ext->supplied_to[i], psy->name)) | ||
839 | psy_found = true; | ||
840 | } | ||
841 | |||
842 | if (!psy_found) | ||
843 | return 0; | ||
844 | |||
845 | /* Go through all properties for the psy */ | ||
846 | for (j = 0; j < ext->num_properties; j++) { | ||
847 | enum power_supply_property prop; | ||
848 | prop = ext->properties[j]; | ||
849 | |||
850 | if (ext->get_property(ext, prop, &ret)) | ||
851 | continue; | ||
852 | |||
853 | switch (prop) { | ||
854 | case POWER_SUPPLY_PROP_PRESENT: | ||
855 | switch (ext->type) { | ||
856 | case POWER_SUPPLY_TYPE_MAINS: | ||
857 | /* AC disconnected */ | ||
858 | if (!ret.intval && di->events.ac_conn) { | ||
859 | di->events.ac_conn = false; | ||
860 | } | ||
861 | /* AC connected */ | ||
862 | else if (ret.intval && !di->events.ac_conn) { | ||
863 | di->events.ac_conn = true; | ||
864 | if (!di->events.usb_conn) | ||
865 | ab8500_btemp_periodic(di, true); | ||
866 | } | ||
867 | break; | ||
868 | case POWER_SUPPLY_TYPE_USB: | ||
869 | /* USB disconnected */ | ||
870 | if (!ret.intval && di->events.usb_conn) { | ||
871 | di->events.usb_conn = false; | ||
872 | } | ||
873 | /* USB connected */ | ||
874 | else if (ret.intval && !di->events.usb_conn) { | ||
875 | di->events.usb_conn = true; | ||
876 | if (!di->events.ac_conn) | ||
877 | ab8500_btemp_periodic(di, true); | ||
878 | } | ||
879 | break; | ||
880 | default: | ||
881 | break; | ||
882 | } | ||
883 | break; | ||
884 | default: | ||
885 | break; | ||
886 | } | ||
887 | } | ||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | /** | ||
892 | * ab8500_btemp_external_power_changed() - callback for power supply changes | ||
893 | * @psy: pointer to the structure power_supply | ||
894 | * | ||
895 | * This function is pointing to the function pointer external_power_changed | ||
896 | * of the structure power_supply. | ||
897 | * This function gets executed when there is a change in the external power | ||
898 | * supply to the btemp. | ||
899 | */ | ||
900 | static void ab8500_btemp_external_power_changed(struct power_supply *psy) | ||
901 | { | ||
902 | struct ab8500_btemp *di = to_ab8500_btemp_device_info(psy); | ||
903 | |||
904 | class_for_each_device(power_supply_class, NULL, | ||
905 | &di->btemp_psy, ab8500_btemp_get_ext_psy_data); | ||
906 | } | ||
907 | |||
908 | /* ab8500 btemp driver interrupts and their respective isr */ | ||
909 | static struct ab8500_btemp_interrupts ab8500_btemp_irq[] = { | ||
910 | {"BAT_CTRL_INDB", ab8500_btemp_batctrlindb_handler}, | ||
911 | {"BTEMP_LOW", ab8500_btemp_templow_handler}, | ||
912 | {"BTEMP_HIGH", ab8500_btemp_temphigh_handler}, | ||
913 | {"BTEMP_LOW_MEDIUM", ab8500_btemp_lowmed_handler}, | ||
914 | {"BTEMP_MEDIUM_HIGH", ab8500_btemp_medhigh_handler}, | ||
915 | }; | ||
916 | |||
917 | #if defined(CONFIG_PM) | ||
918 | static int ab8500_btemp_resume(struct platform_device *pdev) | ||
919 | { | ||
920 | struct ab8500_btemp *di = platform_get_drvdata(pdev); | ||
921 | |||
922 | ab8500_btemp_periodic(di, true); | ||
923 | |||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | static int ab8500_btemp_suspend(struct platform_device *pdev, | ||
928 | pm_message_t state) | ||
929 | { | ||
930 | struct ab8500_btemp *di = platform_get_drvdata(pdev); | ||
931 | |||
932 | ab8500_btemp_periodic(di, false); | ||
933 | |||
934 | return 0; | ||
935 | } | ||
936 | #else | ||
937 | #define ab8500_btemp_suspend NULL | ||
938 | #define ab8500_btemp_resume NULL | ||
939 | #endif | ||
940 | |||
941 | static int __devexit ab8500_btemp_remove(struct platform_device *pdev) | ||
942 | { | ||
943 | struct ab8500_btemp *di = platform_get_drvdata(pdev); | ||
944 | int i, irq; | ||
945 | |||
946 | /* Disable interrupts */ | ||
947 | for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) { | ||
948 | irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); | ||
949 | free_irq(irq, di); | ||
950 | } | ||
951 | |||
952 | /* Delete the work queue */ | ||
953 | destroy_workqueue(di->btemp_wq); | ||
954 | |||
955 | flush_scheduled_work(); | ||
956 | power_supply_unregister(&di->btemp_psy); | ||
957 | platform_set_drvdata(pdev, NULL); | ||
958 | kfree(di); | ||
959 | |||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | static int __devinit ab8500_btemp_probe(struct platform_device *pdev) | ||
964 | { | ||
965 | int irq, i, ret = 0; | ||
966 | u8 val; | ||
967 | struct abx500_bm_plat_data *plat_data; | ||
968 | |||
969 | struct ab8500_btemp *di = | ||
970 | kzalloc(sizeof(struct ab8500_btemp), GFP_KERNEL); | ||
971 | if (!di) | ||
972 | return -ENOMEM; | ||
973 | |||
974 | /* get parent data */ | ||
975 | di->dev = &pdev->dev; | ||
976 | di->parent = dev_get_drvdata(pdev->dev.parent); | ||
977 | di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); | ||
978 | |||
979 | /* get btemp specific platform data */ | ||
980 | plat_data = pdev->dev.platform_data; | ||
981 | di->pdata = plat_data->btemp; | ||
982 | if (!di->pdata) { | ||
983 | dev_err(di->dev, "no btemp platform data supplied\n"); | ||
984 | ret = -EINVAL; | ||
985 | goto free_device_info; | ||
986 | } | ||
987 | |||
988 | /* get battery specific platform data */ | ||
989 | di->bat = plat_data->battery; | ||
990 | if (!di->bat) { | ||
991 | dev_err(di->dev, "no battery platform data supplied\n"); | ||
992 | ret = -EINVAL; | ||
993 | goto free_device_info; | ||
994 | } | ||
995 | |||
996 | /* BTEMP supply */ | ||
997 | di->btemp_psy.name = "ab8500_btemp"; | ||
998 | di->btemp_psy.type = POWER_SUPPLY_TYPE_BATTERY; | ||
999 | di->btemp_psy.properties = ab8500_btemp_props; | ||
1000 | di->btemp_psy.num_properties = ARRAY_SIZE(ab8500_btemp_props); | ||
1001 | di->btemp_psy.get_property = ab8500_btemp_get_property; | ||
1002 | di->btemp_psy.supplied_to = di->pdata->supplied_to; | ||
1003 | di->btemp_psy.num_supplicants = di->pdata->num_supplicants; | ||
1004 | di->btemp_psy.external_power_changed = | ||
1005 | ab8500_btemp_external_power_changed; | ||
1006 | |||
1007 | |||
1008 | /* Create a work queue for the btemp */ | ||
1009 | di->btemp_wq = | ||
1010 | create_singlethread_workqueue("ab8500_btemp_wq"); | ||
1011 | if (di->btemp_wq == NULL) { | ||
1012 | dev_err(di->dev, "failed to create work queue\n"); | ||
1013 | goto free_device_info; | ||
1014 | } | ||
1015 | |||
1016 | /* Init work for measuring temperature periodically */ | ||
1017 | INIT_DELAYED_WORK_DEFERRABLE(&di->btemp_periodic_work, | ||
1018 | ab8500_btemp_periodic_work); | ||
1019 | |||
1020 | /* Identify the battery */ | ||
1021 | if (ab8500_btemp_id(di) < 0) | ||
1022 | dev_warn(di->dev, "failed to identify the battery\n"); | ||
1023 | |||
1024 | /* Set BTEMP thermal limits. Low and Med are fixed */ | ||
1025 | di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT; | ||
1026 | di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT; | ||
1027 | |||
1028 | ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER, | ||
1029 | AB8500_BTEMP_HIGH_TH, &val); | ||
1030 | if (ret < 0) { | ||
1031 | dev_err(di->dev, "%s ab8500 read failed\n", __func__); | ||
1032 | goto free_btemp_wq; | ||
1033 | } | ||
1034 | switch (val) { | ||
1035 | case BTEMP_HIGH_TH_57_0: | ||
1036 | case BTEMP_HIGH_TH_57_1: | ||
1037 | di->btemp_ranges.btemp_high_limit = | ||
1038 | BTEMP_THERMAL_HIGH_LIMIT_57; | ||
1039 | break; | ||
1040 | case BTEMP_HIGH_TH_52: | ||
1041 | di->btemp_ranges.btemp_high_limit = | ||
1042 | BTEMP_THERMAL_HIGH_LIMIT_52; | ||
1043 | break; | ||
1044 | case BTEMP_HIGH_TH_62: | ||
1045 | di->btemp_ranges.btemp_high_limit = | ||
1046 | BTEMP_THERMAL_HIGH_LIMIT_62; | ||
1047 | break; | ||
1048 | } | ||
1049 | |||
1050 | /* Register BTEMP power supply class */ | ||
1051 | ret = power_supply_register(di->dev, &di->btemp_psy); | ||
1052 | if (ret) { | ||
1053 | dev_err(di->dev, "failed to register BTEMP psy\n"); | ||
1054 | goto free_btemp_wq; | ||
1055 | } | ||
1056 | |||
1057 | /* Register interrupts */ | ||
1058 | for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) { | ||
1059 | irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); | ||
1060 | ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr, | ||
1061 | IRQF_SHARED | IRQF_NO_SUSPEND, | ||
1062 | ab8500_btemp_irq[i].name, di); | ||
1063 | |||
1064 | if (ret) { | ||
1065 | dev_err(di->dev, "failed to request %s IRQ %d: %d\n" | ||
1066 | , ab8500_btemp_irq[i].name, irq, ret); | ||
1067 | goto free_irq; | ||
1068 | } | ||
1069 | dev_dbg(di->dev, "Requested %s IRQ %d: %d\n", | ||
1070 | ab8500_btemp_irq[i].name, irq, ret); | ||
1071 | } | ||
1072 | |||
1073 | platform_set_drvdata(pdev, di); | ||
1074 | |||
1075 | /* Kick off periodic temperature measurements */ | ||
1076 | ab8500_btemp_periodic(di, true); | ||
1077 | list_add_tail(&di->node, &ab8500_btemp_list); | ||
1078 | |||
1079 | return ret; | ||
1080 | |||
1081 | free_irq: | ||
1082 | power_supply_unregister(&di->btemp_psy); | ||
1083 | |||
1084 | /* We also have to free all successfully registered irqs */ | ||
1085 | for (i = i - 1; i >= 0; i--) { | ||
1086 | irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name); | ||
1087 | free_irq(irq, di); | ||
1088 | } | ||
1089 | free_btemp_wq: | ||
1090 | destroy_workqueue(di->btemp_wq); | ||
1091 | free_device_info: | ||
1092 | kfree(di); | ||
1093 | |||
1094 | return ret; | ||
1095 | } | ||
1096 | |||
1097 | static struct platform_driver ab8500_btemp_driver = { | ||
1098 | .probe = ab8500_btemp_probe, | ||
1099 | .remove = __devexit_p(ab8500_btemp_remove), | ||
1100 | .suspend = ab8500_btemp_suspend, | ||
1101 | .resume = ab8500_btemp_resume, | ||
1102 | .driver = { | ||
1103 | .name = "ab8500-btemp", | ||
1104 | .owner = THIS_MODULE, | ||
1105 | }, | ||
1106 | }; | ||
1107 | |||
1108 | static int __init ab8500_btemp_init(void) | ||
1109 | { | ||
1110 | return platform_driver_register(&ab8500_btemp_driver); | ||
1111 | } | ||
1112 | |||
1113 | static void __exit ab8500_btemp_exit(void) | ||
1114 | { | ||
1115 | platform_driver_unregister(&ab8500_btemp_driver); | ||
1116 | } | ||
1117 | |||
1118 | subsys_initcall_sync(ab8500_btemp_init); | ||
1119 | module_exit(ab8500_btemp_exit); | ||
1120 | |||
1121 | MODULE_LICENSE("GPL v2"); | ||
1122 | MODULE_AUTHOR("Johan Palsson, Karl Komierowski, Arun R Murthy"); | ||
1123 | MODULE_ALIAS("platform:ab8500-btemp"); | ||
1124 | MODULE_DESCRIPTION("AB8500 battery temperature driver"); | ||