blob: 0ff57885d00fd032a621849fccdf7f7277afffae [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13/*
14 * Qualcomm PMIC8901 Thermal Manager driver
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/err.h>
21#include <linux/thermal.h>
22#include <linux/interrupt.h>
23#include <linux/slab.h>
24#include <linux/mfd/pmic8901.h>
25
26/* PMIC8901 TEMP_ALRM registers */
27#define SSBI_REG_TEMP_ALRM_CTRL 0x23
28#define SSBI_REG_TEMP_ALRM_PWM 0x24
29
30/* TEMP_ALRM_CTRL */
31#define PM8901_TEMP_ST3_SD 0x80
32#define PM8901_TEMP_ST2_SD 0x40
33#define PM8901_TEMP_STATUS_MASK 0x30
34#define PM8901_TEMP_STATUS_SHIFT 4
35#define PM8901_TEMP_THRESH_MASK 0x0C
36#define PM8901_TEMP_THRESH_SHIFT 2
37#define PM8901_TEMP_OVRD_ST3 0x02
38#define PM8901_TEMP_OVRD_ST2 0x01
39#define PM8901_TEMP_OVRD_MASK 0x03
40
41#define PM8901_TEMP_STAGE_STEP 20000 /* Stage step: 20 C */
42#define PM8901_TEMP_STAGE_HYSTERESIS 2000
43
44#define PM8901_TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */
45#define PM8901_TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */
46
47/* TEMP_ALRM_PWM */
48#define PM8901_TEMP_PWM_EN_MASK 0xC0
49#define PM8901_TEMP_PWM_EN_SHIFT 6
50#define PM8901_TEMP_PWM_PER_PRE_MASK 0x38
51#define PM8901_TEMP_PWM_PER_PRE_SHIFT 3
52#define PM8901_TEMP_PWM_PER_DIV_MASK 0x07
53#define PM8901_TEMP_PWM_PER_DIV_SHIFT 0
54
55/* Trips: from critical to less critical */
56#define PM8901_TRIP_STAGE3 0
57#define PM8901_TRIP_STAGE2 1
58#define PM8901_TRIP_STAGE1 2
59#define PM8901_TRIP_NUM 3
60
61/* Used because there is no means to read the die temperature */
62#define DEFAULT_NO_ADC_TEMP 37000
63
64struct pm8901_tm_device {
65 struct pm8901_chip *pm_chip;
66 struct thermal_zone_device *tz_dev;
67 unsigned long temp;
68 enum thermal_device_mode mode;
69 unsigned int thresh;
70 unsigned int stage;
71 unsigned int irq;
72 unsigned int hi_irq;
73};
74
75enum pmic_thermal_override_mode {
76 SOFTWARE_OVERRIDE_DISABLED = 0,
77 SOFTWARE_OVERRIDE_ENABLED,
78};
79
80static inline int pm8901_tm_read_ctrl(struct pm8901_chip *chip, u8 *reg)
81{
82 int rc;
83
84 rc = pm8901_read(chip, SSBI_REG_TEMP_ALRM_CTRL, reg, 1);
85 if (rc)
86 pr_err("%s: pm8901_read FAIL: rc=%d\n", __func__, rc);
87
88 return rc;
89}
90
91static inline int pm8901_tm_write_ctrl(struct pm8901_chip *chip, u8 reg)
92{
93 int rc;
94
95 rc = pm8901_write(chip, SSBI_REG_TEMP_ALRM_CTRL, &reg, 1);
96 if (rc)
97 pr_err("%s: pm8901_write FAIL: rc=%d\n", __func__, rc);
98
99 return rc;
100}
101
102static inline int pm8901_tm_read_pwm(struct pm8901_chip *chip, u8 *reg)
103{
104 int rc;
105
106 rc = pm8901_read(chip, SSBI_REG_TEMP_ALRM_PWM, reg, 1);
107 if (rc)
108 pr_err("%s: pm8901_read FAIL: rc=%d\n", __func__, rc);
109
110 return rc;
111}
112
113static inline int pm8901_tm_write_pwm(struct pm8901_chip *chip, u8 reg)
114{
115 int rc;
116
117 rc = pm8901_write(chip, SSBI_REG_TEMP_ALRM_PWM, &reg, 1);
118 if (rc)
119 pr_err("%s: pm8901_write FAIL: rc=%d\n", __func__, rc);
120
121 return rc;
122}
123
124static inline int
125pm8901_tm_shutdown_override(struct pm8901_chip *chip,
126 enum pmic_thermal_override_mode mode)
127{
128 int rc;
129 u8 reg;
130
131 rc = pm8901_tm_read_ctrl(chip, &reg);
132 if (rc < 0)
133 return rc;
134
135 reg &= ~(PM8901_TEMP_OVRD_MASK | PM8901_TEMP_STATUS_MASK);
136 if (mode == SOFTWARE_OVERRIDE_ENABLED)
137 reg |= (PM8901_TEMP_OVRD_ST3 | PM8901_TEMP_OVRD_ST2) &
138 PM8901_TEMP_OVRD_MASK;
139
140 rc = pm8901_tm_write_ctrl(chip, reg);
141
142 return rc;
143}
144
145/*
146 * This function initializes the internal temperature value based on only the
147 * current thermal stage and threshold.
148 */
149static int pm8901_tm_init_temp(struct pm8901_tm_device *tm)
150{
151 int rc;
152 u8 reg;
153
154 rc = pm8901_tm_read_ctrl(tm->pm_chip, &reg);
155 if (rc < 0)
156 return rc;
157
158 tm->stage = (reg & PM8901_TEMP_STATUS_MASK) >> PM8901_TEMP_STATUS_SHIFT;
159 tm->thresh = (reg & PM8901_TEMP_THRESH_MASK) >>
160 PM8901_TEMP_THRESH_SHIFT;
161
162 if (tm->stage) {
163 tm->temp = tm->thresh * PM8901_TEMP_THRESH_STEP +
164 (tm->stage - 1) * PM8901_TEMP_STAGE_STEP +
165 PM8901_TEMP_THRESH_MIN;
166 } else
167 tm->temp = DEFAULT_NO_ADC_TEMP;
168
169 return 0;
170}
171
172/*
173 * This function updates the internal temperature value based on the
174 * current thermal stage and threshold as well as the previous stage
175 */
176static int pm8901_tm_update_temp(struct pm8901_tm_device *tm)
177{
178 unsigned int stage;
179 int rc;
180 u8 reg;
181
182 rc = pm8901_tm_read_ctrl(tm->pm_chip, &reg);
183 if (rc < 0)
184 return rc;
185
186 stage = (reg & PM8901_TEMP_STATUS_MASK) >> PM8901_TEMP_STATUS_SHIFT;
187 tm->thresh = (reg & PM8901_TEMP_THRESH_MASK) >>
188 PM8901_TEMP_THRESH_SHIFT;
189
190 if (stage > tm->stage) {
191 /* increasing stage, use lower bound */
192 tm->temp = (stage-1) * PM8901_TEMP_STAGE_STEP +
193 tm->thresh * PM8901_TEMP_THRESH_STEP +
194 PM8901_TEMP_STAGE_HYSTERESIS +
195 PM8901_TEMP_THRESH_MIN;
196 } else if (stage < tm->stage) {
197 /* decreasing stage, use upper bound */
198 tm->temp = stage * PM8901_TEMP_STAGE_STEP +
199 tm->thresh * PM8901_TEMP_THRESH_STEP -
200 PM8901_TEMP_STAGE_HYSTERESIS +
201 PM8901_TEMP_THRESH_MIN;
202 }
203
204 tm->stage = stage;
205
206 return 0;
207}
208
209static int pm8901_tz_get_temp(struct thermal_zone_device *thermal,
210 unsigned long *temp)
211{
212 struct pm8901_tm_device *tm = thermal->devdata;
213 int rc;
214
215 if (!tm || !temp)
216 return -EINVAL;
217
218 rc = pm8901_tm_update_temp(tm);
219 if (rc < 0)
220 return rc;
221
222 *temp = tm->temp;
223
224 return 0;
225}
226
227static int pm8901_tz_get_mode(struct thermal_zone_device *thermal,
228 enum thermal_device_mode *mode)
229{
230 struct pm8901_tm_device *tm = thermal->devdata;
231
232 if (!tm || !mode)
233 return -EINVAL;
234
235 *mode = tm->mode;
236
237 return 0;
238}
239
240static int pm8901_tz_set_mode(struct thermal_zone_device *thermal,
241 enum thermal_device_mode mode)
242{
243 struct pm8901_tm_device *tm = thermal->devdata;
244
245 if (!tm)
246 return -EINVAL;
247
248 if (mode != tm->mode) {
249 pr_info("%s: mode: %d --> %d\n", __func__, tm->mode, mode);
250
251 if (mode == THERMAL_DEVICE_ENABLED)
252 pm8901_tm_shutdown_override(tm->pm_chip,
253 SOFTWARE_OVERRIDE_ENABLED);
254 else
255 pm8901_tm_shutdown_override(tm->pm_chip,
256 SOFTWARE_OVERRIDE_DISABLED);
257 }
258 tm->mode = mode;
259
260 return 0;
261}
262
263static int pm8901_tz_get_trip_type(struct thermal_zone_device *thermal,
264 int trip, enum thermal_trip_type *type)
265{
266 struct pm8901_tm_device *tm = thermal->devdata;
267
268 if (!tm || trip < 0 || !type)
269 return -EINVAL;
270
271 switch (trip) {
272 case PM8901_TRIP_STAGE3:
273 *type = THERMAL_TRIP_CRITICAL;
274 break;
275 case PM8901_TRIP_STAGE2:
276 *type = THERMAL_TRIP_HOT;
277 break;
278 case PM8901_TRIP_STAGE1:
279 *type = THERMAL_TRIP_HOT;
280 break;
281 default:
282 return -EINVAL;
283 }
284
285 return 0;
286}
287
288static int pm8901_tz_get_trip_temp(struct thermal_zone_device *thermal,
289 int trip, unsigned long *temp)
290{
291 struct pm8901_tm_device *tm = thermal->devdata;
292 int thresh_temp;
293
294 if (!tm || trip < 0 || !temp)
295 return -EINVAL;
296
297 thresh_temp = tm->thresh * PM8901_TEMP_THRESH_STEP +
298 PM8901_TEMP_THRESH_MIN;
299
300 switch (trip) {
301 case PM8901_TRIP_STAGE3:
302 thresh_temp += 2 * PM8901_TEMP_STAGE_STEP;
303 break;
304 case PM8901_TRIP_STAGE2:
305 thresh_temp += PM8901_TEMP_STAGE_STEP;
306 break;
307 case PM8901_TRIP_STAGE1:
308 break;
309 default:
310 return -EINVAL;
311 }
312 *temp = thresh_temp;
313
314 return 0;
315}
316
317static int pm8901_tz_get_crit_temp(struct thermal_zone_device *thermal,
318 unsigned long *temp)
319{
320 struct pm8901_tm_device *tm = thermal->devdata;
321
322 if (!tm || !temp)
323 return -EINVAL;
324
325 *temp = tm->thresh * PM8901_TEMP_THRESH_STEP +
326 PM8901_TEMP_THRESH_MIN + 2 * PM8901_TEMP_STAGE_STEP;
327
328 return 0;
329}
330
331static struct thermal_zone_device_ops pm8901_thermal_zone_ops = {
332 .get_temp = pm8901_tz_get_temp,
333 .get_mode = pm8901_tz_get_mode,
334 .set_mode = pm8901_tz_set_mode,
335 .get_trip_type = pm8901_tz_get_trip_type,
336 .get_trip_temp = pm8901_tz_get_trip_temp,
337 .get_crit_temp = pm8901_tz_get_crit_temp,
338};
339
340static irqreturn_t pm8901_tm_isr(int irq, void *data)
341{
342 struct pm8901_tm_device *tm = data;
343 int rc;
344 u8 reg;
345
346 rc = pm8901_tm_update_temp(tm);
347 if (rc < 0)
348 goto isr_handled;
349
350 rc = pm8901_tm_read_ctrl(tm->pm_chip, &reg);
351 if (rc < 0)
352 goto isr_handled;
353
354 pr_info("%s: Temp Alarm - stage=%u, threshold=%u, temp=%lu\n",
355 __func__, tm->stage, tm->thresh, tm->temp);
356
357 if (reg & (PM8901_TEMP_ST2_SD | PM8901_TEMP_ST3_SD)) {
358 reg &= ~(PM8901_TEMP_ST2_SD | PM8901_TEMP_ST3_SD |
359 PM8901_TEMP_STATUS_MASK);
360
361 pm8901_tm_write_ctrl(tm->pm_chip, reg);
362 }
363
364 thermal_zone_device_update(tm->tz_dev);
365
366 /* Notify user space */
367 if (tm->mode == THERMAL_DEVICE_ENABLED)
368 kobject_uevent(&tm->tz_dev->device.kobj, KOBJ_CHANGE);
369
370isr_handled:
371 return IRQ_HANDLED;
372}
373
374static irqreturn_t pm8901_tm_isr1(int irq, void *data)
375{
376 struct pm8901_tm_device *tm = data;
377 irqreturn_t rc;
378
379 disable_irq(tm->hi_irq);
380 rc = pm8901_tm_isr(irq, data);
381 enable_irq(tm->hi_irq);
382
383 return rc;
384}
385
386static irqreturn_t pm8901_tm_isr2(int irq, void *data)
387{
388 struct pm8901_tm_device *tm = data;
389 irqreturn_t rc;
390
391 disable_irq(tm->irq);
392 rc = pm8901_tm_isr(irq, data);
393 enable_irq(tm->irq);
394
395 return rc;
396}
397
398static int pm8901_tm_init_reg(struct pm8901_tm_device *tm)
399{
400 int rc;
401 u8 reg;
402
403 rc = pm8901_tm_init_temp(tm);
404 if (rc < 0)
405 return rc;
406
407 /* Use temperature threshold set 0: (105, 125, 145) */
408 tm->thresh = 0;
409 reg = (tm->thresh << PM8901_TEMP_THRESH_SHIFT) &
410 PM8901_TEMP_THRESH_MASK;
411 rc = pm8901_tm_write_ctrl(tm->pm_chip, reg);
412 if (rc < 0)
413 return rc;
414
415 /*
416 * Set the PMIC alarm module PWM to have a frequency of 8 Hz. This
417 * helps cut down on the number of unnecessary interrupts fired when
418 * changing between thermal stages. Also, Enable the over temperature
419 * PWM whenever the PMIC is enabled.
420 */
421 reg = 1 << PM8901_TEMP_PWM_EN_SHIFT |
422 3 << PM8901_TEMP_PWM_PER_PRE_SHIFT |
423 3 << PM8901_TEMP_PWM_PER_DIV_SHIFT;
424
425 rc = pm8901_tm_write_pwm(tm->pm_chip, reg);
426
427 return rc;
428}
429
430static int __devinit pmic8901_tm_probe(struct platform_device *pdev)
431{
432 struct pm8901_tm_device *tmdev;
433 struct pm8901_chip *pm_chip;
434 unsigned int irq, hi_irq;
435 int rc;
436
437 pm_chip = dev_get_drvdata(pdev->dev.parent);
438 if (pm_chip == NULL) {
439 pr_err("%s: no driver data passed in.\n", __func__);
440 return -EFAULT;
441 }
442
443 irq = platform_get_irq(pdev, 0);
444 if (!irq) {
445 pr_err("%s: no IRQ passed in.\n", __func__);
446 return -EFAULT;
447 }
448 hi_irq = platform_get_irq(pdev, 1);
449 if (!hi_irq) {
450 pr_err("%s: no HI IRQ passed in.\n", __func__);
451 return -EFAULT;
452 }
453
454 tmdev = kzalloc(sizeof *tmdev, GFP_KERNEL);
455 if (tmdev == NULL) {
456 pr_err("%s: kzalloc() failed.\n", __func__);
457 return -ENOMEM;
458 }
459
460 tmdev->pm_chip = pm_chip;
461 tmdev->tz_dev = thermal_zone_device_register("pm8901_tz",
462 PM8901_TRIP_NUM, tmdev,
463 &pm8901_thermal_zone_ops,
464 0, 0, 0, 0);
465 if (tmdev->tz_dev == NULL) {
466 pr_err("%s: thermal_zone_device_register() failed.\n",
467 __func__);
468 kfree(tmdev);
469 return -ENODEV;
470 }
471
472 rc = pm8901_tm_init_reg(tmdev);
473 pm8901_tm_shutdown_override(tmdev->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
474 if (rc < 0) {
475 thermal_zone_device_unregister(tmdev->tz_dev);
476 kfree(tmdev);
477 return rc;
478 }
479
480 /* start in HW control, switch to SW control when user changes mode */
481 tmdev->mode = THERMAL_DEVICE_DISABLED;
482 thermal_zone_device_update(tmdev->tz_dev);
483
484 platform_set_drvdata(pdev, tmdev);
485
486 rc = request_threaded_irq(irq, pm8901_tm_isr1, NULL,
487 IRQF_TRIGGER_RISING | IRQF_DISABLED,
488 "pm8901-tm-irq", tmdev);
489 if (rc < 0) {
490 pr_err("%s: request_threaded_irq(%d) FAIL: %d\n",
491 __func__, irq, rc);
492
493 thermal_zone_device_unregister(tmdev->tz_dev);
494 platform_set_drvdata(pdev, tmdev->pm_chip);
495 kfree(tmdev);
496 return -ENODEV;
497 }
498 tmdev->irq = irq;
499
500 rc = request_threaded_irq(hi_irq, pm8901_tm_isr2, NULL,
501 IRQF_TRIGGER_RISING | IRQF_DISABLED,
502 "pm8901-tm-irq2", tmdev);
503 if (rc < 0) {
504 pr_err("%s: request_threaded_irq(%d) FAIL: %d\n",
505 __func__, hi_irq, rc);
506
507 free_irq(irq, tmdev);
508 thermal_zone_device_unregister(tmdev->tz_dev);
509 platform_set_drvdata(pdev, tmdev->pm_chip);
510 kfree(tmdev);
511 return -ENODEV;
512 }
513 tmdev->hi_irq = hi_irq;
514
515 pr_notice("%s: OK\n", __func__);
516 return 0;
517}
518
519static int __devexit pmic8901_tm_remove(struct platform_device *pdev)
520{
521 struct pm8901_tm_device *tmdev = platform_get_drvdata(pdev);
522
523 free_irq(tmdev->hi_irq, tmdev);
524 free_irq(tmdev->irq, tmdev);
525 thermal_zone_device_unregister(tmdev->tz_dev);
526 platform_set_drvdata(pdev, tmdev->pm_chip);
527 pm8901_tm_shutdown_override(tmdev->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
528 kfree(tmdev);
529
530 return 0;
531}
532
533#ifdef CONFIG_PM
534static int pmic8901_tm_suspend(struct device *dev)
535{
536 struct platform_device *pdev = to_platform_device(dev);
537 struct pm8901_tm_device *tm = platform_get_drvdata(pdev);
538
539 pm8901_tm_shutdown_override(tm->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
540
541 return 0;
542}
543
544static int pmic8901_tm_resume(struct device *dev)
545{
546 struct platform_device *pdev = to_platform_device(dev);
547 struct pm8901_tm_device *tm = platform_get_drvdata(pdev);
548
549 pm8901_tm_init_temp(tm);
550
551 if (tm->mode == THERMAL_DEVICE_ENABLED)
552 pm8901_tm_shutdown_override(tm->pm_chip,
553 SOFTWARE_OVERRIDE_ENABLED);
554
555 return 0;
556}
557
558static const struct dev_pm_ops pmic8901_tm_pm_ops = {
559 .suspend = pmic8901_tm_suspend,
560 .resume = pmic8901_tm_resume,
561};
562
563#define PM8901_TM_PM_OPS (&pmic8901_tm_pm_ops)
564#else
565#define PM8901_TM_PM_OPS NULL
566#endif
567
568static struct platform_driver pmic8901_tm_driver = {
569 .probe = pmic8901_tm_probe,
570 .remove = __devexit_p(pmic8901_tm_remove),
571 .driver = {
572 .name = "pm8901-tm",
573 .owner = THIS_MODULE,
574 .pm = PM8901_TM_PM_OPS,
575 },
576};
577
578static int __init pm8901_tm_init(void)
579{
580 return platform_driver_register(&pmic8901_tm_driver);
581}
582
583static void __exit pm8901_tm_exit(void)
584{
585 platform_driver_unregister(&pmic8901_tm_driver);
586}
587
588module_init(pm8901_tm_init);
589module_exit(pm8901_tm_exit);
590
591MODULE_LICENSE("GPL v2");
592MODULE_DESCRIPTION("PMIC8901 Thermal Manager driver");
593MODULE_VERSION("1.0");
594MODULE_ALIAS("platform:pmic8901-tm");