blob: f2be9dc982f36cc2c484c4a9b37ed8f243bac15a [file] [log] [blame]
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Siddartha Mohanadossacd24262011-08-18 11:19:00 -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 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
Siddartha Mohanadossf34b4562012-01-10 15:11:28 -080084#define TSENS_MIN_LIMIT_TH 0x0
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070085#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
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800168static void tsens8960_get_temp(int sensor_num, unsigned long *temp)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700169{
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700170 unsigned int code;
171
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700172 if (!tmdev->prev_reading_avail) {
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800173 while (!(readl_relaxed(TSENS_INT_STATUS_ADDR)
174 & TSENS_TRDY_MASK))
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700175 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
176 TSENS_TRDY_RDY_MAX_TIME);
177 tmdev->prev_reading_avail = true;
178 }
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800179
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700180 code = readl_relaxed(TSENS_S0_STATUS_ADDR +
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800181 (sensor_num << TSENS_STATUS_ADDR_OFFSET));
182 *temp = tsens_tz_code_to_degC(code, sensor_num);
183}
184
185static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
186 unsigned long *temp)
187{
188 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
189
190 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
191 return -EINVAL;
192
193 tsens8960_get_temp(tm_sensor->sensor_num, temp);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700194
195 return 0;
196}
197
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800198int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
199{
200 if (!tmdev)
201 return -ENODEV;
202
203 tsens8960_get_temp(device->sensor_num, temp);
204
205 return 0;
206}
207EXPORT_SYMBOL(tsens_get_temp);
208
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700209static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
210 enum thermal_device_mode *mode)
211{
212 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
213
214 if (!tm_sensor || !mode)
215 return -EINVAL;
216
217 *mode = tm_sensor->mode;
218
219 return 0;
220}
221
222/* Function to enable the mode.
223 * If the main sensor is disabled all the sensors are disable and
224 * the clock is disabled.
225 * If the main sensor is not enabled and sub sensor is enabled
226 * returns with an error stating the main sensor is not enabled.
227 */
228static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
229 enum thermal_device_mode mode)
230{
231 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
232 unsigned int reg, mask, i;
233
234 if (!tm_sensor)
235 return -EINVAL;
236
237 if (mode != tm_sensor->mode) {
238 pr_info("%s: mode: %d --> %d\n", __func__, tm_sensor->mode,
239 mode);
240
241 reg = readl_relaxed(TSENS_CNTL_ADDR);
242
243 mask = 1 << (tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT);
244 if (mode == THERMAL_DEVICE_ENABLED) {
245 if ((mask != SENSOR0_EN) && !(reg & SENSOR0_EN)) {
246 pr_info("Main sensor not enabled\n");
247 return -EINVAL;
248 }
249 writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700250 if (tmdev->hw_type == MSM_8960 ||
251 tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700252 reg |= mask | TSENS_8960_SLP_CLK_ENA
253 | TSENS_EN;
254 else
255 reg |= mask | TSENS_8660_SLP_CLK_ENA
256 | TSENS_EN;
257 tmdev->prev_reading_avail = false;
258 } else {
259 reg &= ~mask;
260 if (!(reg & SENSOR0_EN)) {
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700261 if (tmdev->hw_type == MSM_8960 ||
262 tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700263 reg &= ~(SENSORS_EN |
264 TSENS_8960_SLP_CLK_ENA |
265 TSENS_EN);
266 else
267 reg &= ~(SENSORS_EN |
268 TSENS_8660_SLP_CLK_ENA |
269 TSENS_EN);
270
271 for (i = 1; i < tmdev->tsens_num_sensor; i++)
272 tmdev->sensor[i].mode = mode;
273
274 }
275 }
276 writel_relaxed(reg, TSENS_CNTL_ADDR);
277 }
278 tm_sensor->mode = mode;
279
280 return 0;
281}
282
283static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
284 int trip, enum thermal_trip_type *type)
285{
286 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
287
288 if (!tm_sensor || trip < 0 || !type)
289 return -EINVAL;
290
291 switch (trip) {
292 case TSENS_TRIP_STAGE3:
293 *type = THERMAL_TRIP_CRITICAL;
294 break;
295 case TSENS_TRIP_STAGE2:
296 *type = THERMAL_TRIP_CONFIGURABLE_HI;
297 break;
298 case TSENS_TRIP_STAGE1:
299 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
300 break;
301 case TSENS_TRIP_STAGE0:
302 *type = THERMAL_TRIP_CRITICAL_LOW;
303 break;
304 default:
305 return -EINVAL;
306 }
307
308 return 0;
309}
310
311static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
312 int trip, enum thermal_trip_activation_mode mode)
313{
314 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
315 unsigned int reg_cntl, reg_th, code, hi_code, lo_code, mask;
316
317 if (!tm_sensor || trip < 0)
318 return -EINVAL;
319
320 lo_code = TSENS_THRESHOLD_MIN_CODE;
321 hi_code = TSENS_THRESHOLD_MAX_CODE;
322
323 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
324 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
325 switch (trip) {
326 case TSENS_TRIP_STAGE3:
327 code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
328 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
329 mask = TSENS_MAX_STATUS_MASK;
330
331 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
332 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
333 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
334 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
335 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
336 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
337 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
338 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
339 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
340 break;
341 case TSENS_TRIP_STAGE2:
342 code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
343 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
344 mask = TSENS_UPPER_STATUS_CLR;
345
346 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
347 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
348 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
349 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
350 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
351 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
352 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
353 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
354 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
355 break;
356 case TSENS_TRIP_STAGE1:
357 code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
358 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
359 mask = TSENS_LOWER_STATUS_CLR;
360
361 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
362 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
363 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
364 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
365 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
366 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
367 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
368 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
369 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
370 break;
371 case TSENS_TRIP_STAGE0:
372 code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
373 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
374 mask = TSENS_MIN_STATUS_MASK;
375
376 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
377 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
378 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
379 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
380 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
381 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
382 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
383 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
384 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
385 break;
386 default:
387 return -EINVAL;
388 }
389
390 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
391 writel_relaxed(reg_cntl | mask, TSENS_CNTL_ADDR);
392 else {
393 if (code < lo_code || code > hi_code) {
394 pr_info("%s with invalid code %x\n", __func__, code);
395 return -EINVAL;
396 }
397 writel_relaxed(reg_cntl & ~mask, TSENS_CNTL_ADDR);
398 }
399 mb();
400 return 0;
401}
402
403static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
404 int trip, unsigned long *temp)
405{
406 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
407 unsigned int reg;
408
409 if (!tm_sensor || trip < 0 || !temp)
410 return -EINVAL;
411
412 reg = readl_relaxed(TSENS_THRESHOLD_ADDR);
413 switch (trip) {
414 case TSENS_TRIP_STAGE3:
415 reg = (reg & TSENS_THRESHOLD_MAX_LIMIT_MASK)
416 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
417 break;
418 case TSENS_TRIP_STAGE2:
419 reg = (reg & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
420 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
421 break;
422 case TSENS_TRIP_STAGE1:
423 reg = (reg & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
424 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
425 break;
426 case TSENS_TRIP_STAGE0:
427 reg = (reg & TSENS_THRESHOLD_MIN_LIMIT_MASK)
428 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
429 break;
430 default:
431 return -EINVAL;
432 }
433
434 *temp = tsens_tz_code_to_degC(reg, tm_sensor->sensor_num);
435
436 return 0;
437}
438
439static int tsens_tz_get_crit_temp(struct thermal_zone_device *thermal,
440 unsigned long *temp)
441{
442 return tsens_tz_get_trip_temp(thermal, TSENS_TRIP_STAGE3, temp);
443}
444
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800445static int tsens_tz_notify(struct thermal_zone_device *thermal,
446 int count, enum thermal_trip_type type)
447{
448 /* TSENS driver does not shutdown the device.
449 All Thermal notification are sent to the
450 thermal daemon to take appropriate action */
451 return 1;
452}
453
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700454static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
455 int trip, long temp)
456{
457 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
458 unsigned int reg_th, reg_cntl;
459 int code, hi_code, lo_code, code_err_chk;
460
461 code_err_chk = code = tsens_tz_degC_to_code(temp,
462 tm_sensor->sensor_num);
463 if (!tm_sensor || trip < 0)
464 return -EINVAL;
465
466 lo_code = TSENS_THRESHOLD_MIN_CODE;
467 hi_code = TSENS_THRESHOLD_MAX_CODE;
468
469 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
470 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
471 switch (trip) {
472 case TSENS_TRIP_STAGE3:
473 code <<= TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
474 reg_th &= ~TSENS_THRESHOLD_MAX_LIMIT_MASK;
475
476 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
477 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
478 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
479 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
480 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
481 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
482 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
483 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
484 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
485 break;
486 case TSENS_TRIP_STAGE2:
487 code <<= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
488 reg_th &= ~TSENS_THRESHOLD_UPPER_LIMIT_MASK;
489
490 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
491 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
492 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
493 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
494 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
495 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
496 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
497 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
498 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
499 break;
500 case TSENS_TRIP_STAGE1:
501 code <<= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
502 reg_th &= ~TSENS_THRESHOLD_LOWER_LIMIT_MASK;
503
504 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
505 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
506 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
507 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
508 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
509 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
510 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
511 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
512 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
513 break;
514 case TSENS_TRIP_STAGE0:
515 code <<= TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
516 reg_th &= ~TSENS_THRESHOLD_MIN_LIMIT_MASK;
517
518 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
519 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
520 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
521 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
522 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
523 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
524 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
525 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
526 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
527 break;
528 default:
529 return -EINVAL;
530 }
531
532 if (code_err_chk < lo_code || code_err_chk > hi_code)
533 return -EINVAL;
534
535 writel_relaxed(reg_th | code, TSENS_THRESHOLD_ADDR);
536
537 return 0;
538}
539
540static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
541 .get_temp = tsens_tz_get_temp,
542 .get_mode = tsens_tz_get_mode,
543 .set_mode = tsens_tz_set_mode,
544 .get_trip_type = tsens_tz_get_trip_type,
545 .activate_trip_type = tsens_tz_activate_trip_type,
546 .get_trip_temp = tsens_tz_get_trip_temp,
547 .set_trip_temp = tsens_tz_set_trip_temp,
548 .get_crit_temp = tsens_tz_get_crit_temp,
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800549 .notify = tsens_tz_notify,
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700550};
551
552static void notify_uspace_tsens_fn(struct work_struct *work)
553{
554 struct tsens_tm_device_sensor *tm = container_of(work,
555 struct tsens_tm_device_sensor, work);
556
557 sysfs_notify(&tm->tz_dev->device.kobj,
558 NULL, "type");
559}
560
561static irqreturn_t tsens_isr(int irq, void *data)
562{
563 struct tsens_tm_device *tm = data;
564 unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
565 bool upper_th_x, lower_th_x;
566 int adc_code;
567
568 reg = readl_relaxed(TSENS_CNTL_ADDR);
569 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR,
570 TSENS_CNTL_ADDR);
571 mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
572 threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
573 threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
574 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
575 threshold = (threshold & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
576 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
577 reg = sensor = readl_relaxed(TSENS_CNTL_ADDR);
578 sensor &= (uint32_t) SENSORS_EN;
579 sensor >>= TSENS_SENSOR0_SHIFT;
580 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
581 if (sensor & TSENS_MASK1) {
582 code = readl_relaxed(TSENS_S0_STATUS_ADDR +
583 (i << TSENS_STATUS_ADDR_OFFSET));
584 upper_th_x = code >= threshold;
585 lower_th_x = code <= threshold_low;
586 if (upper_th_x)
587 mask |= TSENS_UPPER_STATUS_CLR;
588 if (lower_th_x)
589 mask |= TSENS_LOWER_STATUS_CLR;
590 if (upper_th_x || lower_th_x) {
591 /* Notify user space */
592 schedule_work(&tm->sensor[i].work);
593 adc_code = readl_relaxed(TSENS_S0_STATUS_ADDR
594 + (i << TSENS_STATUS_ADDR_OFFSET));
595 pr_info("\nTrip point triggered by "
596 "current temperature (%d degrees) "
597 "measured by Temperature-Sensor %d\n",
598 tsens_tz_code_to_degC(adc_code, i), i);
599 }
600 }
601 sensor >>= 1;
602 }
603 writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
604 mb();
605 return IRQ_HANDLED;
606}
607
608static void tsens_disable_mode(void)
609{
610 unsigned int reg_cntl = 0;
611
612 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700613 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700614 writel_relaxed(reg_cntl &
615 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
616 TSENS_SENSOR0_SHIFT) | TSENS_8960_SLP_CLK_ENA
617 | TSENS_EN), TSENS_CNTL_ADDR);
618 else if (tmdev->hw_type == MSM_8660)
619 writel_relaxed(reg_cntl &
620 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
621 TSENS_SENSOR0_SHIFT) | TSENS_8660_SLP_CLK_ENA
622 | TSENS_EN), TSENS_CNTL_ADDR);
623}
624
625static void tsens_hw_init(void)
626{
627 unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
628
629 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
630 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
631
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700632 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615) {
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700633 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700634 (TSENS_MEASURE_PERIOD << 18) |
635 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
636 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
637 (((1 << tmdev->tsens_num_sensor) - 1) <<
638 TSENS_SENSOR0_SHIFT);
639 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700640 reg_cntl |= TSENS_EN;
641 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700642
643 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
644 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
645 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
646 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
647 } else if (tmdev->hw_type == MSM_8660) {
648 reg_cntl |= TSENS_8660_SLP_CLK_ENA | TSENS_EN |
649 (TSENS_MEASURE_PERIOD << 16) |
650 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
651 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
652 (((1 << tmdev->tsens_num_sensor) - 1) <<
653 TSENS_SENSOR0_SHIFT);
654
655 /* set TSENS_CONFIG bits (bits 29:28 of TSENS_CNTL) to '01';
656 this setting found to be optimal. */
657 reg_cntl = (reg_cntl & ~TSENS_8660_CONFIG_MASK) |
658 (TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT);
659
660 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
661 }
662
663 reg_thr |= (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) |
664 (TSENS_UPPER_LIMIT_TH << TSENS_THRESHOLD_UPPER_LIMIT_SHIFT) |
665 (TSENS_MIN_LIMIT_TH << TSENS_THRESHOLD_MIN_LIMIT_SHIFT) |
666 (TSENS_MAX_LIMIT_TH << TSENS_THRESHOLD_MAX_LIMIT_SHIFT);
667 writel_relaxed(reg_thr, TSENS_THRESHOLD_ADDR);
668}
669
670static int tsens_calib_sensors8660(void)
671{
672 uint32_t *main_sensor_addr, sensor_shift, red_sensor_shift;
673 uint32_t sensor_mask, red_sensor_mask;
674
675 main_sensor_addr = TSENS_8660_QFPROM_ADDR;
676 sensor_shift = TSENS_SENSOR_SHIFT;
677 red_sensor_shift = sensor_shift + TSENS_RED_SHIFT;
678 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
679 red_sensor_mask = TSENS_THRESHOLD_MAX_CODE << red_sensor_shift;
680 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
681 (readl_relaxed(main_sensor_addr) & sensor_mask)
682 >> sensor_shift;
683 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup =
684 (readl_relaxed(main_sensor_addr)
685 & red_sensor_mask) >> red_sensor_shift;
686 if (tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup)
687 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
688 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
689 if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
690 pr_err("%s: No temperature sensor data for calibration"
691 " in QFPROM!\n", __func__);
692 return -ENODEV;
693 }
694
695 tmdev->sensor[TSENS_MAIN_SENSOR].offset = tmdev->tsens_factor *
696 TSENS_CAL_DEGC - tmdev->slope_mul_tsens_factor *
697 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data;
698 tmdev->prev_reading_avail = false;
699 INIT_WORK(&tmdev->sensor[TSENS_MAIN_SENSOR].work,
700 notify_uspace_tsens_fn);
701
702 return 0;
703}
704
705static int tsens_calib_sensors8960(void)
706{
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700707 uint32_t *main_sensor_addr, sensor_shift, *backup_sensor_addr;
708 uint32_t sensor_mask, i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700709 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
710 main_sensor_addr = TSENS_8960_QFPROM_ADDR0 +
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700711 (TSENS_8960_QFPROM_SHIFT *
Siddartha Mohanadoss3e1ffc32011-11-30 17:10:44 -0800712 ((i & TSENS_8960_QFPROM_SHIFT) >> TSENS_SENSOR_QFPROM_SHIFT));
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700713 sensor_shift = (i % TSENS_8960_QFPROM_SHIFT) * TSENS_RED_SHIFT;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700714 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700715 backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 +
716 (TSENS_8960_QFPROM_SHIFT *
Siddartha Mohanadoss3e1ffc32011-11-30 17:10:44 -0800717 ((i & TSENS_8960_QFPROM_SHIFT) >> TSENS_SENSOR_QFPROM_SHIFT));
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700718
719 tmdev->sensor[i].calib_data = (readl_relaxed(main_sensor_addr)
720 & sensor_mask) >> sensor_shift;
721 tmdev->sensor[i].calib_data_backup =
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -0700722 (readl_relaxed(backup_sensor_addr) &
723 sensor_mask) >> sensor_shift;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700724 if (tmdev->sensor[i].calib_data_backup)
725 tmdev->sensor[i].calib_data =
726 tmdev->sensor[i].calib_data_backup;
727
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700728 if (!tmdev->sensor[i].calib_data) {
729 pr_err("%s: No temperature sensor:%d data for"
730 " calibration in QFPROM!\n", __func__, i);
731 return -ENODEV;
732 }
733 tmdev->sensor[i].offset = tmdev->tsens_factor *
734 TSENS_CAL_DEGC - tmdev->slope_mul_tsens_factor *
735 tmdev->sensor[i].calib_data;
736 tmdev->prev_reading_avail = false;
737 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
738 }
739
740 return 0;
741}
742
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700743static int tsens_check_version_support(void)
744{
745 int rc = 0;
746
747 if (tmdev->hw_type == MSM_8960)
748 if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
749 rc = -ENODEV;
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700750
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700751 return rc;
752}
753
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700754static int tsens_calib_sensors(void)
755{
Siddartha Mohanadoss73010e52011-10-31 11:23:18 -0700756 int rc = -ENODEV;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700757
758 if (tmdev->hw_type == MSM_8660)
759 rc = tsens_calib_sensors8660();
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700760 else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700761 rc = tsens_calib_sensors8960();
762
763 return rc;
764}
765
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800766int msm_tsens_early_init(struct tsens_platform_data *pdata)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700767{
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800768 int rc = 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700769
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700770 if (!pdata) {
771 pr_err("No TSENS Platform data\n");
772 return -EINVAL;
773 }
774
775 tmdev = kzalloc(sizeof(struct tsens_tm_device) +
776 pdata->tsens_num_sensor *
777 sizeof(struct tsens_tm_device_sensor),
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800778 GFP_ATOMIC);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700779 if (tmdev == NULL) {
780 pr_err("%s: kzalloc() failed.\n", __func__);
781 return -ENOMEM;
782 }
783
784 tmdev->slope_mul_tsens_factor = pdata->slope;
785 tmdev->tsens_factor = pdata->tsens_factor;
786 tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
787 tmdev->hw_type = pdata->hw_type;
788
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700789 rc = tsens_check_version_support();
790 if (rc < 0) {
791 kfree(tmdev);
792 return rc;
793 }
794
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700795 rc = tsens_calib_sensors();
796 if (rc < 0) {
797 kfree(tmdev);
798 return rc;
799 }
800
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700801 tsens_hw_init();
802
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800803 pr_info("msm_tsens_early_init: done\n");
804
805 return rc;
806}
807
808static int __init tsens_tm_init(void)
809{
810 int rc, i;
811
812 if (!tmdev) {
813 pr_info("%s : TSENS early init not done.\n", __func__);
814 return -EFAULT;
815 }
816
817 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700818 char name[17];
819 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
820 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
821 tmdev->sensor[i].sensor_num = i;
822 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
823 TSENS_TRIP_NUM, &tmdev->sensor[i],
824 &tsens_thermal_zone_ops, 0, 0, 0, 0);
825 if (tmdev->sensor[i].tz_dev == NULL) {
826 pr_err("%s: thermal_zone_device_register() failed.\n",
827 __func__);
828 rc = -ENODEV;
829 goto fail;
830 }
831 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
832 }
833
834 rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
835 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
836 if (rc < 0) {
837 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
838 for (i = 0; i < tmdev->tsens_num_sensor; i++)
839 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
840 goto fail;
841 }
842
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700843 pr_notice("%s: OK\n", __func__);
844 mb();
845 return 0;
846fail:
847 tsens_disable_mode();
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700848 kfree(tmdev);
849 mb();
850 return rc;
851}
852
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800853static void __exit tsens_tm_remove(void)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700854{
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700855 int i;
856
857 tsens_disable_mode();
858 mb();
859 free_irq(TSENS_UPPER_LOWER_INT, tmdev);
860 for (i = 0; i < tmdev->tsens_num_sensor; i++)
861 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700862 kfree(tmdev);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700863}
864
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800865module_init(tsens_tm_init);
866module_exit(tsens_tm_remove);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700867
868MODULE_LICENSE("GPL v2");
869MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
870MODULE_VERSION("1.0");
871MODULE_ALIAS("platform:tsens8960-tm");