blob: 86bae0697fa347b3a6b64caec2b6b8387fda7f1f [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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 TSENS Thermal Manager driver
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/thermal.h>
21#include <linux/interrupt.h>
22#include <linux/delay.h>
23#include <linux/slab.h>
24
25#include <linux/io.h>
26#include <mach/msm_iomap.h>
Siddartha Mohanadossba7291c2011-09-29 13:50:24 -070027#include <linux/pm.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028
29/* Trips: from very hot to very cold */
30enum tsens_trip_type {
31 TSENS_TRIP_STAGE3 = 0,
32 TSENS_TRIP_STAGE2,
33 TSENS_TRIP_STAGE1,
34 TSENS_TRIP_STAGE0,
35 TSENS_TRIP_NUM,
36};
37
38#define TSENS_NUM_SENSORS 1 /* There are 5 but only 1 is useful now */
39#define TSENS_CAL_DEGC 30 /* degree C used for calibration */
40#define TSENS_QFPROM_ADDR (MSM_QFPROM_BASE + 0x000000bc)
41#define TSENS_QFPROM_RED_TEMP_SENSOR0_SHIFT 24
42#define TSENS_QFPROM_TEMP_SENSOR0_SHIFT 16
43#define TSENS_QFPROM_TEMP_SENSOR0_MASK (255 << TSENS_QFPROM_TEMP_SENSOR0_SHIFT)
44#define TSENS_SLOPE (0.702) /* slope in (degrees_C / ADC_code) */
45#define TSENS_FACTOR (1000) /* convert floating-point into integer */
46#define TSENS_CONFIG 01 /* this setting found to be optimal */
47#define TSENS_CONFIG_SHIFT 28
48#define TSENS_CONFIG_MASK (3 << TSENS_CONFIG_SHIFT)
49#define TSENS_CNTL_ADDR (MSM_CLK_CTL_BASE + 0x00003620)
50#define TSENS_EN (1 << 0)
51#define TSENS_SW_RST (1 << 1)
52#define SENSOR0_EN (1 << 3)
53#define SENSOR1_EN (1 << 4)
54#define SENSOR2_EN (1 << 5)
55#define SENSOR3_EN (1 << 6)
56#define SENSOR4_EN (1 << 7)
57#define TSENS_MIN_STATUS_MASK (1 << 8)
58#define TSENS_LOWER_STATUS_CLR (1 << 9)
59#define TSENS_UPPER_STATUS_CLR (1 << 10)
60#define TSENS_MAX_STATUS_MASK (1 << 11)
61#define TSENS_MEASURE_PERIOD 4 /* 1 sec. default as required by Willie */
62#define TSENS_SLP_CLK_ENA (1 << 24)
63#define TSENS_THRESHOLD_ADDR (MSM_CLK_CTL_BASE + 0x00003624)
64#define TSENS_THRESHOLD_MAX_CODE (0xff)
65#define TSENS_THRESHOLD_MAX_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << 24)
66#define TSENS_THRESHOLD_MIN_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << 16)
67#define TSENS_THRESHOLD_UPPER_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << 8)
68#define TSENS_THRESHOLD_LOWER_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << 0)
69/* Initial temperature threshold values */
70#define TSENS_LOWER_LIMIT_TH 0x50
71#define TSENS_UPPER_LIMIT_TH 0xdf
72#define TSENS_MIN_LIMIT_TH 0x38
73#define TSENS_MAX_LIMIT_TH 0xff
74
75#define TSENS_S0_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003628)
76#define TSENS_INT_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x0000363c)
77#define TSENS_LOWER_INT_MASK (1 << 1)
78#define TSENS_UPPER_INT_MASK (1 << 2)
79#define TSENS_TRDY_MASK (1 << 7)
80
81struct tsens_tm_device_sensor {
82 struct thermal_zone_device *tz_dev;
83 enum thermal_device_mode mode;
84 unsigned int sensor_num;
85};
86
87struct tsens_tm_device {
88 struct tsens_tm_device_sensor sensor[TSENS_NUM_SENSORS];
89 bool prev_reading_avail;
90 int offset;
91 struct work_struct work;
Siddartha Mohanadossba7291c2011-09-29 13:50:24 -070092 uint32_t pm_tsens_thr_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093};
94
95struct tsens_tm_device *tmdev;
96
97/* Temperature on y axis and ADC-code on x-axis */
98static int tsens_tz_code_to_degC(int adc_code)
99{
100 int degC, degcbeforefactor;
101 degcbeforefactor = adc_code * (int)(TSENS_SLOPE * TSENS_FACTOR)
102 + tmdev->offset;
103 if (degcbeforefactor == 0)
104 degC = degcbeforefactor;
105 else if (degcbeforefactor > 0)
106 degC = (degcbeforefactor + TSENS_FACTOR/2) / TSENS_FACTOR;
107 else /* rounding for negative degrees */
108 degC = (degcbeforefactor - TSENS_FACTOR/2) / TSENS_FACTOR;
109 return degC;
110}
111
112static int tsens_tz_degC_to_code(int degC)
113{
114 int code = (degC * TSENS_FACTOR - tmdev->offset
115 + (int)(TSENS_FACTOR * TSENS_SLOPE)/2)
116 / (int)(TSENS_FACTOR * TSENS_SLOPE);
117 if (code > 255) /* upper bound */
118 code = 255;
119 else if (code < 0) /* lower bound */
120 code = 0;
121 return code;
122}
123
124static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
125 unsigned long *temp)
126{
127 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
128 unsigned int code;
129
130 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
131 return -EINVAL;
132
133 if (!tmdev->prev_reading_avail) {
134 while (!(readl(TSENS_INT_STATUS_ADDR) & TSENS_TRDY_MASK))
135 msleep(1);
136 tmdev->prev_reading_avail = 1;
137 }
138
139 code = readl(TSENS_S0_STATUS_ADDR + (tm_sensor->sensor_num << 2));
140 *temp = tsens_tz_code_to_degC(code);
141
142 return 0;
143}
144
145static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
146 enum thermal_device_mode *mode)
147{
148 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
149
150 if (!tm_sensor || !mode)
151 return -EINVAL;
152
153 *mode = tm_sensor->mode;
154
155 return 0;
156}
157
158static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
159 enum thermal_device_mode mode)
160{
161 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
162 unsigned int reg, mask;
163
164 if (!tm_sensor)
165 return -EINVAL;
166
167 if (mode != tm_sensor->mode) {
168 pr_info("%s: mode: %d --> %d\n", __func__, tm_sensor->mode,
169 mode);
170
171 reg = readl(TSENS_CNTL_ADDR);
172 mask = 1 << (tm_sensor->sensor_num + 3);
173 if (mode == THERMAL_DEVICE_ENABLED) {
174 writel(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
175 reg |= mask | TSENS_SLP_CLK_ENA | TSENS_EN;
176 tmdev->prev_reading_avail = 0;
177 } else {
178 reg &= ~mask;
179 if (!(reg & (((1 << TSENS_NUM_SENSORS) - 1) << 3)))
180 reg &= ~(TSENS_SLP_CLK_ENA | TSENS_EN);
181 }
182
183 writel(reg, TSENS_CNTL_ADDR);
184 }
185 tm_sensor->mode = mode;
186
187 return 0;
188}
189
190static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
191 int trip, enum thermal_trip_type *type)
192{
193 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
194
195 if (!tm_sensor || trip < 0 || !type)
196 return -EINVAL;
197
198 switch (trip) {
199 case TSENS_TRIP_STAGE3:
200 *type = THERMAL_TRIP_CRITICAL;
201 break;
202 case TSENS_TRIP_STAGE2:
203 *type = THERMAL_TRIP_CONFIGURABLE_HI;
204 break;
205 case TSENS_TRIP_STAGE1:
206 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
207 break;
208 case TSENS_TRIP_STAGE0:
209 *type = THERMAL_TRIP_CRITICAL_LOW;
210 break;
211 default:
212 return -EINVAL;
213 }
214
215 return 0;
216}
217
218static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
219 int trip, enum thermal_trip_activation_mode mode)
220{
221 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
222 unsigned int reg_cntl, reg_th, code, hi_code, lo_code, mask;
223
224 if (!tm_sensor || trip < 0)
225 return -EINVAL;
226
227 lo_code = 0;
228 hi_code = TSENS_THRESHOLD_MAX_CODE;
229
230 reg_cntl = readl(TSENS_CNTL_ADDR);
231 reg_th = readl(TSENS_THRESHOLD_ADDR);
232 switch (trip) {
233 case TSENS_TRIP_STAGE3:
234 code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK) >> 24;
235 mask = TSENS_MAX_STATUS_MASK;
236
237 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
238 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
239 >> 8;
240 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
241 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK);
242 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
243 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
244 >> 16;
245 break;
246 case TSENS_TRIP_STAGE2:
247 code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK) >> 8;
248 mask = TSENS_UPPER_STATUS_CLR;
249
250 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
251 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
252 >> 24;
253 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
254 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK);
255 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
256 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
257 >> 16;
258 break;
259 case TSENS_TRIP_STAGE1:
260 code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK) >> 0;
261 mask = TSENS_LOWER_STATUS_CLR;
262
263 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
264 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
265 >> 16;
266 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
267 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
268 >> 8;
269 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
270 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
271 >> 24;
272 break;
273 case TSENS_TRIP_STAGE0:
274 code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK) >> 16;
275 mask = TSENS_MIN_STATUS_MASK;
276
277 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
278 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK);
279 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
280 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
281 >> 8;
282 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
283 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
284 >> 24;
285 break;
286 default:
287 return -EINVAL;
288 }
289
290 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
291 writel(reg_cntl | mask, TSENS_CNTL_ADDR);
292 else {
293 if (code < lo_code || code > hi_code)
294 return -EINVAL;
295 writel(reg_cntl & ~mask, TSENS_CNTL_ADDR);
296 }
297
298 return 0;
299}
300
301static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
302 int trip, unsigned long *temp)
303{
304 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
305 unsigned int reg;
306
307 if (!tm_sensor || trip < 0 || !temp)
308 return -EINVAL;
309
310 reg = readl(TSENS_THRESHOLD_ADDR);
311 switch (trip) {
312 case TSENS_TRIP_STAGE3:
313 reg = (reg & TSENS_THRESHOLD_MAX_LIMIT_MASK) >> 24;
314 break;
315 case TSENS_TRIP_STAGE2:
316 reg = (reg & TSENS_THRESHOLD_UPPER_LIMIT_MASK) >> 8;
317 break;
318 case TSENS_TRIP_STAGE1:
319 reg = (reg & TSENS_THRESHOLD_LOWER_LIMIT_MASK) >> 0;
320 break;
321 case TSENS_TRIP_STAGE0:
322 reg = (reg & TSENS_THRESHOLD_MIN_LIMIT_MASK) >> 16;
323 break;
324 default:
325 return -EINVAL;
326 }
327
328 *temp = tsens_tz_code_to_degC(reg);
329
330 return 0;
331}
332
333static int tsens_tz_get_crit_temp(struct thermal_zone_device *thermal,
334 unsigned long *temp)
335{
336 return tsens_tz_get_trip_temp(thermal, TSENS_TRIP_STAGE3, temp);
337}
338
339static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
340 int trip, long temp)
341{
342 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
343 unsigned int reg_th, reg_cntl;
344 int code, hi_code, lo_code, code_err_chk;
345
346 code_err_chk = code = tsens_tz_degC_to_code(temp);
347 if (!tm_sensor || trip < 0)
348 return -EINVAL;
349
350 lo_code = 0;
351 hi_code = TSENS_THRESHOLD_MAX_CODE;
352
353 reg_cntl = readl(TSENS_CNTL_ADDR);
354 reg_th = readl(TSENS_THRESHOLD_ADDR);
355 switch (trip) {
356 case TSENS_TRIP_STAGE3:
357 code <<= 24;
358 reg_th &= ~TSENS_THRESHOLD_MAX_LIMIT_MASK;
359
360 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
361 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
362 >> 8;
363 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
364 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK);
365 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
366 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
367 >> 16;
368 break;
369 case TSENS_TRIP_STAGE2:
370 code <<= 8;
371 reg_th &= ~TSENS_THRESHOLD_UPPER_LIMIT_MASK;
372
373 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
374 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
375 >> 24;
376 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
377 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK);
378 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
379 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
380 >> 16;
381 break;
382 case TSENS_TRIP_STAGE1:
383 reg_th &= ~TSENS_THRESHOLD_LOWER_LIMIT_MASK;
384
385 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
386 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
387 >> 16;
388 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
389 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
390 >> 8;
391 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
392 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
393 >> 24;
394 break;
395 case TSENS_TRIP_STAGE0:
396 code <<= 16;
397 reg_th &= ~TSENS_THRESHOLD_MIN_LIMIT_MASK;
398
399 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
400 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK);
401 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
402 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
403 >> 8;
404 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
405 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
406 >> 24;
407 break;
408 default:
409 return -EINVAL;
410 }
411
412 if (code_err_chk < lo_code || code_err_chk > hi_code)
413 return -EINVAL;
414
415 writel(reg_th | code, TSENS_THRESHOLD_ADDR);
416 return 0;
417}
418
419static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
420 .get_temp = tsens_tz_get_temp,
421 .get_mode = tsens_tz_get_mode,
422 .set_mode = tsens_tz_set_mode,
423 .get_trip_type = tsens_tz_get_trip_type,
424 .activate_trip_type = tsens_tz_activate_trip_type,
425 .get_trip_temp = tsens_tz_get_trip_temp,
426 .set_trip_temp = tsens_tz_set_trip_temp,
427 .get_crit_temp = tsens_tz_get_crit_temp,
428};
429
430static void notify_uspace_tsens_fn(struct work_struct *work)
431{
432 struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
433 work);
434 /* Currently only Sensor0 is supported. We added support
435 to notify only the supported Sensor and this portion
436 needs to be revisited once other sensors are supported */
437 sysfs_notify(&tm->sensor[0].tz_dev->device.kobj,
438 NULL, "type");
439}
440
441static irqreturn_t tsens_isr(int irq, void *data)
442{
443 unsigned int reg = readl(TSENS_CNTL_ADDR);
444
445 writel(reg | TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR,
446 TSENS_CNTL_ADDR);
447
448 return IRQ_WAKE_THREAD;
449}
450
451static irqreturn_t tsens_isr_thread(int irq, void *data)
452{
453 struct tsens_tm_device *tm = data;
454 unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
455 bool upper_th_x, lower_th_x;
456 int adc_code;
457
458 mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
459 threshold = readl(TSENS_THRESHOLD_ADDR);
460 threshold_low = threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK;
461 threshold = (threshold & TSENS_THRESHOLD_UPPER_LIMIT_MASK) >> 8;
462 reg = sensor = readl(TSENS_CNTL_ADDR);
463 sensor &= (SENSOR0_EN | SENSOR1_EN | SENSOR2_EN |
464 SENSOR3_EN | SENSOR4_EN);
465 sensor >>= 3;
466 for (i = 0; i < TSENS_NUM_SENSORS; i++) {
467 if (sensor & 1) {
468 code = readl(TSENS_S0_STATUS_ADDR + (i << 2));
469 upper_th_x = code >= threshold;
470 lower_th_x = code <= threshold_low;
471 if (upper_th_x)
472 mask |= TSENS_UPPER_STATUS_CLR;
473 if (lower_th_x)
474 mask |= TSENS_LOWER_STATUS_CLR;
475 if (upper_th_x || lower_th_x) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700476 /* Notify user space */
477 schedule_work(&tm->work);
478 adc_code = readl(TSENS_S0_STATUS_ADDR
479 + (i << 2));
480 printk(KERN_INFO"\nTrip point triggered by "
481 "current temperature (%d degrees) "
482 "measured by Temperature-Sensor %d\n",
483 tsens_tz_code_to_degC(adc_code), i);
484 }
485 }
486 sensor >>= 1;
487 }
488 writel(reg & mask, TSENS_CNTL_ADDR);
489 return IRQ_HANDLED;
490}
491
Siddartha Mohanadossba7291c2011-09-29 13:50:24 -0700492#ifdef CONFIG_PM
493static int tsens_suspend(struct device *dev)
494{
495 unsigned int reg;
496
497 tmdev->pm_tsens_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
498 reg = readl_relaxed(TSENS_CNTL_ADDR);
499 writel_relaxed(reg & ~(TSENS_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
500 tmdev->prev_reading_avail = 0;
501
502 disable_irq_nosync(TSENS_UPPER_LOWER_INT);
503 mb();
504 return 0;
505}
506
507static int tsens_resume(struct device *dev)
508{
509 unsigned int reg;
510
511 reg = readl_relaxed(TSENS_CNTL_ADDR);
512 writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
513 reg |= TSENS_SLP_CLK_ENA | TSENS_EN | (TSENS_MEASURE_PERIOD << 16) |
Siddartha Mohanadossba7291c2011-09-29 13:50:24 -0700514 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
515 (((1 << TSENS_NUM_SENSORS) - 1) << 3);
516
517 reg = (reg & ~TSENS_CONFIG_MASK) | (TSENS_CONFIG << TSENS_CONFIG_SHIFT);
518 writel_relaxed(reg, TSENS_CNTL_ADDR);
519
520 if (tmdev->sensor->mode == THERMAL_DEVICE_DISABLED) {
521 writel_relaxed(reg & ~((((1 << TSENS_NUM_SENSORS) - 1) << 3)
522 | TSENS_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
523 }
524
525 writel_relaxed(tmdev->pm_tsens_thr_data, TSENS_THRESHOLD_ADDR);
526
527 enable_irq(TSENS_UPPER_LOWER_INT);
528 mb();
529 return 0;
530}
531
532static const struct dev_pm_ops tsens_pm_ops = {
533 .suspend = tsens_suspend,
534 .resume = tsens_resume,
535};
536#endif
537
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700538static int __devinit tsens_tm_probe(struct platform_device *pdev)
539{
540 unsigned int reg, i, calib_data, calib_data_backup;
541 int rc;
542
543 calib_data = (readl(TSENS_QFPROM_ADDR) & TSENS_QFPROM_TEMP_SENSOR0_MASK)
544 >> TSENS_QFPROM_TEMP_SENSOR0_SHIFT;
545 calib_data_backup = readl(TSENS_QFPROM_ADDR)
546 >> TSENS_QFPROM_RED_TEMP_SENSOR0_SHIFT;
547
548 if (calib_data_backup)
549 calib_data = calib_data_backup;
550
551 if (!calib_data) {
552 pr_err("%s: No temperature sensor data for calibration"
553 " in QFPROM!\n", __func__);
554 return -ENODEV;
555 }
556
557 tmdev = kzalloc(sizeof(struct tsens_tm_device), GFP_KERNEL);
558 if (tmdev == NULL) {
559 pr_err("%s: kzalloc() failed.\n", __func__);
560 return -ENOMEM;
561 }
562
563 platform_set_drvdata(pdev, tmdev);
564
565 tmdev->offset = TSENS_FACTOR * TSENS_CAL_DEGC
566 - (int)(TSENS_FACTOR * TSENS_SLOPE) * calib_data;
567 tmdev->prev_reading_avail = 0;
568
569 INIT_WORK(&tmdev->work, notify_uspace_tsens_fn);
570
571 reg = readl(TSENS_CNTL_ADDR);
572 writel(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
573 reg |= TSENS_SLP_CLK_ENA | TSENS_EN | (TSENS_MEASURE_PERIOD << 16) |
574 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
575 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
576 (((1 << TSENS_NUM_SENSORS) - 1) << 3);
577
578 /* set TSENS_CONFIG bits (bits 29:28 of TSENS_CNTL) to '01';
579 this setting found to be optimal. */
580 reg = (reg & ~TSENS_CONFIG_MASK) | (TSENS_CONFIG << TSENS_CONFIG_SHIFT);
581
582 writel(reg, TSENS_CNTL_ADDR);
583
584 writel((TSENS_LOWER_LIMIT_TH << 0) | (TSENS_UPPER_LIMIT_TH << 8) |
585 (TSENS_MIN_LIMIT_TH << 16) | (TSENS_MAX_LIMIT_TH << 24),
586 TSENS_THRESHOLD_ADDR);
587
588 for (i = 0; i < TSENS_NUM_SENSORS; i++) {
589 char name[17];
590 sprintf(name, "tsens_tz_sensor%d", i);
591
592 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
593 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
594 TSENS_TRIP_NUM, &tmdev->sensor[i],
595 &tsens_thermal_zone_ops, 0, 0, 0, 0);
596 if (tmdev->sensor[i].tz_dev == NULL) {
597 pr_err("%s: thermal_zone_device_register() failed.\n",
598 __func__);
599 kfree(tmdev);
600 return -ENODEV;
601 }
602 tmdev->sensor[i].sensor_num = i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
604 }
605
606 rc = request_threaded_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
607 tsens_isr_thread, 0, "tsens", tmdev);
608 if (rc < 0) {
609 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
610 kfree(tmdev);
611 return rc;
612 }
613
614 writel(reg & ~((((1 << TSENS_NUM_SENSORS) - 1) << 3)
615 | TSENS_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
616 pr_notice("%s: OK\n", __func__);
617 return 0;
618}
619
620static int __devexit tsens_tm_remove(struct platform_device *pdev)
621{
622 struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
623 unsigned int reg, i;
624
625 reg = readl(TSENS_CNTL_ADDR);
626 writel(reg & ~(TSENS_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
627
628 for (i = 0; i < TSENS_NUM_SENSORS; i++)
629 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
630 platform_set_drvdata(pdev, NULL);
631 free_irq(TSENS_UPPER_LOWER_INT, tmdev);
632 kfree(tmdev);
633
634 return 0;
635}
636
637static struct platform_driver tsens_tm_driver = {
638 .probe = tsens_tm_probe,
639 .remove = __devexit_p(tsens_tm_remove),
640 .driver = {
641 .name = "tsens-tm",
642 .owner = THIS_MODULE,
Siddartha Mohanadossba7291c2011-09-29 13:50:24 -0700643#ifdef CONFIG_PM
644 .pm = &tsens_pm_ops,
645#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 },
647};
648
649static int __init tsens_init(void)
650{
651 return platform_driver_register(&tsens_tm_driver);
652}
653
654static void __exit tsens_exit(void)
655{
656 platform_driver_unregister(&tsens_tm_driver);
657}
658
659module_init(tsens_init);
660module_exit(tsens_exit);
661
662MODULE_LICENSE("GPL v2");
663MODULE_DESCRIPTION("MSM Temperature Sensor driver");
664MODULE_VERSION("1.0");
665MODULE_ALIAS("platform:tsens-tm");