blob: ec043692a63dcd906fdcae5a93377e27b6be975f [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;
David Collinsb2451ea2012-09-12 14:58:54 -070068 struct delayed_work irq_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070069 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
David Collinsb2451ea2012-09-12 14:58:54 -070086/* Delay between TEMP_STAT IRQ going high and status value changing in ms. */
87#define STATUS_REGISTER_DELAY_MS 40
88
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089static inline int pm8xxx_tm_read_ctrl(struct pm8xxx_tm_chip *chip, u8 *reg)
90{
91 int rc;
92
93 rc = pm8xxx_readb(chip->dev->parent,
94 chip->cdata.reg_addr_temp_alarm_ctrl, reg);
95 if (rc)
96 pr_err("%s: pm8xxx_readb(0x%03X) failed, rc=%d\n",
97 chip->cdata.tm_name,
98 chip->cdata.reg_addr_temp_alarm_ctrl, rc);
99
100 return rc;
101}
102
103static inline int pm8xxx_tm_write_ctrl(struct pm8xxx_tm_chip *chip, u8 reg)
104{
105 int rc;
106
107 rc = pm8xxx_writeb(chip->dev->parent,
108 chip->cdata.reg_addr_temp_alarm_ctrl, reg);
109 if (rc)
110 pr_err("%s: pm8xxx_writeb(0x%03X)=0x%02X failed, rc=%d\n",
111 chip->cdata.tm_name,
112 chip->cdata.reg_addr_temp_alarm_ctrl, reg, rc);
113
114 return rc;
115}
116
117static inline int pm8xxx_tm_write_pwm(struct pm8xxx_tm_chip *chip, u8 reg)
118{
119 int rc;
120
121 rc = pm8xxx_writeb(chip->dev->parent,
122 chip->cdata.reg_addr_temp_alarm_pwm, reg);
123 if (rc)
124 pr_err("%s: pm8xxx_writeb(0x%03X)=0x%02X failed, rc=%d\n",
125 chip->cdata.tm_name,
126 chip->cdata.reg_addr_temp_alarm_pwm, reg, rc);
127
128 return rc;
129}
130
131static inline int
132pm8xxx_tm_shutdown_override(struct pm8xxx_tm_chip *chip,
133 enum pmic_thermal_override_mode mode)
134{
135 int rc;
136 u8 reg;
137
138 rc = pm8xxx_tm_read_ctrl(chip, &reg);
139 if (rc < 0)
140 return rc;
141
142 reg &= ~(TEMP_ALARM_CTRL_OVRD_MASK | TEMP_ALARM_CTRL_STATUS_MASK);
143 if (mode == SOFTWARE_OVERRIDE_ENABLED)
144 reg |= (TEMP_ALARM_CTRL_OVRD_ST3 | TEMP_ALARM_CTRL_OVRD_ST2) &
145 TEMP_ALARM_CTRL_OVRD_MASK;
146
147 rc = pm8xxx_tm_write_ctrl(chip, reg);
148
149 return rc;
150}
151
152/*
153 * This function initializes the internal temperature value based on only the
154 * current thermal stage and threshold.
155 */
156static int pm8xxx_tm_init_temp_no_adc(struct pm8xxx_tm_chip *chip)
157{
158 int rc;
159 u8 reg;
160
161 rc = pm8xxx_tm_read_ctrl(chip, &reg);
162 if (rc < 0)
163 return rc;
164
165 chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
166 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
167 chip->thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
168 >> TEMP_ALARM_CTRL_THRESH_SHIFT;
169
170 if (chip->stage)
171 chip->temp = chip->thresh * TEMP_THRESH_MIN +
172 (chip->stage - 1) * TEMP_STAGE_STEP +
173 TEMP_THRESH_MIN;
174 else
175 chip->temp = chip->cdata.default_no_adc_temp;
176
177 return 0;
178}
179
180/*
181 * This function updates the internal temperature value based on the
182 * current thermal stage and threshold as well as the previous stage
183 */
184static int pm8xxx_tm_update_temp_no_adc(struct pm8xxx_tm_chip *chip)
185{
186 unsigned int stage;
187 int rc;
188 u8 reg;
189
190 rc = pm8xxx_tm_read_ctrl(chip, &reg);
191 if (rc < 0)
192 return rc;
193
194 stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
195 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
196 chip->thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
197 >> TEMP_ALARM_CTRL_THRESH_SHIFT;
198
199 if (stage > chip->stage) {
200 /* increasing stage, use lower bound */
201 chip->temp = (stage - 1) * TEMP_STAGE_STEP
202 + chip->thresh * TEMP_THRESH_STEP
203 + TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
204 } else if (stage < chip->stage) {
205 /* decreasing stage, use upper bound */
206 chip->temp = stage * TEMP_STAGE_STEP
207 + chip->thresh * TEMP_THRESH_STEP
208 - TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
209 }
210
211 chip->stage = stage;
212
213 return 0;
214}
215
216static int pm8xxx_tz_get_temp_no_adc(struct thermal_zone_device *thermal,
217 unsigned long *temp)
218{
219 struct pm8xxx_tm_chip *chip = thermal->devdata;
220 int rc;
221
222 if (!chip || !temp)
223 return -EINVAL;
224
225 rc = pm8xxx_tm_update_temp_no_adc(chip);
226 if (rc < 0)
227 return rc;
228
229 *temp = chip->temp;
230
231 return 0;
232}
233
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530234static int pm8xxx_tz_get_temp_pm8058_adc(struct thermal_zone_device *thermal,
235 unsigned long *temp)
236{
237 struct pm8xxx_tm_chip *chip = thermal->devdata;
238 DECLARE_COMPLETION_ONSTACK(wait);
239 struct adc_chan_result adc_result = {
240 .physical = 0lu,
241 };
242 int rc;
243
244 if (!chip || !temp)
245 return -EINVAL;
246
247 *temp = chip->temp;
248
249 rc = adc_channel_request_conv(chip->adc_handle, &wait);
250 if (rc < 0) {
251 pr_err("%s: adc_channel_request_conv() failed, rc = %d\n",
252 __func__, rc);
253 return rc;
254 }
255
256 wait_for_completion(&wait);
257
258 rc = adc_channel_read_result(chip->adc_handle, &adc_result);
259 if (rc < 0) {
260 pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
261 __func__, rc);
262 return rc;
263 }
264
265 *temp = adc_result.physical;
266 chip->temp = adc_result.physical;
267
268 return 0;
269}
270
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700271static int pm8xxx_tz_get_temp_pm8xxx_adc(struct thermal_zone_device *thermal,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272 unsigned long *temp)
273{
274 struct pm8xxx_tm_chip *chip = thermal->devdata;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700275 struct pm8xxx_adc_chan_result result = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 .physical = 0lu,
277 };
278 int rc;
279
280 if (!chip || !temp)
281 return -EINVAL;
282
283 *temp = chip->temp;
284
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700285 rc = pm8xxx_adc_read(chip->cdata.adc_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286 if (rc < 0) {
287 pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
288 chip->cdata.tm_name, rc);
289 return rc;
290 }
291
292 *temp = result.physical;
293 chip->temp = result.physical;
294
295 return 0;
296}
297
298static int pm8xxx_tz_get_mode(struct thermal_zone_device *thermal,
299 enum thermal_device_mode *mode)
300{
301 struct pm8xxx_tm_chip *chip = thermal->devdata;
302
303 if (!chip || !mode)
304 return -EINVAL;
305
306 *mode = chip->mode;
307
308 return 0;
309}
310
311static int pm8xxx_tz_set_mode(struct thermal_zone_device *thermal,
312 enum thermal_device_mode mode)
313{
314 struct pm8xxx_tm_chip *chip = thermal->devdata;
315
316 if (!chip)
317 return -EINVAL;
318
David Collinsc4eb8e52012-09-10 14:43:14 -0700319 /* Mask software override requests if they are not allowed. */
320 if (!chip->cdata.allow_software_override)
321 mode = THERMAL_DEVICE_DISABLED;
322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 if (mode != chip->mode) {
324 if (mode == THERMAL_DEVICE_ENABLED)
325 pm8xxx_tm_shutdown_override(chip,
326 SOFTWARE_OVERRIDE_ENABLED);
327 else
328 pm8xxx_tm_shutdown_override(chip,
329 SOFTWARE_OVERRIDE_DISABLED);
330 }
331 chip->mode = mode;
332
333 return 0;
334}
335
336static int pm8xxx_tz_get_trip_type(struct thermal_zone_device *thermal,
337 int trip, enum thermal_trip_type *type)
338{
339 if (trip < 0 || !type)
340 return -EINVAL;
341
342 switch (trip) {
343 case TRIP_STAGE3:
344 *type = THERMAL_TRIP_CRITICAL;
345 break;
346 case TRIP_STAGE2:
347 *type = THERMAL_TRIP_HOT;
348 break;
349 case TRIP_STAGE1:
350 *type = THERMAL_TRIP_HOT;
351 break;
352 default:
353 return -EINVAL;
354 }
355
356 return 0;
357}
358
359static int pm8xxx_tz_get_trip_temp(struct thermal_zone_device *thermal,
360 int trip, unsigned long *temp)
361{
362 struct pm8xxx_tm_chip *chip = thermal->devdata;
363 int thresh_temp;
364
365 if (!chip || trip < 0 || !temp)
366 return -EINVAL;
367
368 thresh_temp = chip->thresh * TEMP_THRESH_STEP +
369 TEMP_THRESH_MIN;
370
371 switch (trip) {
372 case TRIP_STAGE3:
373 thresh_temp += 2 * TEMP_STAGE_STEP;
374 break;
375 case TRIP_STAGE2:
376 thresh_temp += TEMP_STAGE_STEP;
377 break;
378 case TRIP_STAGE1:
379 break;
380 default:
381 return -EINVAL;
382 }
383
384 *temp = thresh_temp;
385
386 return 0;
387}
388
389static int pm8xxx_tz_get_crit_temp(struct thermal_zone_device *thermal,
390 unsigned long *temp)
391{
392 struct pm8xxx_tm_chip *chip = thermal->devdata;
393
394 if (!chip || !temp)
395 return -EINVAL;
396
397 *temp = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN +
398 2 * TEMP_STAGE_STEP;
399
400 return 0;
401}
402
403static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_no_adc = {
404 .get_temp = pm8xxx_tz_get_temp_no_adc,
405 .get_mode = pm8xxx_tz_get_mode,
406 .set_mode = pm8xxx_tz_set_mode,
407 .get_trip_type = pm8xxx_tz_get_trip_type,
408 .get_trip_temp = pm8xxx_tz_get_trip_temp,
409 .get_crit_temp = pm8xxx_tz_get_crit_temp,
410};
411
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700412static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8xxx_adc = {
413 .get_temp = pm8xxx_tz_get_temp_pm8xxx_adc,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700414 .get_mode = pm8xxx_tz_get_mode,
415 .set_mode = pm8xxx_tz_set_mode,
416 .get_trip_type = pm8xxx_tz_get_trip_type,
417 .get_trip_temp = pm8xxx_tz_get_trip_temp,
418 .get_crit_temp = pm8xxx_tz_get_crit_temp,
419};
420
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530421static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8058_adc = {
422 .get_temp = pm8xxx_tz_get_temp_pm8058_adc,
423 .get_mode = pm8xxx_tz_get_mode,
424 .set_mode = pm8xxx_tz_set_mode,
425 .get_trip_type = pm8xxx_tz_get_trip_type,
426 .get_trip_temp = pm8xxx_tz_get_trip_temp,
427 .get_crit_temp = pm8xxx_tz_get_crit_temp,
428};
429
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430static void pm8xxx_tm_work(struct work_struct *work)
431{
David Collinsb2451ea2012-09-12 14:58:54 -0700432 struct delayed_work *dwork
433 = container_of(work, struct delayed_work, work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 struct pm8xxx_tm_chip *chip
David Collinsb2451ea2012-09-12 14:58:54 -0700435 = container_of(dwork, struct pm8xxx_tm_chip, irq_work);
David Collinsb42b2942012-09-12 14:47:03 -0700436 unsigned long temp = 0;
437 int rc, stage, thresh;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 u8 reg;
439
440 rc = pm8xxx_tm_read_ctrl(chip, &reg);
441 if (rc < 0)
442 goto bail;
443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444 /* Clear status bits. */
445 if (reg & (TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD)) {
446 reg &= ~(TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD
447 | TEMP_ALARM_CTRL_STATUS_MASK);
448
449 pm8xxx_tm_write_ctrl(chip, reg);
450 }
451
David Collinsb42b2942012-09-12 14:47:03 -0700452 stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
453 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
454 thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
455 >> TEMP_ALARM_CTRL_THRESH_SHIFT;
456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 thermal_zone_device_update(chip->tz_dev);
458
David Collinsb42b2942012-09-12 14:47:03 -0700459 if (stage != chip->prev_stage) {
460 chip->prev_stage = stage;
461
462 switch (chip->cdata.adc_type) {
463 case PM8XXX_TM_ADC_NONE:
464 rc = pm8xxx_tz_get_temp_no_adc(chip->tz_dev, &temp);
465 break;
466 case PM8XXX_TM_ADC_PM8058_ADC:
467 rc = pm8xxx_tz_get_temp_pm8058_adc(chip->tz_dev, &temp);
468 break;
469 case PM8XXX_TM_ADC_PM8XXX_ADC:
470 rc = pm8xxx_tz_get_temp_pm8xxx_adc(chip->tz_dev, &temp);
471 break;
472 }
473 if (rc < 0)
474 goto bail;
475
476 pr_crit("%s: PMIC Temp Alarm - stage=%u, threshold=%u, temp=%lu mC\n",
477 chip->cdata.tm_name, stage, thresh, temp);
478
479 /* Notify user space */
480 sysfs_notify(&chip->tz_dev->device.kobj, NULL, "type");
481 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482
483bail:
David Collinsb2451ea2012-09-12 14:58:54 -0700484 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485}
486
487static irqreturn_t pm8xxx_tm_isr(int irq, void *data)
488{
489 struct pm8xxx_tm_chip *chip = data;
490
David Collinsb2451ea2012-09-12 14:58:54 -0700491 schedule_delayed_work(&chip->irq_work,
492 msecs_to_jiffies(STATUS_REGISTER_DELAY_MS) + 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493
494 return IRQ_HANDLED;
495}
496
497static int pm8xxx_tm_init_reg(struct pm8xxx_tm_chip *chip)
498{
499 int rc;
500 u8 reg;
501
502 rc = pm8xxx_tm_read_ctrl(chip, &reg);
503 if (rc < 0)
504 return rc;
505
506 chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
507 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
508 chip->temp = 0;
509
510 /* Use temperature threshold set 0: (105, 125, 145) */
511 chip->thresh = 0;
512 reg = (chip->thresh << TEMP_ALARM_CTRL_THRESH_SHIFT)
513 & TEMP_ALARM_CTRL_THRESH_MASK;
514 rc = pm8xxx_tm_write_ctrl(chip, reg);
515 if (rc < 0)
516 return rc;
517
518 /*
519 * Set the PMIC alarm module PWM to have a frequency of 8 Hz. This
520 * helps cut down on the number of unnecessary interrupts fired when
521 * changing between thermal stages. Also, Enable the over temperature
522 * PWM whenever the PMIC is enabled.
523 */
524 reg = (1 << TEMP_ALARM_PWM_EN_SHIFT)
525 | (3 << TEMP_ALARM_PWM_PER_PRE_SHIFT)
526 | (3 << TEMP_ALARM_PWM_PER_DIV_SHIFT);
527
528 rc = pm8xxx_tm_write_pwm(chip, reg);
529
530 return rc;
531}
532
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530533static int pm8xxx_init_adc(struct pm8xxx_tm_chip *chip, bool enable)
534{
535 int rc = 0;
536
537 if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8058_ADC) {
538 if (enable) {
539 rc = adc_channel_open(chip->cdata.adc_channel,
540 &(chip->adc_handle));
541 if (rc < 0)
542 pr_err("adc_channel_open() failed.\n");
543 } else {
544 adc_channel_close(chip->adc_handle);
545 }
546 }
547
548 return rc;
549}
550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551static int __devinit pm8xxx_tm_probe(struct platform_device *pdev)
552{
553 const struct pm8xxx_tm_core_data *cdata = pdev->dev.platform_data;
554 struct thermal_zone_device_ops *tz_ops;
555 struct pm8xxx_tm_chip *chip;
556 struct resource *res;
557 int rc = 0;
558
559 if (!cdata) {
560 pr_err("missing core data\n");
561 return -EINVAL;
562 }
563
564 chip = kzalloc(sizeof(struct pm8xxx_tm_chip), GFP_KERNEL);
565 if (chip == NULL) {
566 pr_err("kzalloc() failed.\n");
567 return -ENOMEM;
568 }
569
570 chip->dev = &pdev->dev;
571 memcpy(&(chip->cdata), cdata, sizeof(struct pm8xxx_tm_core_data));
572
573 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
574 chip->cdata.irq_name_temp_stat);
575 if (res) {
576 chip->tempstat_irq = res->start;
577 } else {
578 pr_err("temp stat IRQ not specified\n");
579 goto err_free_chip;
580 }
581
582 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
583 chip->cdata.irq_name_over_temp);
584 if (res) {
585 chip->overtemp_irq = res->start;
586 } else {
587 pr_err("over temp IRQ not specified\n");
588 goto err_free_chip;
589 }
590
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530591 rc = pm8xxx_init_adc(chip, true);
592 if (rc < 0) {
593 pr_err("Unable to initialize adc\n");
594 goto err_free_chip;
595 }
596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597 /* Select proper thermal zone ops functions based on ADC type. */
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700598 if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8XXX_ADC)
599 tz_ops = &pm8xxx_thermal_zone_ops_pm8xxx_adc;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530600 else if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8058_ADC)
601 tz_ops = &pm8xxx_thermal_zone_ops_pm8058_adc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700602 else
603 tz_ops = &pm8xxx_thermal_zone_ops_no_adc;
604
605 chip->tz_dev = thermal_zone_device_register(chip->cdata.tm_name,
606 TRIP_NUM, chip, tz_ops, 0, 0, 0, 0);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 if (chip->tz_dev == NULL) {
609 pr_err("thermal_zone_device_register() failed.\n");
610 rc = -ENODEV;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530611 goto err_fail_adc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 }
613
614 rc = pm8xxx_tm_init_reg(chip);
615 if (rc < 0)
616 goto err_free_tz;
617 rc = pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
618 if (rc < 0)
619 goto err_free_tz;
620
621 if (chip->cdata.adc_type == PM8XXX_TM_ADC_NONE) {
622 rc = pm8xxx_tm_init_temp_no_adc(chip);
623 if (rc < 0)
624 goto err_free_tz;
625 }
626
627 /* Start in HW control; switch to SW control when user changes mode. */
628 chip->mode = THERMAL_DEVICE_DISABLED;
629 thermal_zone_device_update(chip->tz_dev);
630
David Collinsb2451ea2012-09-12 14:58:54 -0700631 INIT_DELAYED_WORK(&chip->irq_work, pm8xxx_tm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632
633 rc = request_irq(chip->tempstat_irq, pm8xxx_tm_isr, IRQF_TRIGGER_RISING,
634 chip->cdata.irq_name_temp_stat, chip);
635 if (rc < 0) {
636 pr_err("request_irq(%d) failed: %d\n", chip->tempstat_irq, rc);
637 goto err_cancel_work;
638 }
639
640 rc = request_irq(chip->overtemp_irq, pm8xxx_tm_isr, IRQF_TRIGGER_RISING,
641 chip->cdata.irq_name_over_temp, chip);
642 if (rc < 0) {
643 pr_err("request_irq(%d) failed: %d\n", chip->overtemp_irq, rc);
644 goto err_free_irq_tempstat;
645 }
646
647 platform_set_drvdata(pdev, chip);
648
649 pr_info("OK\n");
650
651 return 0;
652
653err_free_irq_tempstat:
654 free_irq(chip->tempstat_irq, chip);
655err_cancel_work:
David Collinsb2451ea2012-09-12 14:58:54 -0700656 cancel_delayed_work_sync(&chip->irq_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657err_free_tz:
658 thermal_zone_device_unregister(chip->tz_dev);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530659err_fail_adc:
660 pm8xxx_init_adc(chip, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661err_free_chip:
662 kfree(chip);
663 return rc;
664}
665
666static int __devexit pm8xxx_tm_remove(struct platform_device *pdev)
667{
668 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
669
670 if (chip) {
671 platform_set_drvdata(pdev, NULL);
David Collinsb2451ea2012-09-12 14:58:54 -0700672 cancel_delayed_work_sync(&chip->irq_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700673 free_irq(chip->overtemp_irq, chip);
674 free_irq(chip->tempstat_irq, chip);
675 pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530676 pm8xxx_init_adc(chip, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677 thermal_zone_device_unregister(chip->tz_dev);
678 kfree(chip);
679 }
680 return 0;
681}
682
683#ifdef CONFIG_PM
684static int pm8xxx_tm_suspend(struct device *dev)
685{
686 struct platform_device *pdev = to_platform_device(dev);
687 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
688
689 /* Clear override bits in suspend to allow hardware control */
690 pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
691
692 return 0;
693}
694
695static int pm8xxx_tm_resume(struct device *dev)
696{
697 struct platform_device *pdev = to_platform_device(dev);
698 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
699
700 /* Override hardware actions so software can control */
701 if (chip->mode == THERMAL_DEVICE_ENABLED)
702 pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_ENABLED);
703
704 return 0;
705}
706
707static const struct dev_pm_ops pm8xxx_tm_pm_ops = {
708 .suspend = pm8xxx_tm_suspend,
709 .resume = pm8xxx_tm_resume,
710};
711
712#define PM8XXX_TM_PM_OPS (&pm8xxx_tm_pm_ops)
713#else
714#define PM8XXX_TM_PM_OPS NULL
715#endif
716
717static struct platform_driver pm8xxx_tm_driver = {
718 .probe = pm8xxx_tm_probe,
719 .remove = __devexit_p(pm8xxx_tm_remove),
720 .driver = {
721 .name = PM8XXX_TM_DEV_NAME,
722 .owner = THIS_MODULE,
723 .pm = PM8XXX_TM_PM_OPS,
724 },
725};
726
727static int __init pm8xxx_tm_init(void)
728{
729 return platform_driver_register(&pm8xxx_tm_driver);
730}
731
732static void __exit pm8xxx_tm_exit(void)
733{
734 platform_driver_unregister(&pm8xxx_tm_driver);
735}
736
737module_init(pm8xxx_tm_init);
738module_exit(pm8xxx_tm_exit);
739
740MODULE_LICENSE("GPL v2");
741MODULE_DESCRIPTION("PM8xxx Thermal Manager driver");
742MODULE_VERSION("1.0");
743MODULE_ALIAS("platform:" PM8XXX_TM_DEV_NAME);