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