blob: 8d9ee86bc4b1ba819bbc4eea3d2d8e5f753762f7 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
David Collins197c31e2012-09-10 13:15:17 -07002 * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14/*
15 * Qualcomm PMIC PM8xxx Thermal Manager driver
16 */
17
18#define pr_fmt(fmt) "%s: " fmt, __func__
19
20#include <linux/module.h>
21#include <linux/err.h>
22#include <linux/string.h>
23#include <linux/kernel.h>
24#include <linux/slab.h>
25#include <linux/mutex.h>
26#include <linux/thermal.h>
27#include <linux/interrupt.h>
28#include <linux/platform_device.h>
29#include <linux/mfd/pm8xxx/core.h>
30#include <linux/mfd/pm8xxx/tm.h>
31#include <linux/completion.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070032#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Anirudh Ghayalc2019332011-11-12 06:29:10 +053033#include <linux/msm_adc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034
35/* Register TEMP_ALARM_CTRL bits */
36#define TEMP_ALARM_CTRL_ST3_SD 0x80
37#define TEMP_ALARM_CTRL_ST2_SD 0x40
38#define TEMP_ALARM_CTRL_STATUS_MASK 0x30
39#define TEMP_ALARM_CTRL_STATUS_SHIFT 4
40#define TEMP_ALARM_CTRL_THRESH_MASK 0x0C
41#define TEMP_ALARM_CTRL_THRESH_SHIFT 2
42#define TEMP_ALARM_CTRL_OVRD_ST3 0x02
43#define TEMP_ALARM_CTRL_OVRD_ST2 0x01
44#define TEMP_ALARM_CTRL_OVRD_MASK 0x03
45
46#define TEMP_STAGE_STEP 20000 /* Stage step: 20.000 C */
47#define TEMP_STAGE_HYSTERESIS 2000
48
49#define TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */
50#define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */
51
52/* Register TEMP_ALARM_PWM bits */
53#define TEMP_ALARM_PWM_EN_MASK 0xC0
54#define TEMP_ALARM_PWM_EN_SHIFT 6
55#define TEMP_ALARM_PWM_PER_PRE_MASK 0x38
56#define TEMP_ALARM_PWM_PER_PRE_SHIFT 3
57#define TEMP_ALARM_PWM_PER_DIV_MASK 0x07
58#define TEMP_ALARM_PWM_PER_DIV_SHIFT 0
59
60/* Trips: from critical to less critical */
61#define TRIP_STAGE3 0
62#define TRIP_STAGE2 1
63#define TRIP_STAGE1 2
64#define TRIP_NUM 3
65
66struct pm8xxx_tm_chip {
67 struct pm8xxx_tm_core_data cdata;
68 struct work_struct irq_work;
69 struct device *dev;
70 struct thermal_zone_device *tz_dev;
71 unsigned long temp;
David Collinsb42b2942012-09-12 14:47:03 -070072 unsigned int prev_stage;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073 enum thermal_device_mode mode;
74 unsigned int thresh;
75 unsigned int stage;
76 unsigned int tempstat_irq;
77 unsigned int overtemp_irq;
78 void *adc_handle;
79};
80
81enum pmic_thermal_override_mode {
82 SOFTWARE_OVERRIDE_DISABLED = 0,
83 SOFTWARE_OVERRIDE_ENABLED,
84};
85
86static inline int pm8xxx_tm_read_ctrl(struct pm8xxx_tm_chip *chip, u8 *reg)
87{
88 int rc;
89
90 rc = pm8xxx_readb(chip->dev->parent,
91 chip->cdata.reg_addr_temp_alarm_ctrl, reg);
92 if (rc)
93 pr_err("%s: pm8xxx_readb(0x%03X) failed, rc=%d\n",
94 chip->cdata.tm_name,
95 chip->cdata.reg_addr_temp_alarm_ctrl, rc);
96
97 return rc;
98}
99
100static inline int pm8xxx_tm_write_ctrl(struct pm8xxx_tm_chip *chip, u8 reg)
101{
102 int rc;
103
104 rc = pm8xxx_writeb(chip->dev->parent,
105 chip->cdata.reg_addr_temp_alarm_ctrl, reg);
106 if (rc)
107 pr_err("%s: pm8xxx_writeb(0x%03X)=0x%02X failed, rc=%d\n",
108 chip->cdata.tm_name,
109 chip->cdata.reg_addr_temp_alarm_ctrl, reg, rc);
110
111 return rc;
112}
113
114static inline int pm8xxx_tm_write_pwm(struct pm8xxx_tm_chip *chip, u8 reg)
115{
116 int rc;
117
118 rc = pm8xxx_writeb(chip->dev->parent,
119 chip->cdata.reg_addr_temp_alarm_pwm, reg);
120 if (rc)
121 pr_err("%s: pm8xxx_writeb(0x%03X)=0x%02X failed, rc=%d\n",
122 chip->cdata.tm_name,
123 chip->cdata.reg_addr_temp_alarm_pwm, reg, rc);
124
125 return rc;
126}
127
128static inline int
129pm8xxx_tm_shutdown_override(struct pm8xxx_tm_chip *chip,
130 enum pmic_thermal_override_mode mode)
131{
132 int rc;
133 u8 reg;
134
135 rc = pm8xxx_tm_read_ctrl(chip, &reg);
136 if (rc < 0)
137 return rc;
138
139 reg &= ~(TEMP_ALARM_CTRL_OVRD_MASK | TEMP_ALARM_CTRL_STATUS_MASK);
140 if (mode == SOFTWARE_OVERRIDE_ENABLED)
141 reg |= (TEMP_ALARM_CTRL_OVRD_ST3 | TEMP_ALARM_CTRL_OVRD_ST2) &
142 TEMP_ALARM_CTRL_OVRD_MASK;
143
144 rc = pm8xxx_tm_write_ctrl(chip, reg);
145
146 return rc;
147}
148
149/*
150 * This function initializes the internal temperature value based on only the
151 * current thermal stage and threshold.
152 */
153static int pm8xxx_tm_init_temp_no_adc(struct pm8xxx_tm_chip *chip)
154{
155 int rc;
156 u8 reg;
157
158 rc = pm8xxx_tm_read_ctrl(chip, &reg);
159 if (rc < 0)
160 return rc;
161
162 chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
163 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
164 chip->thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
165 >> TEMP_ALARM_CTRL_THRESH_SHIFT;
166
167 if (chip->stage)
168 chip->temp = chip->thresh * TEMP_THRESH_MIN +
169 (chip->stage - 1) * TEMP_STAGE_STEP +
170 TEMP_THRESH_MIN;
171 else
172 chip->temp = chip->cdata.default_no_adc_temp;
173
174 return 0;
175}
176
177/*
178 * This function updates the internal temperature value based on the
179 * current thermal stage and threshold as well as the previous stage
180 */
181static int pm8xxx_tm_update_temp_no_adc(struct pm8xxx_tm_chip *chip)
182{
183 unsigned int stage;
184 int rc;
185 u8 reg;
186
187 rc = pm8xxx_tm_read_ctrl(chip, &reg);
188 if (rc < 0)
189 return rc;
190
191 stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
192 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
193 chip->thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
194 >> TEMP_ALARM_CTRL_THRESH_SHIFT;
195
196 if (stage > chip->stage) {
197 /* increasing stage, use lower bound */
198 chip->temp = (stage - 1) * TEMP_STAGE_STEP
199 + chip->thresh * TEMP_THRESH_STEP
200 + TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
201 } else if (stage < chip->stage) {
202 /* decreasing stage, use upper bound */
203 chip->temp = stage * TEMP_STAGE_STEP
204 + chip->thresh * TEMP_THRESH_STEP
205 - TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
206 }
207
208 chip->stage = stage;
209
210 return 0;
211}
212
213static int pm8xxx_tz_get_temp_no_adc(struct thermal_zone_device *thermal,
214 unsigned long *temp)
215{
216 struct pm8xxx_tm_chip *chip = thermal->devdata;
217 int rc;
218
219 if (!chip || !temp)
220 return -EINVAL;
221
222 rc = pm8xxx_tm_update_temp_no_adc(chip);
223 if (rc < 0)
224 return rc;
225
226 *temp = chip->temp;
227
228 return 0;
229}
230
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530231static int pm8xxx_tz_get_temp_pm8058_adc(struct thermal_zone_device *thermal,
232 unsigned long *temp)
233{
234 struct pm8xxx_tm_chip *chip = thermal->devdata;
235 DECLARE_COMPLETION_ONSTACK(wait);
236 struct adc_chan_result adc_result = {
237 .physical = 0lu,
238 };
239 int rc;
240
241 if (!chip || !temp)
242 return -EINVAL;
243
244 *temp = chip->temp;
245
246 rc = adc_channel_request_conv(chip->adc_handle, &wait);
247 if (rc < 0) {
248 pr_err("%s: adc_channel_request_conv() failed, rc = %d\n",
249 __func__, rc);
250 return rc;
251 }
252
253 wait_for_completion(&wait);
254
255 rc = adc_channel_read_result(chip->adc_handle, &adc_result);
256 if (rc < 0) {
257 pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
258 __func__, rc);
259 return rc;
260 }
261
262 *temp = adc_result.physical;
263 chip->temp = adc_result.physical;
264
265 return 0;
266}
267
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700268static int pm8xxx_tz_get_temp_pm8xxx_adc(struct thermal_zone_device *thermal,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 unsigned long *temp)
270{
271 struct pm8xxx_tm_chip *chip = thermal->devdata;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700272 struct pm8xxx_adc_chan_result result = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 .physical = 0lu,
274 };
275 int rc;
276
277 if (!chip || !temp)
278 return -EINVAL;
279
280 *temp = chip->temp;
281
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700282 rc = pm8xxx_adc_read(chip->cdata.adc_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 if (rc < 0) {
284 pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
285 chip->cdata.tm_name, rc);
286 return rc;
287 }
288
289 *temp = result.physical;
290 chip->temp = result.physical;
291
292 return 0;
293}
294
295static int pm8xxx_tz_get_mode(struct thermal_zone_device *thermal,
296 enum thermal_device_mode *mode)
297{
298 struct pm8xxx_tm_chip *chip = thermal->devdata;
299
300 if (!chip || !mode)
301 return -EINVAL;
302
303 *mode = chip->mode;
304
305 return 0;
306}
307
308static int pm8xxx_tz_set_mode(struct thermal_zone_device *thermal,
309 enum thermal_device_mode mode)
310{
311 struct pm8xxx_tm_chip *chip = thermal->devdata;
312
313 if (!chip)
314 return -EINVAL;
315
316 if (mode != chip->mode) {
317 if (mode == THERMAL_DEVICE_ENABLED)
318 pm8xxx_tm_shutdown_override(chip,
319 SOFTWARE_OVERRIDE_ENABLED);
320 else
321 pm8xxx_tm_shutdown_override(chip,
322 SOFTWARE_OVERRIDE_DISABLED);
323 }
324 chip->mode = mode;
325
326 return 0;
327}
328
329static int pm8xxx_tz_get_trip_type(struct thermal_zone_device *thermal,
330 int trip, enum thermal_trip_type *type)
331{
332 if (trip < 0 || !type)
333 return -EINVAL;
334
335 switch (trip) {
336 case TRIP_STAGE3:
337 *type = THERMAL_TRIP_CRITICAL;
338 break;
339 case TRIP_STAGE2:
340 *type = THERMAL_TRIP_HOT;
341 break;
342 case TRIP_STAGE1:
343 *type = THERMAL_TRIP_HOT;
344 break;
345 default:
346 return -EINVAL;
347 }
348
349 return 0;
350}
351
352static int pm8xxx_tz_get_trip_temp(struct thermal_zone_device *thermal,
353 int trip, unsigned long *temp)
354{
355 struct pm8xxx_tm_chip *chip = thermal->devdata;
356 int thresh_temp;
357
358 if (!chip || trip < 0 || !temp)
359 return -EINVAL;
360
361 thresh_temp = chip->thresh * TEMP_THRESH_STEP +
362 TEMP_THRESH_MIN;
363
364 switch (trip) {
365 case TRIP_STAGE3:
366 thresh_temp += 2 * TEMP_STAGE_STEP;
367 break;
368 case TRIP_STAGE2:
369 thresh_temp += TEMP_STAGE_STEP;
370 break;
371 case TRIP_STAGE1:
372 break;
373 default:
374 return -EINVAL;
375 }
376
377 *temp = thresh_temp;
378
379 return 0;
380}
381
382static int pm8xxx_tz_get_crit_temp(struct thermal_zone_device *thermal,
383 unsigned long *temp)
384{
385 struct pm8xxx_tm_chip *chip = thermal->devdata;
386
387 if (!chip || !temp)
388 return -EINVAL;
389
390 *temp = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN +
391 2 * TEMP_STAGE_STEP;
392
393 return 0;
394}
395
396static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_no_adc = {
397 .get_temp = pm8xxx_tz_get_temp_no_adc,
398 .get_mode = pm8xxx_tz_get_mode,
399 .set_mode = pm8xxx_tz_set_mode,
400 .get_trip_type = pm8xxx_tz_get_trip_type,
401 .get_trip_temp = pm8xxx_tz_get_trip_temp,
402 .get_crit_temp = pm8xxx_tz_get_crit_temp,
403};
404
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700405static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8xxx_adc = {
406 .get_temp = pm8xxx_tz_get_temp_pm8xxx_adc,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 .get_mode = pm8xxx_tz_get_mode,
408 .set_mode = pm8xxx_tz_set_mode,
409 .get_trip_type = pm8xxx_tz_get_trip_type,
410 .get_trip_temp = pm8xxx_tz_get_trip_temp,
411 .get_crit_temp = pm8xxx_tz_get_crit_temp,
412};
413
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530414static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8058_adc = {
415 .get_temp = pm8xxx_tz_get_temp_pm8058_adc,
416 .get_mode = pm8xxx_tz_get_mode,
417 .set_mode = pm8xxx_tz_set_mode,
418 .get_trip_type = pm8xxx_tz_get_trip_type,
419 .get_trip_temp = pm8xxx_tz_get_trip_temp,
420 .get_crit_temp = pm8xxx_tz_get_crit_temp,
421};
422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423static void pm8xxx_tm_work(struct work_struct *work)
424{
425 struct pm8xxx_tm_chip *chip
426 = container_of(work, struct pm8xxx_tm_chip, irq_work);
David Collinsb42b2942012-09-12 14:47:03 -0700427 unsigned long temp = 0;
428 int rc, stage, thresh;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 u8 reg;
430
431 rc = pm8xxx_tm_read_ctrl(chip, &reg);
432 if (rc < 0)
433 goto bail;
434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 /* Clear status bits. */
436 if (reg & (TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD)) {
437 reg &= ~(TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD
438 | TEMP_ALARM_CTRL_STATUS_MASK);
439
440 pm8xxx_tm_write_ctrl(chip, reg);
441 }
442
David Collinsb42b2942012-09-12 14:47:03 -0700443 stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
444 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
445 thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
446 >> TEMP_ALARM_CTRL_THRESH_SHIFT;
447
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 thermal_zone_device_update(chip->tz_dev);
449
David Collinsb42b2942012-09-12 14:47:03 -0700450 if (stage != chip->prev_stage) {
451 chip->prev_stage = stage;
452
453 switch (chip->cdata.adc_type) {
454 case PM8XXX_TM_ADC_NONE:
455 rc = pm8xxx_tz_get_temp_no_adc(chip->tz_dev, &temp);
456 break;
457 case PM8XXX_TM_ADC_PM8058_ADC:
458 rc = pm8xxx_tz_get_temp_pm8058_adc(chip->tz_dev, &temp);
459 break;
460 case PM8XXX_TM_ADC_PM8XXX_ADC:
461 rc = pm8xxx_tz_get_temp_pm8xxx_adc(chip->tz_dev, &temp);
462 break;
463 }
464 if (rc < 0)
465 goto bail;
466
467 pr_crit("%s: PMIC Temp Alarm - stage=%u, threshold=%u, temp=%lu mC\n",
468 chip->cdata.tm_name, stage, thresh, temp);
469
470 /* Notify user space */
471 sysfs_notify(&chip->tz_dev->device.kobj, NULL, "type");
472 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473
474bail:
475 enable_irq(chip->tempstat_irq);
476 enable_irq(chip->overtemp_irq);
477}
478
479static irqreturn_t pm8xxx_tm_isr(int irq, void *data)
480{
481 struct pm8xxx_tm_chip *chip = data;
482
483 disable_irq_nosync(chip->tempstat_irq);
484 disable_irq_nosync(chip->overtemp_irq);
485 schedule_work(&chip->irq_work);
486
487 return IRQ_HANDLED;
488}
489
490static int pm8xxx_tm_init_reg(struct pm8xxx_tm_chip *chip)
491{
492 int rc;
493 u8 reg;
494
495 rc = pm8xxx_tm_read_ctrl(chip, &reg);
496 if (rc < 0)
497 return rc;
498
499 chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
500 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
501 chip->temp = 0;
502
503 /* Use temperature threshold set 0: (105, 125, 145) */
504 chip->thresh = 0;
505 reg = (chip->thresh << TEMP_ALARM_CTRL_THRESH_SHIFT)
506 & TEMP_ALARM_CTRL_THRESH_MASK;
507 rc = pm8xxx_tm_write_ctrl(chip, reg);
508 if (rc < 0)
509 return rc;
510
511 /*
512 * Set the PMIC alarm module PWM to have a frequency of 8 Hz. This
513 * helps cut down on the number of unnecessary interrupts fired when
514 * changing between thermal stages. Also, Enable the over temperature
515 * PWM whenever the PMIC is enabled.
516 */
517 reg = (1 << TEMP_ALARM_PWM_EN_SHIFT)
518 | (3 << TEMP_ALARM_PWM_PER_PRE_SHIFT)
519 | (3 << TEMP_ALARM_PWM_PER_DIV_SHIFT);
520
521 rc = pm8xxx_tm_write_pwm(chip, reg);
522
523 return rc;
524}
525
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530526static int pm8xxx_init_adc(struct pm8xxx_tm_chip *chip, bool enable)
527{
528 int rc = 0;
529
530 if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8058_ADC) {
531 if (enable) {
532 rc = adc_channel_open(chip->cdata.adc_channel,
533 &(chip->adc_handle));
534 if (rc < 0)
535 pr_err("adc_channel_open() failed.\n");
536 } else {
537 adc_channel_close(chip->adc_handle);
538 }
539 }
540
541 return rc;
542}
543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544static int __devinit pm8xxx_tm_probe(struct platform_device *pdev)
545{
546 const struct pm8xxx_tm_core_data *cdata = pdev->dev.platform_data;
547 struct thermal_zone_device_ops *tz_ops;
548 struct pm8xxx_tm_chip *chip;
549 struct resource *res;
550 int rc = 0;
551
552 if (!cdata) {
553 pr_err("missing core data\n");
554 return -EINVAL;
555 }
556
557 chip = kzalloc(sizeof(struct pm8xxx_tm_chip), GFP_KERNEL);
558 if (chip == NULL) {
559 pr_err("kzalloc() failed.\n");
560 return -ENOMEM;
561 }
562
563 chip->dev = &pdev->dev;
564 memcpy(&(chip->cdata), cdata, sizeof(struct pm8xxx_tm_core_data));
565
566 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
567 chip->cdata.irq_name_temp_stat);
568 if (res) {
569 chip->tempstat_irq = res->start;
570 } else {
571 pr_err("temp stat IRQ not specified\n");
572 goto err_free_chip;
573 }
574
575 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
576 chip->cdata.irq_name_over_temp);
577 if (res) {
578 chip->overtemp_irq = res->start;
579 } else {
580 pr_err("over temp IRQ not specified\n");
581 goto err_free_chip;
582 }
583
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530584 rc = pm8xxx_init_adc(chip, true);
585 if (rc < 0) {
586 pr_err("Unable to initialize adc\n");
587 goto err_free_chip;
588 }
589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 /* Select proper thermal zone ops functions based on ADC type. */
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700591 if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8XXX_ADC)
592 tz_ops = &pm8xxx_thermal_zone_ops_pm8xxx_adc;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530593 else if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8058_ADC)
594 tz_ops = &pm8xxx_thermal_zone_ops_pm8058_adc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700595 else
596 tz_ops = &pm8xxx_thermal_zone_ops_no_adc;
597
598 chip->tz_dev = thermal_zone_device_register(chip->cdata.tm_name,
599 TRIP_NUM, chip, tz_ops, 0, 0, 0, 0);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601 if (chip->tz_dev == NULL) {
602 pr_err("thermal_zone_device_register() failed.\n");
603 rc = -ENODEV;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530604 goto err_fail_adc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 }
606
607 rc = pm8xxx_tm_init_reg(chip);
608 if (rc < 0)
609 goto err_free_tz;
610 rc = pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
611 if (rc < 0)
612 goto err_free_tz;
613
614 if (chip->cdata.adc_type == PM8XXX_TM_ADC_NONE) {
615 rc = pm8xxx_tm_init_temp_no_adc(chip);
616 if (rc < 0)
617 goto err_free_tz;
618 }
619
620 /* Start in HW control; switch to SW control when user changes mode. */
621 chip->mode = THERMAL_DEVICE_DISABLED;
622 thermal_zone_device_update(chip->tz_dev);
623
624 INIT_WORK(&chip->irq_work, pm8xxx_tm_work);
625
626 rc = request_irq(chip->tempstat_irq, pm8xxx_tm_isr, IRQF_TRIGGER_RISING,
627 chip->cdata.irq_name_temp_stat, chip);
628 if (rc < 0) {
629 pr_err("request_irq(%d) failed: %d\n", chip->tempstat_irq, rc);
630 goto err_cancel_work;
631 }
632
633 rc = request_irq(chip->overtemp_irq, pm8xxx_tm_isr, IRQF_TRIGGER_RISING,
634 chip->cdata.irq_name_over_temp, chip);
635 if (rc < 0) {
636 pr_err("request_irq(%d) failed: %d\n", chip->overtemp_irq, rc);
637 goto err_free_irq_tempstat;
638 }
639
640 platform_set_drvdata(pdev, chip);
641
642 pr_info("OK\n");
643
644 return 0;
645
646err_free_irq_tempstat:
647 free_irq(chip->tempstat_irq, chip);
648err_cancel_work:
649 cancel_work_sync(&chip->irq_work);
650err_free_tz:
651 thermal_zone_device_unregister(chip->tz_dev);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530652err_fail_adc:
653 pm8xxx_init_adc(chip, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654err_free_chip:
655 kfree(chip);
656 return rc;
657}
658
659static int __devexit pm8xxx_tm_remove(struct platform_device *pdev)
660{
661 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
662
663 if (chip) {
664 platform_set_drvdata(pdev, NULL);
665 cancel_work_sync(&chip->irq_work);
666 free_irq(chip->overtemp_irq, chip);
667 free_irq(chip->tempstat_irq, chip);
668 pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530669 pm8xxx_init_adc(chip, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670 thermal_zone_device_unregister(chip->tz_dev);
671 kfree(chip);
672 }
673 return 0;
674}
675
676#ifdef CONFIG_PM
677static int pm8xxx_tm_suspend(struct device *dev)
678{
679 struct platform_device *pdev = to_platform_device(dev);
680 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
681
682 /* Clear override bits in suspend to allow hardware control */
683 pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
684
685 return 0;
686}
687
688static int pm8xxx_tm_resume(struct device *dev)
689{
690 struct platform_device *pdev = to_platform_device(dev);
691 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
692
693 /* Override hardware actions so software can control */
694 if (chip->mode == THERMAL_DEVICE_ENABLED)
695 pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_ENABLED);
696
697 return 0;
698}
699
700static const struct dev_pm_ops pm8xxx_tm_pm_ops = {
701 .suspend = pm8xxx_tm_suspend,
702 .resume = pm8xxx_tm_resume,
703};
704
705#define PM8XXX_TM_PM_OPS (&pm8xxx_tm_pm_ops)
706#else
707#define PM8XXX_TM_PM_OPS NULL
708#endif
709
710static struct platform_driver pm8xxx_tm_driver = {
711 .probe = pm8xxx_tm_probe,
712 .remove = __devexit_p(pm8xxx_tm_remove),
713 .driver = {
714 .name = PM8XXX_TM_DEV_NAME,
715 .owner = THIS_MODULE,
716 .pm = PM8XXX_TM_PM_OPS,
717 },
718};
719
720static int __init pm8xxx_tm_init(void)
721{
722 return platform_driver_register(&pm8xxx_tm_driver);
723}
724
725static void __exit pm8xxx_tm_exit(void)
726{
727 platform_driver_unregister(&pm8xxx_tm_driver);
728}
729
730module_init(pm8xxx_tm_init);
731module_exit(pm8xxx_tm_exit);
732
733MODULE_LICENSE("GPL v2");
734MODULE_DESCRIPTION("PM8xxx Thermal Manager driver");
735MODULE_VERSION("1.0");
736MODULE_ALIAS("platform:" PM8XXX_TM_DEV_NAME);