blob: 63d8666a95c66dab21c03a41e0eebc9dd1a74e5b [file] [log] [blame]
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001/* Copyright (c) 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 MSM8960 TSENS 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#include <linux/msm_tsens.h>
25#include <linux/io.h>
26
27#include <mach/msm_iomap.h>
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -070028#include <mach/socinfo.h>
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070029
30/* Trips: from very hot to very cold */
31enum tsens_trip_type {
32 TSENS_TRIP_STAGE3 = 0,
33 TSENS_TRIP_STAGE2,
34 TSENS_TRIP_STAGE1,
35 TSENS_TRIP_STAGE0,
36 TSENS_TRIP_NUM,
37};
38
39/* MSM8960 TSENS register info */
40#define TSENS_CAL_DEGC 30
41#define TSENS_MAIN_SENSOR 0
42
43#define TSENS_8960_QFPROM_ADDR0 (MSM_QFPROM_BASE + 0x00000404)
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -070044#define TSENS_8960_QFPROM_SPARE_ADDR0 (MSM_QFPROM_BASE + 0x00000414)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070045#define TSENS_8960_CONFIG 0x9b
46#define TSENS_8960_CONFIG_SHIFT 0
47#define TSENS_8960_CONFIG_MASK (0xf << TSENS_8960_CONFIG_SHIFT)
48#define TSENS_CNTL_ADDR (MSM_CLK_CTL_BASE + 0x00003620)
49#define TSENS_EN BIT(0)
50#define TSENS_SW_RST BIT(1)
51#define TSENS_ADC_CLK_SEL BIT(2)
52#define SENSOR0_EN BIT(3)
53#define SENSOR1_EN BIT(4)
54#define SENSOR2_EN BIT(5)
55#define SENSOR3_EN BIT(6)
56#define SENSOR4_EN BIT(7)
57#define SENSORS_EN (SENSOR0_EN | SENSOR1_EN | \
58 SENSOR2_EN | SENSOR3_EN | SENSOR4_EN)
59#define TSENS_MIN_STATUS_MASK BIT(8)
60#define TSENS_LOWER_STATUS_CLR BIT(9)
61#define TSENS_UPPER_STATUS_CLR BIT(10)
62#define TSENS_MAX_STATUS_MASK BIT(11)
63#define TSENS_MEASURE_PERIOD 4 /* 1 sec. default */
64#define TSENS_8960_SLP_CLK_ENA BIT(26)
65
66#define TSENS_THRESHOLD_ADDR (MSM_CLK_CTL_BASE + 0x00003624)
67#define TSENS_THRESHOLD_MAX_CODE 0xff
68#define TSENS_THRESHOLD_MIN_CODE 0
69#define TSENS_THRESHOLD_MAX_LIMIT_SHIFT 24
70#define TSENS_THRESHOLD_MIN_LIMIT_SHIFT 16
71#define TSENS_THRESHOLD_UPPER_LIMIT_SHIFT 8
72#define TSENS_THRESHOLD_LOWER_LIMIT_SHIFT 0
73#define TSENS_THRESHOLD_MAX_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
74 TSENS_THRESHOLD_MAX_LIMIT_SHIFT)
75#define TSENS_THRESHOLD_MIN_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
76 TSENS_THRESHOLD_MIN_LIMIT_SHIFT)
77#define TSENS_THRESHOLD_UPPER_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
78 TSENS_THRESHOLD_UPPER_LIMIT_SHIFT)
79#define TSENS_THRESHOLD_LOWER_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
80 TSENS_THRESHOLD_LOWER_LIMIT_SHIFT)
81/* Initial temperature threshold values */
82#define TSENS_LOWER_LIMIT_TH 0x50
83#define TSENS_UPPER_LIMIT_TH 0xdf
84#define TSENS_MIN_LIMIT_TH 0x38
85#define TSENS_MAX_LIMIT_TH 0xff
86
87#define TSENS_S0_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003628)
88#define TSENS_STATUS_ADDR_OFFSET 2
89#define TSENS_INT_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x0000363c)
90
91#define TSENS_LOWER_INT_MASK BIT(1)
92#define TSENS_UPPER_INT_MASK BIT(2)
93#define TSENS_MAX_INT_MASK BIT(3)
94#define TSENS_TRDY_MASK BIT(7)
95
96#define TSENS_8960_CONFIG_ADDR (MSM_CLK_CTL_BASE + 0x00003640)
97#define TSENS_TRDY_RDY_MIN_TIME 1000
98#define TSENS_TRDY_RDY_MAX_TIME 1100
99#define TSENS_SENSOR_SHIFT 16
100#define TSENS_RED_SHIFT 8
101#define TSENS_8960_QFPROM_SHIFT 4
Siddartha Mohanadoss3e1ffc32011-11-30 17:10:44 -0800102#define TSENS_SENSOR_QFPROM_SHIFT 2
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700103#define TSENS_SENSOR0_SHIFT 3
104#define TSENS_MASK1 1
105
106#define TSENS_8660_QFPROM_ADDR (MSM_QFPROM_BASE + 0x000000bc)
107#define TSENS_8660_QFPROM_RED_TEMP_SENSOR0_SHIFT 24
108#define TSENS_8660_QFPROM_TEMP_SENSOR0_SHIFT 16
109#define TSENS_8660_QFPROM_TEMP_SENSOR0_MASK (255 \
110 << TSENS_8660_QFPROM_TEMP_SENSOR0_SHIFT)
111#define TSENS_8660_CONFIG 01
112#define TSENS_8660_CONFIG_SHIFT 28
113#define TSENS_8660_CONFIG_MASK (3 << TSENS_8660_CONFIG_SHIFT)
114#define TSENS_8660_SLP_CLK_ENA BIT(24)
115
116struct tsens_tm_device_sensor {
117 struct thermal_zone_device *tz_dev;
118 enum thermal_device_mode mode;
119 unsigned int sensor_num;
120 struct work_struct work;
121 int offset;
122 int calib_data;
123 int calib_data_backup;
124};
125
126struct tsens_tm_device {
127 bool prev_reading_avail;
128 int slope_mul_tsens_factor;
129 int tsens_factor;
130 uint32_t tsens_num_sensor;
131 enum platform_type hw_type;
132 struct tsens_tm_device_sensor sensor[0];
133};
134
135struct tsens_tm_device *tmdev;
136
137/* Temperature on y axis and ADC-code on x-axis */
138static int tsens_tz_code_to_degC(int adc_code, int sensor_num)
139{
140 int degC, degcbeforefactor;
141 degcbeforefactor = adc_code * tmdev->slope_mul_tsens_factor
142 + tmdev->sensor[sensor_num].offset;
143 if (degcbeforefactor == 0)
144 degC = degcbeforefactor;
145 else if (degcbeforefactor > 0)
146 degC = (degcbeforefactor + tmdev->tsens_factor/2)
147 / tmdev->tsens_factor;
148 else /* rounding for negative degrees */
149 degC = (degcbeforefactor - tmdev->tsens_factor/2)
150 / tmdev->tsens_factor;
151 return degC;
152}
153
154static int tsens_tz_degC_to_code(int degC, int sensor_num)
155{
156 int code = (degC * tmdev->tsens_factor -
157 tmdev->sensor[sensor_num].offset
158 + tmdev->slope_mul_tsens_factor/2)
159 / tmdev->slope_mul_tsens_factor;
160
161 if (code > TSENS_THRESHOLD_MAX_CODE)
162 code = TSENS_THRESHOLD_MAX_CODE;
163 else if (code < TSENS_THRESHOLD_MIN_CODE)
164 code = TSENS_THRESHOLD_MIN_CODE;
165 return code;
166}
167
168static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
169 unsigned long *temp)
170{
171 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
172 unsigned int code;
173
174 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
175 return -EINVAL;
176
177 if (!tmdev->prev_reading_avail) {
178 while (!(readl_relaxed(TSENS_INT_STATUS_ADDR) &
179 TSENS_TRDY_MASK))
180 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
181 TSENS_TRDY_RDY_MAX_TIME);
182 tmdev->prev_reading_avail = true;
183 }
184 code = readl_relaxed(TSENS_S0_STATUS_ADDR +
185 (tm_sensor->sensor_num << TSENS_STATUS_ADDR_OFFSET));
186 *temp = tsens_tz_code_to_degC(code, tm_sensor->sensor_num);
187
188 return 0;
189}
190
191static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
192 enum thermal_device_mode *mode)
193{
194 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
195
196 if (!tm_sensor || !mode)
197 return -EINVAL;
198
199 *mode = tm_sensor->mode;
200
201 return 0;
202}
203
204/* Function to enable the mode.
205 * If the main sensor is disabled all the sensors are disable and
206 * the clock is disabled.
207 * If the main sensor is not enabled and sub sensor is enabled
208 * returns with an error stating the main sensor is not enabled.
209 */
210static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
211 enum thermal_device_mode mode)
212{
213 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
214 unsigned int reg, mask, i;
215
216 if (!tm_sensor)
217 return -EINVAL;
218
219 if (mode != tm_sensor->mode) {
220 pr_info("%s: mode: %d --> %d\n", __func__, tm_sensor->mode,
221 mode);
222
223 reg = readl_relaxed(TSENS_CNTL_ADDR);
224
225 mask = 1 << (tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT);
226 if (mode == THERMAL_DEVICE_ENABLED) {
227 if ((mask != SENSOR0_EN) && !(reg & SENSOR0_EN)) {
228 pr_info("Main sensor not enabled\n");
229 return -EINVAL;
230 }
231 writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700232 if (tmdev->hw_type == MSM_8960 ||
233 tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700234 reg |= mask | TSENS_8960_SLP_CLK_ENA
235 | TSENS_EN;
236 else
237 reg |= mask | TSENS_8660_SLP_CLK_ENA
238 | TSENS_EN;
239 tmdev->prev_reading_avail = false;
240 } else {
241 reg &= ~mask;
242 if (!(reg & SENSOR0_EN)) {
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700243 if (tmdev->hw_type == MSM_8960 ||
244 tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700245 reg &= ~(SENSORS_EN |
246 TSENS_8960_SLP_CLK_ENA |
247 TSENS_EN);
248 else
249 reg &= ~(SENSORS_EN |
250 TSENS_8660_SLP_CLK_ENA |
251 TSENS_EN);
252
253 for (i = 1; i < tmdev->tsens_num_sensor; i++)
254 tmdev->sensor[i].mode = mode;
255
256 }
257 }
258 writel_relaxed(reg, TSENS_CNTL_ADDR);
259 }
260 tm_sensor->mode = mode;
261
262 return 0;
263}
264
265static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
266 int trip, enum thermal_trip_type *type)
267{
268 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
269
270 if (!tm_sensor || trip < 0 || !type)
271 return -EINVAL;
272
273 switch (trip) {
274 case TSENS_TRIP_STAGE3:
275 *type = THERMAL_TRIP_CRITICAL;
276 break;
277 case TSENS_TRIP_STAGE2:
278 *type = THERMAL_TRIP_CONFIGURABLE_HI;
279 break;
280 case TSENS_TRIP_STAGE1:
281 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
282 break;
283 case TSENS_TRIP_STAGE0:
284 *type = THERMAL_TRIP_CRITICAL_LOW;
285 break;
286 default:
287 return -EINVAL;
288 }
289
290 return 0;
291}
292
293static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
294 int trip, enum thermal_trip_activation_mode mode)
295{
296 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
297 unsigned int reg_cntl, reg_th, code, hi_code, lo_code, mask;
298
299 if (!tm_sensor || trip < 0)
300 return -EINVAL;
301
302 lo_code = TSENS_THRESHOLD_MIN_CODE;
303 hi_code = TSENS_THRESHOLD_MAX_CODE;
304
305 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
306 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
307 switch (trip) {
308 case TSENS_TRIP_STAGE3:
309 code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
310 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
311 mask = TSENS_MAX_STATUS_MASK;
312
313 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
314 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
315 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
316 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
317 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
318 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
319 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
320 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
321 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
322 break;
323 case TSENS_TRIP_STAGE2:
324 code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
325 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
326 mask = TSENS_UPPER_STATUS_CLR;
327
328 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
329 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
330 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
331 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
332 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
333 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
334 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
335 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
336 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
337 break;
338 case TSENS_TRIP_STAGE1:
339 code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
340 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
341 mask = TSENS_LOWER_STATUS_CLR;
342
343 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
344 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
345 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
346 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
347 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
348 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
349 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
350 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
351 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
352 break;
353 case TSENS_TRIP_STAGE0:
354 code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
355 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
356 mask = TSENS_MIN_STATUS_MASK;
357
358 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
359 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
360 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
361 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
362 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
363 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
364 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
365 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
366 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
367 break;
368 default:
369 return -EINVAL;
370 }
371
372 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
373 writel_relaxed(reg_cntl | mask, TSENS_CNTL_ADDR);
374 else {
375 if (code < lo_code || code > hi_code) {
376 pr_info("%s with invalid code %x\n", __func__, code);
377 return -EINVAL;
378 }
379 writel_relaxed(reg_cntl & ~mask, TSENS_CNTL_ADDR);
380 }
381 mb();
382 return 0;
383}
384
385static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
386 int trip, unsigned long *temp)
387{
388 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
389 unsigned int reg;
390
391 if (!tm_sensor || trip < 0 || !temp)
392 return -EINVAL;
393
394 reg = readl_relaxed(TSENS_THRESHOLD_ADDR);
395 switch (trip) {
396 case TSENS_TRIP_STAGE3:
397 reg = (reg & TSENS_THRESHOLD_MAX_LIMIT_MASK)
398 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
399 break;
400 case TSENS_TRIP_STAGE2:
401 reg = (reg & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
402 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
403 break;
404 case TSENS_TRIP_STAGE1:
405 reg = (reg & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
406 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
407 break;
408 case TSENS_TRIP_STAGE0:
409 reg = (reg & TSENS_THRESHOLD_MIN_LIMIT_MASK)
410 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
411 break;
412 default:
413 return -EINVAL;
414 }
415
416 *temp = tsens_tz_code_to_degC(reg, tm_sensor->sensor_num);
417
418 return 0;
419}
420
421static int tsens_tz_get_crit_temp(struct thermal_zone_device *thermal,
422 unsigned long *temp)
423{
424 return tsens_tz_get_trip_temp(thermal, TSENS_TRIP_STAGE3, temp);
425}
426
427static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
428 int trip, long temp)
429{
430 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
431 unsigned int reg_th, reg_cntl;
432 int code, hi_code, lo_code, code_err_chk;
433
434 code_err_chk = code = tsens_tz_degC_to_code(temp,
435 tm_sensor->sensor_num);
436 if (!tm_sensor || trip < 0)
437 return -EINVAL;
438
439 lo_code = TSENS_THRESHOLD_MIN_CODE;
440 hi_code = TSENS_THRESHOLD_MAX_CODE;
441
442 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
443 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
444 switch (trip) {
445 case TSENS_TRIP_STAGE3:
446 code <<= TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
447 reg_th &= ~TSENS_THRESHOLD_MAX_LIMIT_MASK;
448
449 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
450 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
451 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
452 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
453 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
454 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
455 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
456 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
457 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
458 break;
459 case TSENS_TRIP_STAGE2:
460 code <<= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
461 reg_th &= ~TSENS_THRESHOLD_UPPER_LIMIT_MASK;
462
463 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
464 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
465 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
466 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
467 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
468 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
469 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
470 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
471 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
472 break;
473 case TSENS_TRIP_STAGE1:
474 code <<= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
475 reg_th &= ~TSENS_THRESHOLD_LOWER_LIMIT_MASK;
476
477 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
478 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
479 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
480 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
481 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
482 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
483 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
484 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
485 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
486 break;
487 case TSENS_TRIP_STAGE0:
488 code <<= TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
489 reg_th &= ~TSENS_THRESHOLD_MIN_LIMIT_MASK;
490
491 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
492 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
493 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
494 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
495 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
496 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
497 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
498 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
499 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
500 break;
501 default:
502 return -EINVAL;
503 }
504
505 if (code_err_chk < lo_code || code_err_chk > hi_code)
506 return -EINVAL;
507
508 writel_relaxed(reg_th | code, TSENS_THRESHOLD_ADDR);
509
510 return 0;
511}
512
513static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
514 .get_temp = tsens_tz_get_temp,
515 .get_mode = tsens_tz_get_mode,
516 .set_mode = tsens_tz_set_mode,
517 .get_trip_type = tsens_tz_get_trip_type,
518 .activate_trip_type = tsens_tz_activate_trip_type,
519 .get_trip_temp = tsens_tz_get_trip_temp,
520 .set_trip_temp = tsens_tz_set_trip_temp,
521 .get_crit_temp = tsens_tz_get_crit_temp,
522};
523
524static void notify_uspace_tsens_fn(struct work_struct *work)
525{
526 struct tsens_tm_device_sensor *tm = container_of(work,
527 struct tsens_tm_device_sensor, work);
528
529 sysfs_notify(&tm->tz_dev->device.kobj,
530 NULL, "type");
531}
532
533static irqreturn_t tsens_isr(int irq, void *data)
534{
535 struct tsens_tm_device *tm = data;
536 unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
537 bool upper_th_x, lower_th_x;
538 int adc_code;
539
540 reg = readl_relaxed(TSENS_CNTL_ADDR);
541 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR,
542 TSENS_CNTL_ADDR);
543 mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
544 threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
545 threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
546 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
547 threshold = (threshold & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
548 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
549 reg = sensor = readl_relaxed(TSENS_CNTL_ADDR);
550 sensor &= (uint32_t) SENSORS_EN;
551 sensor >>= TSENS_SENSOR0_SHIFT;
552 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
553 if (sensor & TSENS_MASK1) {
554 code = readl_relaxed(TSENS_S0_STATUS_ADDR +
555 (i << TSENS_STATUS_ADDR_OFFSET));
556 upper_th_x = code >= threshold;
557 lower_th_x = code <= threshold_low;
558 if (upper_th_x)
559 mask |= TSENS_UPPER_STATUS_CLR;
560 if (lower_th_x)
561 mask |= TSENS_LOWER_STATUS_CLR;
562 if (upper_th_x || lower_th_x) {
563 /* Notify user space */
564 schedule_work(&tm->sensor[i].work);
565 adc_code = readl_relaxed(TSENS_S0_STATUS_ADDR
566 + (i << TSENS_STATUS_ADDR_OFFSET));
567 pr_info("\nTrip point triggered by "
568 "current temperature (%d degrees) "
569 "measured by Temperature-Sensor %d\n",
570 tsens_tz_code_to_degC(adc_code, i), i);
571 }
572 }
573 sensor >>= 1;
574 }
575 writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
576 mb();
577 return IRQ_HANDLED;
578}
579
580static void tsens_disable_mode(void)
581{
582 unsigned int reg_cntl = 0;
583
584 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700585 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700586 writel_relaxed(reg_cntl &
587 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
588 TSENS_SENSOR0_SHIFT) | TSENS_8960_SLP_CLK_ENA
589 | TSENS_EN), TSENS_CNTL_ADDR);
590 else if (tmdev->hw_type == MSM_8660)
591 writel_relaxed(reg_cntl &
592 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
593 TSENS_SENSOR0_SHIFT) | TSENS_8660_SLP_CLK_ENA
594 | TSENS_EN), TSENS_CNTL_ADDR);
595}
596
597static void tsens_hw_init(void)
598{
599 unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
600
601 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
602 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
603
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700604 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615) {
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700605 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700606 (TSENS_MEASURE_PERIOD << 18) |
607 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
608 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
609 (((1 << tmdev->tsens_num_sensor) - 1) <<
610 TSENS_SENSOR0_SHIFT);
611 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700612 reg_cntl |= TSENS_EN;
613 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700614
615 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
616 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
617 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
618 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
619 } else if (tmdev->hw_type == MSM_8660) {
620 reg_cntl |= TSENS_8660_SLP_CLK_ENA | TSENS_EN |
621 (TSENS_MEASURE_PERIOD << 16) |
622 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
623 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
624 (((1 << tmdev->tsens_num_sensor) - 1) <<
625 TSENS_SENSOR0_SHIFT);
626
627 /* set TSENS_CONFIG bits (bits 29:28 of TSENS_CNTL) to '01';
628 this setting found to be optimal. */
629 reg_cntl = (reg_cntl & ~TSENS_8660_CONFIG_MASK) |
630 (TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT);
631
632 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
633 }
634
635 reg_thr |= (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) |
636 (TSENS_UPPER_LIMIT_TH << TSENS_THRESHOLD_UPPER_LIMIT_SHIFT) |
637 (TSENS_MIN_LIMIT_TH << TSENS_THRESHOLD_MIN_LIMIT_SHIFT) |
638 (TSENS_MAX_LIMIT_TH << TSENS_THRESHOLD_MAX_LIMIT_SHIFT);
639 writel_relaxed(reg_thr, TSENS_THRESHOLD_ADDR);
640}
641
642static int tsens_calib_sensors8660(void)
643{
644 uint32_t *main_sensor_addr, sensor_shift, red_sensor_shift;
645 uint32_t sensor_mask, red_sensor_mask;
646
647 main_sensor_addr = TSENS_8660_QFPROM_ADDR;
648 sensor_shift = TSENS_SENSOR_SHIFT;
649 red_sensor_shift = sensor_shift + TSENS_RED_SHIFT;
650 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
651 red_sensor_mask = TSENS_THRESHOLD_MAX_CODE << red_sensor_shift;
652 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
653 (readl_relaxed(main_sensor_addr) & sensor_mask)
654 >> sensor_shift;
655 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup =
656 (readl_relaxed(main_sensor_addr)
657 & red_sensor_mask) >> red_sensor_shift;
658 if (tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup)
659 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
660 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
661 if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
662 pr_err("%s: No temperature sensor data for calibration"
663 " in QFPROM!\n", __func__);
664 return -ENODEV;
665 }
666
667 tmdev->sensor[TSENS_MAIN_SENSOR].offset = tmdev->tsens_factor *
668 TSENS_CAL_DEGC - tmdev->slope_mul_tsens_factor *
669 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data;
670 tmdev->prev_reading_avail = false;
671 INIT_WORK(&tmdev->sensor[TSENS_MAIN_SENSOR].work,
672 notify_uspace_tsens_fn);
673
674 return 0;
675}
676
677static int tsens_calib_sensors8960(void)
678{
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700679 uint32_t *main_sensor_addr, sensor_shift, *backup_sensor_addr;
680 uint32_t sensor_mask, i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700681 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
682 main_sensor_addr = TSENS_8960_QFPROM_ADDR0 +
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700683 (TSENS_8960_QFPROM_SHIFT *
Siddartha Mohanadoss3e1ffc32011-11-30 17:10:44 -0800684 ((i & TSENS_8960_QFPROM_SHIFT) >> TSENS_SENSOR_QFPROM_SHIFT));
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700685 sensor_shift = (i % TSENS_8960_QFPROM_SHIFT) * TSENS_RED_SHIFT;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700686 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700687 backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 +
688 (TSENS_8960_QFPROM_SHIFT *
Siddartha Mohanadoss3e1ffc32011-11-30 17:10:44 -0800689 ((i & TSENS_8960_QFPROM_SHIFT) >> TSENS_SENSOR_QFPROM_SHIFT));
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700690
691 tmdev->sensor[i].calib_data = (readl_relaxed(main_sensor_addr)
692 & sensor_mask) >> sensor_shift;
693 tmdev->sensor[i].calib_data_backup =
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700694 (readl_relaxed(backup_sensor_addr) &
695 sensor_mask) >> sensor_shift;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700696 if (tmdev->sensor[i].calib_data_backup)
697 tmdev->sensor[i].calib_data =
698 tmdev->sensor[i].calib_data_backup;
699
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700700 if (!tmdev->sensor[i].calib_data) {
701 pr_err("%s: No temperature sensor:%d data for"
702 " calibration in QFPROM!\n", __func__, i);
703 return -ENODEV;
704 }
705 tmdev->sensor[i].offset = tmdev->tsens_factor *
706 TSENS_CAL_DEGC - tmdev->slope_mul_tsens_factor *
707 tmdev->sensor[i].calib_data;
708 tmdev->prev_reading_avail = false;
709 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
710 }
711
712 return 0;
713}
714
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700715static int tsens_check_version_support(void)
716{
717 int rc = 0;
718
719 if (tmdev->hw_type == MSM_8960)
720 if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
721 rc = -ENODEV;
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700722
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700723 return rc;
724}
725
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700726static int tsens_calib_sensors(void)
727{
Siddartha Mohanadoss73010e52011-10-31 11:23:18 -0700728 int rc = -ENODEV;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700729
730 if (tmdev->hw_type == MSM_8660)
731 rc = tsens_calib_sensors8660();
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700732 else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700733 rc = tsens_calib_sensors8960();
734
735 return rc;
736}
737
738static int __devinit tsens_tm_probe(struct platform_device *pdev)
739{
740 int rc, i;
741 struct tsens_platform_data *pdata;
742
743 pdata = pdev->dev.platform_data;
744 if (!pdata) {
745 pr_err("No TSENS Platform data\n");
746 return -EINVAL;
747 }
748
749 tmdev = kzalloc(sizeof(struct tsens_tm_device) +
750 pdata->tsens_num_sensor *
751 sizeof(struct tsens_tm_device_sensor),
752 GFP_KERNEL);
753 if (tmdev == NULL) {
754 pr_err("%s: kzalloc() failed.\n", __func__);
755 return -ENOMEM;
756 }
757
758 tmdev->slope_mul_tsens_factor = pdata->slope;
759 tmdev->tsens_factor = pdata->tsens_factor;
760 tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
761 tmdev->hw_type = pdata->hw_type;
762
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700763 rc = tsens_check_version_support();
764 if (rc < 0) {
765 kfree(tmdev);
766 return rc;
767 }
768
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700769 rc = tsens_calib_sensors();
770 if (rc < 0) {
771 kfree(tmdev);
772 return rc;
773 }
774
775 platform_set_drvdata(pdev, tmdev);
776
777 tsens_hw_init();
778
779 for (i = 0; i < pdata->tsens_num_sensor; i++) {
780 char name[17];
781 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
782 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
783 tmdev->sensor[i].sensor_num = i;
784 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
785 TSENS_TRIP_NUM, &tmdev->sensor[i],
786 &tsens_thermal_zone_ops, 0, 0, 0, 0);
787 if (tmdev->sensor[i].tz_dev == NULL) {
788 pr_err("%s: thermal_zone_device_register() failed.\n",
789 __func__);
790 rc = -ENODEV;
791 goto fail;
792 }
793 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
794 }
795
796 rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
797 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
798 if (rc < 0) {
799 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
800 for (i = 0; i < tmdev->tsens_num_sensor; i++)
801 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
802 goto fail;
803 }
804
805 tsens_disable_mode();
806
807 pr_notice("%s: OK\n", __func__);
808 mb();
809 return 0;
810fail:
811 tsens_disable_mode();
812 platform_set_drvdata(pdev, NULL);
813 kfree(tmdev);
814 mb();
815 return rc;
816}
817
818static int __devexit tsens_tm_remove(struct platform_device *pdev)
819{
820 struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
821 int i;
822
823 tsens_disable_mode();
824 mb();
825 free_irq(TSENS_UPPER_LOWER_INT, tmdev);
826 for (i = 0; i < tmdev->tsens_num_sensor; i++)
827 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
828 platform_set_drvdata(pdev, NULL);
829 kfree(tmdev);
830 return 0;
831}
832
833static struct platform_driver tsens_tm_driver = {
834 .probe = tsens_tm_probe,
835 .remove = __devexit_p(tsens_tm_remove),
836 .driver = {
837 .name = "tsens8960-tm",
838 .owner = THIS_MODULE,
839 },
840};
841
842static int __init tsens_init(void)
843{
844 return platform_driver_register(&tsens_tm_driver);
845}
846
847static void __exit tsens_exit(void)
848{
849 platform_driver_unregister(&tsens_tm_driver);
850}
851
852module_init(tsens_init);
853module_exit(tsens_exit);
854
855MODULE_LICENSE("GPL v2");
856MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
857MODULE_VERSION("1.0");
858MODULE_ALIAS("platform:tsens8960-tm");