blob: 99a9454bd12d9936dc07e204e8fc6b99967677fc [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
Anirudh Ghayal9f072112013-04-12 16:50:40 +05302 * Copyright (c) 2011-2013, 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 */
David Collins2bd7fe42012-11-20 14:52:37 -080036#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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045
David Collins2bd7fe42012-11-20 14:52:37 -080046#define TEMP_STAGE_STEP 20000 /* Stage step: 20.000 C */
47#define TEMP_STAGE_HYSTERESIS 2000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048
David Collins2bd7fe42012-11-20 14:52:37 -080049#define TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */
50#define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051
52/* Register TEMP_ALARM_PWM bits */
David Collins2bd7fe42012-11-20 14:52:37 -080053#define TEMP_ALARM_PWM_EN_MASK 0xC0
54#define TEMP_ALARM_PWM_EN_NEVER 0x00
55#define TEMP_ALARM_PWM_EN_SLEEP_B 0x40
56#define TEMP_ALARM_PWM_EN_PWM 0x80
57#define TEMP_ALARM_PWM_EN_ALWAYS 0xC0
58#define TEMP_ALARM_PWM_PER_PRE_MASK 0x38
59#define TEMP_ALARM_PWM_PER_PRE_SHIFT 3
60#define TEMP_ALARM_PWM_PER_DIV_MASK 0x07
61#define TEMP_ALARM_PWM_PER_DIV_SHIFT 0
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062
63/* Trips: from critical to less critical */
64#define TRIP_STAGE3 0
65#define TRIP_STAGE2 1
66#define TRIP_STAGE1 2
67#define TRIP_NUM 3
68
69struct pm8xxx_tm_chip {
70 struct pm8xxx_tm_core_data cdata;
David Collinsa42ed242012-09-12 14:58:54 -070071 struct delayed_work irq_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072 struct device *dev;
73 struct thermal_zone_device *tz_dev;
74 unsigned long temp;
David Collins76e6e2a2012-09-12 14:47:03 -070075 unsigned int prev_stage;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076 enum thermal_device_mode mode;
77 unsigned int thresh;
78 unsigned int stage;
79 unsigned int tempstat_irq;
80 unsigned int overtemp_irq;
81 void *adc_handle;
82};
83
84enum pmic_thermal_override_mode {
85 SOFTWARE_OVERRIDE_DISABLED = 0,
86 SOFTWARE_OVERRIDE_ENABLED,
87};
88
David Collinsa42ed242012-09-12 14:58:54 -070089/* Delay between TEMP_STAT IRQ going high and status value changing in ms. */
90#define STATUS_REGISTER_DELAY_MS 40
91
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092static inline int pm8xxx_tm_read_ctrl(struct pm8xxx_tm_chip *chip, u8 *reg)
93{
94 int rc;
95
96 rc = pm8xxx_readb(chip->dev->parent,
97 chip->cdata.reg_addr_temp_alarm_ctrl, reg);
98 if (rc)
99 pr_err("%s: pm8xxx_readb(0x%03X) failed, rc=%d\n",
100 chip->cdata.tm_name,
101 chip->cdata.reg_addr_temp_alarm_ctrl, rc);
102
103 return rc;
104}
105
106static inline int pm8xxx_tm_write_ctrl(struct pm8xxx_tm_chip *chip, u8 reg)
107{
108 int rc;
109
110 rc = pm8xxx_writeb(chip->dev->parent,
111 chip->cdata.reg_addr_temp_alarm_ctrl, reg);
112 if (rc)
113 pr_err("%s: pm8xxx_writeb(0x%03X)=0x%02X failed, rc=%d\n",
114 chip->cdata.tm_name,
115 chip->cdata.reg_addr_temp_alarm_ctrl, reg, rc);
116
117 return rc;
118}
119
120static inline int pm8xxx_tm_write_pwm(struct pm8xxx_tm_chip *chip, u8 reg)
121{
122 int rc;
123
124 rc = pm8xxx_writeb(chip->dev->parent,
125 chip->cdata.reg_addr_temp_alarm_pwm, reg);
126 if (rc)
127 pr_err("%s: pm8xxx_writeb(0x%03X)=0x%02X failed, rc=%d\n",
128 chip->cdata.tm_name,
129 chip->cdata.reg_addr_temp_alarm_pwm, reg, rc);
130
131 return rc;
132}
133
134static inline int
135pm8xxx_tm_shutdown_override(struct pm8xxx_tm_chip *chip,
136 enum pmic_thermal_override_mode mode)
137{
138 int rc;
139 u8 reg;
140
141 rc = pm8xxx_tm_read_ctrl(chip, &reg);
142 if (rc < 0)
143 return rc;
144
145 reg &= ~(TEMP_ALARM_CTRL_OVRD_MASK | TEMP_ALARM_CTRL_STATUS_MASK);
146 if (mode == SOFTWARE_OVERRIDE_ENABLED)
147 reg |= (TEMP_ALARM_CTRL_OVRD_ST3 | TEMP_ALARM_CTRL_OVRD_ST2) &
148 TEMP_ALARM_CTRL_OVRD_MASK;
149
150 rc = pm8xxx_tm_write_ctrl(chip, reg);
151
152 return rc;
153}
154
155/*
156 * This function initializes the internal temperature value based on only the
157 * current thermal stage and threshold.
158 */
159static int pm8xxx_tm_init_temp_no_adc(struct pm8xxx_tm_chip *chip)
160{
161 int rc;
162 u8 reg;
163
164 rc = pm8xxx_tm_read_ctrl(chip, &reg);
165 if (rc < 0)
166 return rc;
167
168 chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
169 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
170 chip->thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
171 >> TEMP_ALARM_CTRL_THRESH_SHIFT;
172
173 if (chip->stage)
174 chip->temp = chip->thresh * TEMP_THRESH_MIN +
175 (chip->stage - 1) * TEMP_STAGE_STEP +
176 TEMP_THRESH_MIN;
177 else
178 chip->temp = chip->cdata.default_no_adc_temp;
179
180 return 0;
181}
182
183/*
184 * This function updates the internal temperature value based on the
185 * current thermal stage and threshold as well as the previous stage
186 */
187static int pm8xxx_tm_update_temp_no_adc(struct pm8xxx_tm_chip *chip)
188{
189 unsigned int stage;
190 int rc;
191 u8 reg;
192
193 rc = pm8xxx_tm_read_ctrl(chip, &reg);
194 if (rc < 0)
195 return rc;
196
197 stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
198 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
199 chip->thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
200 >> TEMP_ALARM_CTRL_THRESH_SHIFT;
201
202 if (stage > chip->stage) {
203 /* increasing stage, use lower bound */
204 chip->temp = (stage - 1) * TEMP_STAGE_STEP
205 + chip->thresh * TEMP_THRESH_STEP
206 + TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
207 } else if (stage < chip->stage) {
208 /* decreasing stage, use upper bound */
209 chip->temp = stage * TEMP_STAGE_STEP
210 + chip->thresh * TEMP_THRESH_STEP
211 - TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN;
212 }
213
214 chip->stage = stage;
215
216 return 0;
217}
218
219static int pm8xxx_tz_get_temp_no_adc(struct thermal_zone_device *thermal,
220 unsigned long *temp)
221{
222 struct pm8xxx_tm_chip *chip = thermal->devdata;
223 int rc;
224
225 if (!chip || !temp)
226 return -EINVAL;
227
228 rc = pm8xxx_tm_update_temp_no_adc(chip);
229 if (rc < 0)
230 return rc;
231
232 *temp = chip->temp;
233
234 return 0;
235}
236
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530237static int pm8xxx_tz_get_temp_pm8058_adc(struct thermal_zone_device *thermal,
238 unsigned long *temp)
239{
240 struct pm8xxx_tm_chip *chip = thermal->devdata;
241 DECLARE_COMPLETION_ONSTACK(wait);
242 struct adc_chan_result adc_result = {
243 .physical = 0lu,
244 };
245 int rc;
246
247 if (!chip || !temp)
248 return -EINVAL;
249
250 *temp = chip->temp;
251
252 rc = adc_channel_request_conv(chip->adc_handle, &wait);
253 if (rc < 0) {
254 pr_err("%s: adc_channel_request_conv() failed, rc = %d\n",
255 __func__, rc);
256 return rc;
257 }
258
259 wait_for_completion(&wait);
260
261 rc = adc_channel_read_result(chip->adc_handle, &adc_result);
262 if (rc < 0) {
263 pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
264 __func__, rc);
265 return rc;
266 }
267
268 *temp = adc_result.physical;
269 chip->temp = adc_result.physical;
270
271 return 0;
272}
273
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700274static int pm8xxx_tz_get_temp_pm8xxx_adc(struct thermal_zone_device *thermal,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 unsigned long *temp)
276{
277 struct pm8xxx_tm_chip *chip = thermal->devdata;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700278 struct pm8xxx_adc_chan_result result = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 .physical = 0lu,
280 };
281 int rc;
282
283 if (!chip || !temp)
284 return -EINVAL;
285
286 *temp = chip->temp;
287
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700288 rc = pm8xxx_adc_read(chip->cdata.adc_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 if (rc < 0) {
290 pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
291 chip->cdata.tm_name, rc);
292 return rc;
293 }
294
295 *temp = result.physical;
296 chip->temp = result.physical;
297
298 return 0;
299}
300
301static int pm8xxx_tz_get_mode(struct thermal_zone_device *thermal,
302 enum thermal_device_mode *mode)
303{
304 struct pm8xxx_tm_chip *chip = thermal->devdata;
305
306 if (!chip || !mode)
307 return -EINVAL;
308
309 *mode = chip->mode;
310
311 return 0;
312}
313
314static int pm8xxx_tz_set_mode(struct thermal_zone_device *thermal,
315 enum thermal_device_mode mode)
316{
317 struct pm8xxx_tm_chip *chip = thermal->devdata;
318
319 if (!chip)
320 return -EINVAL;
321
David Collins8f6d8a82012-09-10 14:43:14 -0700322 /* Mask software override requests if they are not allowed. */
323 if (!chip->cdata.allow_software_override)
324 mode = THERMAL_DEVICE_DISABLED;
325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326 if (mode != chip->mode) {
327 if (mode == THERMAL_DEVICE_ENABLED)
328 pm8xxx_tm_shutdown_override(chip,
329 SOFTWARE_OVERRIDE_ENABLED);
330 else
331 pm8xxx_tm_shutdown_override(chip,
332 SOFTWARE_OVERRIDE_DISABLED);
333 }
334 chip->mode = mode;
335
336 return 0;
337}
338
339static int pm8xxx_tz_get_trip_type(struct thermal_zone_device *thermal,
340 int trip, enum thermal_trip_type *type)
341{
342 if (trip < 0 || !type)
343 return -EINVAL;
344
345 switch (trip) {
346 case TRIP_STAGE3:
347 *type = THERMAL_TRIP_CRITICAL;
348 break;
349 case TRIP_STAGE2:
350 *type = THERMAL_TRIP_HOT;
351 break;
352 case TRIP_STAGE1:
353 *type = THERMAL_TRIP_HOT;
354 break;
355 default:
356 return -EINVAL;
357 }
358
359 return 0;
360}
361
362static int pm8xxx_tz_get_trip_temp(struct thermal_zone_device *thermal,
363 int trip, unsigned long *temp)
364{
365 struct pm8xxx_tm_chip *chip = thermal->devdata;
366 int thresh_temp;
367
368 if (!chip || trip < 0 || !temp)
369 return -EINVAL;
370
371 thresh_temp = chip->thresh * TEMP_THRESH_STEP +
372 TEMP_THRESH_MIN;
373
374 switch (trip) {
375 case TRIP_STAGE3:
376 thresh_temp += 2 * TEMP_STAGE_STEP;
377 break;
378 case TRIP_STAGE2:
379 thresh_temp += TEMP_STAGE_STEP;
380 break;
381 case TRIP_STAGE1:
382 break;
383 default:
384 return -EINVAL;
385 }
386
387 *temp = thresh_temp;
388
389 return 0;
390}
391
392static int pm8xxx_tz_get_crit_temp(struct thermal_zone_device *thermal,
393 unsigned long *temp)
394{
395 struct pm8xxx_tm_chip *chip = thermal->devdata;
396
397 if (!chip || !temp)
398 return -EINVAL;
399
400 *temp = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN +
401 2 * TEMP_STAGE_STEP;
402
403 return 0;
404}
405
406static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_no_adc = {
407 .get_temp = pm8xxx_tz_get_temp_no_adc,
408 .get_mode = pm8xxx_tz_get_mode,
409 .set_mode = pm8xxx_tz_set_mode,
410 .get_trip_type = pm8xxx_tz_get_trip_type,
411 .get_trip_temp = pm8xxx_tz_get_trip_temp,
412 .get_crit_temp = pm8xxx_tz_get_crit_temp,
413};
414
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700415static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8xxx_adc = {
416 .get_temp = pm8xxx_tz_get_temp_pm8xxx_adc,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 .get_mode = pm8xxx_tz_get_mode,
418 .set_mode = pm8xxx_tz_set_mode,
419 .get_trip_type = pm8xxx_tz_get_trip_type,
420 .get_trip_temp = pm8xxx_tz_get_trip_temp,
421 .get_crit_temp = pm8xxx_tz_get_crit_temp,
422};
423
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530424static struct thermal_zone_device_ops pm8xxx_thermal_zone_ops_pm8058_adc = {
425 .get_temp = pm8xxx_tz_get_temp_pm8058_adc,
426 .get_mode = pm8xxx_tz_get_mode,
427 .set_mode = pm8xxx_tz_set_mode,
428 .get_trip_type = pm8xxx_tz_get_trip_type,
429 .get_trip_temp = pm8xxx_tz_get_trip_temp,
430 .get_crit_temp = pm8xxx_tz_get_crit_temp,
431};
432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433static void pm8xxx_tm_work(struct work_struct *work)
434{
David Collinsa42ed242012-09-12 14:58:54 -0700435 struct delayed_work *dwork
436 = container_of(work, struct delayed_work, work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 struct pm8xxx_tm_chip *chip
David Collinsa42ed242012-09-12 14:58:54 -0700438 = container_of(dwork, struct pm8xxx_tm_chip, irq_work);
David Collins76e6e2a2012-09-12 14:47:03 -0700439 unsigned long temp = 0;
440 int rc, stage, thresh;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700441 u8 reg;
442
443 rc = pm8xxx_tm_read_ctrl(chip, &reg);
444 if (rc < 0)
445 goto bail;
446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 /* Clear status bits. */
448 if (reg & (TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD)) {
449 reg &= ~(TEMP_ALARM_CTRL_ST2_SD | TEMP_ALARM_CTRL_ST3_SD
450 | TEMP_ALARM_CTRL_STATUS_MASK);
451
452 pm8xxx_tm_write_ctrl(chip, reg);
453 }
454
David Collins76e6e2a2012-09-12 14:47:03 -0700455 stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
456 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
457 thresh = (reg & TEMP_ALARM_CTRL_THRESH_MASK)
458 >> TEMP_ALARM_CTRL_THRESH_SHIFT;
459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 thermal_zone_device_update(chip->tz_dev);
461
David Collins76e6e2a2012-09-12 14:47:03 -0700462 if (stage != chip->prev_stage) {
463 chip->prev_stage = stage;
464
465 switch (chip->cdata.adc_type) {
466 case PM8XXX_TM_ADC_NONE:
467 rc = pm8xxx_tz_get_temp_no_adc(chip->tz_dev, &temp);
468 break;
469 case PM8XXX_TM_ADC_PM8058_ADC:
470 rc = pm8xxx_tz_get_temp_pm8058_adc(chip->tz_dev, &temp);
471 break;
472 case PM8XXX_TM_ADC_PM8XXX_ADC:
473 rc = pm8xxx_tz_get_temp_pm8xxx_adc(chip->tz_dev, &temp);
474 break;
475 }
476 if (rc < 0)
477 goto bail;
478
479 pr_crit("%s: PMIC Temp Alarm - stage=%u, threshold=%u, temp=%lu mC\n",
480 chip->cdata.tm_name, stage, thresh, temp);
481
482 /* Notify user space */
483 sysfs_notify(&chip->tz_dev->device.kobj, NULL, "type");
484 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485
486bail:
David Collinsa42ed242012-09-12 14:58:54 -0700487 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488}
489
490static irqreturn_t pm8xxx_tm_isr(int irq, void *data)
491{
492 struct pm8xxx_tm_chip *chip = data;
493
David Collinsa42ed242012-09-12 14:58:54 -0700494 schedule_delayed_work(&chip->irq_work,
495 msecs_to_jiffies(STATUS_REGISTER_DELAY_MS) + 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496
497 return IRQ_HANDLED;
498}
499
500static int pm8xxx_tm_init_reg(struct pm8xxx_tm_chip *chip)
501{
502 int rc;
503 u8 reg;
504
505 rc = pm8xxx_tm_read_ctrl(chip, &reg);
506 if (rc < 0)
507 return rc;
508
509 chip->stage = (reg & TEMP_ALARM_CTRL_STATUS_MASK)
510 >> TEMP_ALARM_CTRL_STATUS_SHIFT;
511 chip->temp = 0;
512
513 /* Use temperature threshold set 0: (105, 125, 145) */
514 chip->thresh = 0;
515 reg = (chip->thresh << TEMP_ALARM_CTRL_THRESH_SHIFT)
516 & TEMP_ALARM_CTRL_THRESH_MASK;
517 rc = pm8xxx_tm_write_ctrl(chip, reg);
518 if (rc < 0)
519 return rc;
520
521 /*
David Collins2bd7fe42012-11-20 14:52:37 -0800522 * Set the PMIC temperature alarm module to be always on. This ensures
523 * that die temperature monitoring is active even if CXO is disabled
524 * (i.e. when sleep_b is low). This is necessary since CXO can be
525 * disabled while the system is still heavily loaded. Also, using
526 * the alway-on instead of PWM-enabled configurations ensures that the
527 * die temperature can be measured by the PMIC ADC without reconfiguring
528 * the temperature alarm module first.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 */
David Collins2bd7fe42012-11-20 14:52:37 -0800530 rc = pm8xxx_tm_write_pwm(chip, TEMP_ALARM_PWM_EN_ALWAYS);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531
532 return rc;
533}
534
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530535static int pm8xxx_init_adc(struct pm8xxx_tm_chip *chip, bool enable)
536{
537 int rc = 0;
538
539 if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8058_ADC) {
540 if (enable) {
541 rc = adc_channel_open(chip->cdata.adc_channel,
542 &(chip->adc_handle));
543 if (rc < 0)
544 pr_err("adc_channel_open() failed.\n");
545 } else {
546 adc_channel_close(chip->adc_handle);
547 }
548 }
549
550 return rc;
551}
552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553static int __devinit pm8xxx_tm_probe(struct platform_device *pdev)
554{
555 const struct pm8xxx_tm_core_data *cdata = pdev->dev.platform_data;
556 struct thermal_zone_device_ops *tz_ops;
557 struct pm8xxx_tm_chip *chip;
558 struct resource *res;
559 int rc = 0;
560
561 if (!cdata) {
562 pr_err("missing core data\n");
563 return -EINVAL;
564 }
565
566 chip = kzalloc(sizeof(struct pm8xxx_tm_chip), GFP_KERNEL);
567 if (chip == NULL) {
568 pr_err("kzalloc() failed.\n");
569 return -ENOMEM;
570 }
571
572 chip->dev = &pdev->dev;
573 memcpy(&(chip->cdata), cdata, sizeof(struct pm8xxx_tm_core_data));
574
575 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
576 chip->cdata.irq_name_temp_stat);
577 if (res) {
578 chip->tempstat_irq = res->start;
579 } else {
580 pr_err("temp stat IRQ not specified\n");
581 goto err_free_chip;
582 }
583
584 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
585 chip->cdata.irq_name_over_temp);
586 if (res) {
587 chip->overtemp_irq = res->start;
588 } else {
589 pr_err("over temp IRQ not specified\n");
590 goto err_free_chip;
591 }
592
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530593 rc = pm8xxx_init_adc(chip, true);
594 if (rc < 0) {
595 pr_err("Unable to initialize adc\n");
596 goto err_free_chip;
597 }
598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 /* Select proper thermal zone ops functions based on ADC type. */
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700600 if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8XXX_ADC)
601 tz_ops = &pm8xxx_thermal_zone_ops_pm8xxx_adc;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530602 else if (chip->cdata.adc_type == PM8XXX_TM_ADC_PM8058_ADC)
603 tz_ops = &pm8xxx_thermal_zone_ops_pm8058_adc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604 else
605 tz_ops = &pm8xxx_thermal_zone_ops_no_adc;
606
607 chip->tz_dev = thermal_zone_device_register(chip->cdata.tm_name,
608 TRIP_NUM, chip, tz_ops, 0, 0, 0, 0);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 if (chip->tz_dev == NULL) {
611 pr_err("thermal_zone_device_register() failed.\n");
612 rc = -ENODEV;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530613 goto err_fail_adc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614 }
615
616 rc = pm8xxx_tm_init_reg(chip);
617 if (rc < 0)
618 goto err_free_tz;
619 rc = pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
620 if (rc < 0)
621 goto err_free_tz;
622
623 if (chip->cdata.adc_type == PM8XXX_TM_ADC_NONE) {
624 rc = pm8xxx_tm_init_temp_no_adc(chip);
625 if (rc < 0)
626 goto err_free_tz;
627 }
628
629 /* Start in HW control; switch to SW control when user changes mode. */
630 chip->mode = THERMAL_DEVICE_DISABLED;
631 thermal_zone_device_update(chip->tz_dev);
632
David Collinsa42ed242012-09-12 14:58:54 -0700633 INIT_DELAYED_WORK(&chip->irq_work, pm8xxx_tm_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634
635 rc = request_irq(chip->tempstat_irq, pm8xxx_tm_isr, IRQF_TRIGGER_RISING,
636 chip->cdata.irq_name_temp_stat, chip);
637 if (rc < 0) {
638 pr_err("request_irq(%d) failed: %d\n", chip->tempstat_irq, rc);
639 goto err_cancel_work;
640 }
641
642 rc = request_irq(chip->overtemp_irq, pm8xxx_tm_isr, IRQF_TRIGGER_RISING,
643 chip->cdata.irq_name_over_temp, chip);
644 if (rc < 0) {
645 pr_err("request_irq(%d) failed: %d\n", chip->overtemp_irq, rc);
646 goto err_free_irq_tempstat;
647 }
648
649 platform_set_drvdata(pdev, chip);
650
651 pr_info("OK\n");
652
653 return 0;
654
655err_free_irq_tempstat:
656 free_irq(chip->tempstat_irq, chip);
657err_cancel_work:
David Collinsa42ed242012-09-12 14:58:54 -0700658 cancel_delayed_work_sync(&chip->irq_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659err_free_tz:
660 thermal_zone_device_unregister(chip->tz_dev);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530661err_fail_adc:
662 pm8xxx_init_adc(chip, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663err_free_chip:
664 kfree(chip);
665 return rc;
666}
667
668static int __devexit pm8xxx_tm_remove(struct platform_device *pdev)
669{
670 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
671
672 if (chip) {
673 platform_set_drvdata(pdev, NULL);
David Collinsa42ed242012-09-12 14:58:54 -0700674 cancel_delayed_work_sync(&chip->irq_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 free_irq(chip->overtemp_irq, chip);
676 free_irq(chip->tempstat_irq, chip);
677 pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530678 pm8xxx_init_adc(chip, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 thermal_zone_device_unregister(chip->tz_dev);
680 kfree(chip);
681 }
682 return 0;
683}
684
Anirudh Ghayal9f072112013-04-12 16:50:40 +0530685static void pm8xxx_tm_shutdown(struct platform_device *pdev)
686{
687 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
688
689 pm8xxx_tm_write_pwm(chip, TEMP_ALARM_PWM_EN_NEVER);
690}
691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692#ifdef CONFIG_PM
693static int pm8xxx_tm_suspend(struct device *dev)
694{
695 struct platform_device *pdev = to_platform_device(dev);
696 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
697
698 /* Clear override bits in suspend to allow hardware control */
699 pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
700
701 return 0;
702}
703
704static int pm8xxx_tm_resume(struct device *dev)
705{
706 struct platform_device *pdev = to_platform_device(dev);
707 struct pm8xxx_tm_chip *chip = platform_get_drvdata(pdev);
708
709 /* Override hardware actions so software can control */
710 if (chip->mode == THERMAL_DEVICE_ENABLED)
711 pm8xxx_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_ENABLED);
712
713 return 0;
714}
715
716static const struct dev_pm_ops pm8xxx_tm_pm_ops = {
717 .suspend = pm8xxx_tm_suspend,
718 .resume = pm8xxx_tm_resume,
719};
720
721#define PM8XXX_TM_PM_OPS (&pm8xxx_tm_pm_ops)
722#else
723#define PM8XXX_TM_PM_OPS NULL
724#endif
725
726static struct platform_driver pm8xxx_tm_driver = {
727 .probe = pm8xxx_tm_probe,
728 .remove = __devexit_p(pm8xxx_tm_remove),
Anirudh Ghayal9f072112013-04-12 16:50:40 +0530729 .shutdown = pm8xxx_tm_shutdown,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730 .driver = {
731 .name = PM8XXX_TM_DEV_NAME,
732 .owner = THIS_MODULE,
733 .pm = PM8XXX_TM_PM_OPS,
734 },
735};
736
737static int __init pm8xxx_tm_init(void)
738{
739 return platform_driver_register(&pm8xxx_tm_driver);
740}
741
742static void __exit pm8xxx_tm_exit(void)
743{
744 platform_driver_unregister(&pm8xxx_tm_driver);
745}
746
747module_init(pm8xxx_tm_init);
748module_exit(pm8xxx_tm_exit);
749
750MODULE_LICENSE("GPL v2");
751MODULE_DESCRIPTION("PM8xxx Thermal Manager driver");
752MODULE_VERSION("1.0");
753MODULE_ALIAS("platform:" PM8XXX_TM_DEV_NAME);