blob: 78a1292f8be3c72a375dfa18f3c82e6a7046785d [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>
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -080026#include <linux/err.h>
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -070027#include <linux/pm.h>
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070028
29#include <mach/msm_iomap.h>
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -070030#include <mach/socinfo.h>
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070031
32/* Trips: from very hot to very cold */
33enum tsens_trip_type {
34 TSENS_TRIP_STAGE3 = 0,
35 TSENS_TRIP_STAGE2,
36 TSENS_TRIP_STAGE1,
37 TSENS_TRIP_STAGE0,
38 TSENS_TRIP_NUM,
39};
40
41/* MSM8960 TSENS register info */
42#define TSENS_CAL_DEGC 30
43#define TSENS_MAIN_SENSOR 0
44
45#define TSENS_8960_QFPROM_ADDR0 (MSM_QFPROM_BASE + 0x00000404)
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -070046#define TSENS_8960_QFPROM_SPARE_ADDR0 (MSM_QFPROM_BASE + 0x00000414)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070047#define TSENS_8960_CONFIG 0x9b
48#define TSENS_8960_CONFIG_SHIFT 0
49#define TSENS_8960_CONFIG_MASK (0xf << TSENS_8960_CONFIG_SHIFT)
50#define TSENS_CNTL_ADDR (MSM_CLK_CTL_BASE + 0x00003620)
51#define TSENS_EN BIT(0)
52#define TSENS_SW_RST BIT(1)
53#define TSENS_ADC_CLK_SEL BIT(2)
54#define SENSOR0_EN BIT(3)
55#define SENSOR1_EN BIT(4)
56#define SENSOR2_EN BIT(5)
57#define SENSOR3_EN BIT(6)
58#define SENSOR4_EN BIT(7)
59#define SENSORS_EN (SENSOR0_EN | SENSOR1_EN | \
60 SENSOR2_EN | SENSOR3_EN | SENSOR4_EN)
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -080061#define TSENS_STATUS_CNTL_OFFSET 8
62#define TSENS_MIN_STATUS_MASK BIT((tsens_status_cntl_start))
63#define TSENS_LOWER_STATUS_CLR BIT((tsens_status_cntl_start + 1))
64#define TSENS_UPPER_STATUS_CLR BIT((tsens_status_cntl_start + 2))
65#define TSENS_MAX_STATUS_MASK BIT((tsens_status_cntl_start + 3))
66
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070067#define TSENS_MEASURE_PERIOD 4 /* 1 sec. default */
68#define TSENS_8960_SLP_CLK_ENA BIT(26)
69
70#define TSENS_THRESHOLD_ADDR (MSM_CLK_CTL_BASE + 0x00003624)
71#define TSENS_THRESHOLD_MAX_CODE 0xff
72#define TSENS_THRESHOLD_MIN_CODE 0
73#define TSENS_THRESHOLD_MAX_LIMIT_SHIFT 24
74#define TSENS_THRESHOLD_MIN_LIMIT_SHIFT 16
75#define TSENS_THRESHOLD_UPPER_LIMIT_SHIFT 8
76#define TSENS_THRESHOLD_LOWER_LIMIT_SHIFT 0
77#define TSENS_THRESHOLD_MAX_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
78 TSENS_THRESHOLD_MAX_LIMIT_SHIFT)
79#define TSENS_THRESHOLD_MIN_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
80 TSENS_THRESHOLD_MIN_LIMIT_SHIFT)
81#define TSENS_THRESHOLD_UPPER_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
82 TSENS_THRESHOLD_UPPER_LIMIT_SHIFT)
83#define TSENS_THRESHOLD_LOWER_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
84 TSENS_THRESHOLD_LOWER_LIMIT_SHIFT)
85/* Initial temperature threshold values */
86#define TSENS_LOWER_LIMIT_TH 0x50
87#define TSENS_UPPER_LIMIT_TH 0xdf
Siddartha Mohanadossf34b4562012-01-10 15:11:28 -080088#define TSENS_MIN_LIMIT_TH 0x0
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070089#define TSENS_MAX_LIMIT_TH 0xff
90
91#define TSENS_S0_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003628)
92#define TSENS_STATUS_ADDR_OFFSET 2
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -080093#define TSENS_SENSOR_STATUS_SIZE 4
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070094#define TSENS_INT_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x0000363c)
95
96#define TSENS_LOWER_INT_MASK BIT(1)
97#define TSENS_UPPER_INT_MASK BIT(2)
98#define TSENS_MAX_INT_MASK BIT(3)
99#define TSENS_TRDY_MASK BIT(7)
100
101#define TSENS_8960_CONFIG_ADDR (MSM_CLK_CTL_BASE + 0x00003640)
102#define TSENS_TRDY_RDY_MIN_TIME 1000
103#define TSENS_TRDY_RDY_MAX_TIME 1100
104#define TSENS_SENSOR_SHIFT 16
105#define TSENS_RED_SHIFT 8
106#define TSENS_8960_QFPROM_SHIFT 4
Siddartha Mohanadoss3e1ffc32011-11-30 17:10:44 -0800107#define TSENS_SENSOR_QFPROM_SHIFT 2
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700108#define TSENS_SENSOR0_SHIFT 3
109#define TSENS_MASK1 1
110
111#define TSENS_8660_QFPROM_ADDR (MSM_QFPROM_BASE + 0x000000bc)
112#define TSENS_8660_QFPROM_RED_TEMP_SENSOR0_SHIFT 24
113#define TSENS_8660_QFPROM_TEMP_SENSOR0_SHIFT 16
114#define TSENS_8660_QFPROM_TEMP_SENSOR0_MASK (255 \
115 << TSENS_8660_QFPROM_TEMP_SENSOR0_SHIFT)
116#define TSENS_8660_CONFIG 01
117#define TSENS_8660_CONFIG_SHIFT 28
118#define TSENS_8660_CONFIG_MASK (3 << TSENS_8660_CONFIG_SHIFT)
119#define TSENS_8660_SLP_CLK_ENA BIT(24)
120
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800121#define TSENS_8064_SENSOR5_EN BIT(8)
122#define TSENS_8064_SENSOR6_EN BIT(9)
123#define TSENS_8064_SENSOR7_EN BIT(10)
124#define TSENS_8064_SENSOR8_EN BIT(11)
125#define TSENS_8064_SENSOR9_EN BIT(12)
126#define TSENS_8064_SENSOR10_EN BIT(13)
127#define TSENS_8064_SENSORS_EN (SENSORS_EN | \
128 TSENS_8064_SENSOR5_EN | \
129 TSENS_8064_SENSOR6_EN | \
130 TSENS_8064_SENSOR7_EN | \
131 TSENS_8064_SENSOR8_EN | \
132 TSENS_8064_SENSOR9_EN | \
133 TSENS_8064_SENSOR10_EN)
134#define TSENS_8064_STATUS_CNTL (MSM_CLK_CTL_BASE + 0x00003660)
135#define TSENS_8064_S5_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003664)
136#define TSENS_8064_SEQ_SENSORS 5
137#define TSENS_8064_S4_S5_OFFSET 40
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700138#define TSENS_CNTL_RESUME_MASK 0xfffffff9
139#define TSENS_8960_SENSOR_MASK 0xf8
140#define TSENS_8064_SENSOR_MASK 0x3ff8
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800141
142static int tsens_status_cntl_start;
143
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700144struct tsens_tm_device_sensor {
145 struct thermal_zone_device *tz_dev;
146 enum thermal_device_mode mode;
147 unsigned int sensor_num;
148 struct work_struct work;
149 int offset;
150 int calib_data;
151 int calib_data_backup;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800152 uint32_t slope_mul_tsens_factor;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700153};
154
155struct tsens_tm_device {
156 bool prev_reading_avail;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700157 int tsens_factor;
158 uint32_t tsens_num_sensor;
159 enum platform_type hw_type;
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700160 int pm_tsens_thr_data;
161 int pm_tsens_cntl;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700162 struct tsens_tm_device_sensor sensor[0];
163};
164
165struct tsens_tm_device *tmdev;
166
167/* Temperature on y axis and ADC-code on x-axis */
168static int tsens_tz_code_to_degC(int adc_code, int sensor_num)
169{
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800170 int degcbeforefactor, degc;
171 degcbeforefactor = (adc_code *
172 tmdev->sensor[sensor_num].slope_mul_tsens_factor
173 + tmdev->sensor[sensor_num].offset);
174
175 if (degcbeforefactor == 0)
176 degc = degcbeforefactor;
177 else if (degcbeforefactor > 0)
178 degc = (degcbeforefactor + tmdev->tsens_factor/2)
179 / tmdev->tsens_factor;
180 else
181 degc = (degcbeforefactor - tmdev->tsens_factor/2)
182 / tmdev->tsens_factor;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800183 return degc;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700184}
185
186static int tsens_tz_degC_to_code(int degC, int sensor_num)
187{
188 int code = (degC * tmdev->tsens_factor -
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800189 tmdev->sensor[sensor_num].offset
190 + tmdev->sensor[sensor_num].slope_mul_tsens_factor/2)
191 / tmdev->sensor[sensor_num].slope_mul_tsens_factor;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700192
193 if (code > TSENS_THRESHOLD_MAX_CODE)
194 code = TSENS_THRESHOLD_MAX_CODE;
195 else if (code < TSENS_THRESHOLD_MIN_CODE)
196 code = TSENS_THRESHOLD_MIN_CODE;
197 return code;
198}
199
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800200static void tsens8960_get_temp(int sensor_num, unsigned long *temp)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700201{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800202 unsigned int code, offset = 0, sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700203
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700204 if (!tmdev->prev_reading_avail) {
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800205 while (!(readl_relaxed(TSENS_INT_STATUS_ADDR)
206 & TSENS_TRDY_MASK))
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700207 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
208 TSENS_TRDY_RDY_MAX_TIME);
209 tmdev->prev_reading_avail = true;
210 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800211
212 sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
213 if (tmdev->hw_type == APQ_8064 &&
214 sensor_num >= TSENS_8064_SEQ_SENSORS)
215 offset = TSENS_8064_S4_S5_OFFSET;
216 code = readl_relaxed(sensor_addr + offset +
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800217 (sensor_num << TSENS_STATUS_ADDR_OFFSET));
218 *temp = tsens_tz_code_to_degC(code, sensor_num);
219}
220
221static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
222 unsigned long *temp)
223{
224 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
225
226 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
227 return -EINVAL;
228
229 tsens8960_get_temp(tm_sensor->sensor_num, temp);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700230
231 return 0;
232}
233
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800234int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
235{
236 if (!tmdev)
237 return -ENODEV;
238
239 tsens8960_get_temp(device->sensor_num, temp);
240
241 return 0;
242}
243EXPORT_SYMBOL(tsens_get_temp);
244
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700245static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
246 enum thermal_device_mode *mode)
247{
248 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
249
250 if (!tm_sensor || !mode)
251 return -EINVAL;
252
253 *mode = tm_sensor->mode;
254
255 return 0;
256}
257
258/* Function to enable the mode.
259 * If the main sensor is disabled all the sensors are disable and
260 * the clock is disabled.
261 * If the main sensor is not enabled and sub sensor is enabled
262 * returns with an error stating the main sensor is not enabled.
263 */
264static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
265 enum thermal_device_mode mode)
266{
267 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
268 unsigned int reg, mask, i;
269
270 if (!tm_sensor)
271 return -EINVAL;
272
273 if (mode != tm_sensor->mode) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700274 reg = readl_relaxed(TSENS_CNTL_ADDR);
275
276 mask = 1 << (tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT);
277 if (mode == THERMAL_DEVICE_ENABLED) {
278 if ((mask != SENSOR0_EN) && !(reg & SENSOR0_EN)) {
279 pr_info("Main sensor not enabled\n");
280 return -EINVAL;
281 }
282 writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700283 if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700284 tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800285 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700286 reg |= mask | TSENS_8960_SLP_CLK_ENA
287 | TSENS_EN;
288 else
289 reg |= mask | TSENS_8660_SLP_CLK_ENA
290 | TSENS_EN;
291 tmdev->prev_reading_avail = false;
292 } else {
293 reg &= ~mask;
294 if (!(reg & SENSOR0_EN)) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800295 if (tmdev->hw_type == APQ_8064)
296 reg &= ~(TSENS_8064_SENSORS_EN |
297 TSENS_8960_SLP_CLK_ENA |
298 TSENS_EN);
299 else if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700300 tmdev->hw_type == MDM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700301 reg &= ~(SENSORS_EN |
302 TSENS_8960_SLP_CLK_ENA |
303 TSENS_EN);
304 else
305 reg &= ~(SENSORS_EN |
306 TSENS_8660_SLP_CLK_ENA |
307 TSENS_EN);
308
309 for (i = 1; i < tmdev->tsens_num_sensor; i++)
310 tmdev->sensor[i].mode = mode;
311
312 }
313 }
314 writel_relaxed(reg, TSENS_CNTL_ADDR);
315 }
316 tm_sensor->mode = mode;
317
318 return 0;
319}
320
321static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
322 int trip, enum thermal_trip_type *type)
323{
324 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
325
326 if (!tm_sensor || trip < 0 || !type)
327 return -EINVAL;
328
329 switch (trip) {
330 case TSENS_TRIP_STAGE3:
331 *type = THERMAL_TRIP_CRITICAL;
332 break;
333 case TSENS_TRIP_STAGE2:
334 *type = THERMAL_TRIP_CONFIGURABLE_HI;
335 break;
336 case TSENS_TRIP_STAGE1:
337 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
338 break;
339 case TSENS_TRIP_STAGE0:
340 *type = THERMAL_TRIP_CRITICAL_LOW;
341 break;
342 default:
343 return -EINVAL;
344 }
345
346 return 0;
347}
348
349static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
350 int trip, enum thermal_trip_activation_mode mode)
351{
352 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
353 unsigned int reg_cntl, reg_th, code, hi_code, lo_code, mask;
354
355 if (!tm_sensor || trip < 0)
356 return -EINVAL;
357
358 lo_code = TSENS_THRESHOLD_MIN_CODE;
359 hi_code = TSENS_THRESHOLD_MAX_CODE;
360
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800361 if (tmdev->hw_type == APQ_8064)
362 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
363 else
364 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
365
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700366 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
367 switch (trip) {
368 case TSENS_TRIP_STAGE3:
369 code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
370 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
371 mask = TSENS_MAX_STATUS_MASK;
372
373 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
374 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
375 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
376 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
377 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
378 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
379 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
380 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
381 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
382 break;
383 case TSENS_TRIP_STAGE2:
384 code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
385 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
386 mask = TSENS_UPPER_STATUS_CLR;
387
388 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
389 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
390 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
391 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
392 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
393 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
394 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
395 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
396 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
397 break;
398 case TSENS_TRIP_STAGE1:
399 code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
400 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
401 mask = TSENS_LOWER_STATUS_CLR;
402
403 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
404 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
405 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
406 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
407 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
408 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
409 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
410 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
411 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
412 break;
413 case TSENS_TRIP_STAGE0:
414 code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
415 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
416 mask = TSENS_MIN_STATUS_MASK;
417
418 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
419 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
420 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
421 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
422 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
423 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
424 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
425 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
426 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
427 break;
428 default:
429 return -EINVAL;
430 }
431
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800432 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) {
433 if (tmdev->hw_type == APQ_8064)
434 writel_relaxed(reg_cntl | mask, TSENS_8064_STATUS_CNTL);
435 else
436 writel_relaxed(reg_cntl | mask, TSENS_CNTL_ADDR);
437 } else {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700438 if (code < lo_code || code > hi_code) {
439 pr_info("%s with invalid code %x\n", __func__, code);
440 return -EINVAL;
441 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800442 if (tmdev->hw_type == APQ_8064)
443 writel_relaxed(reg_cntl & ~mask,
444 TSENS_8064_STATUS_CNTL);
445 else
446 writel_relaxed(reg_cntl & ~mask, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700447 }
448 mb();
449 return 0;
450}
451
452static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
453 int trip, unsigned long *temp)
454{
455 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
456 unsigned int reg;
457
458 if (!tm_sensor || trip < 0 || !temp)
459 return -EINVAL;
460
461 reg = readl_relaxed(TSENS_THRESHOLD_ADDR);
462 switch (trip) {
463 case TSENS_TRIP_STAGE3:
464 reg = (reg & TSENS_THRESHOLD_MAX_LIMIT_MASK)
465 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
466 break;
467 case TSENS_TRIP_STAGE2:
468 reg = (reg & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
469 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
470 break;
471 case TSENS_TRIP_STAGE1:
472 reg = (reg & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
473 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
474 break;
475 case TSENS_TRIP_STAGE0:
476 reg = (reg & TSENS_THRESHOLD_MIN_LIMIT_MASK)
477 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
478 break;
479 default:
480 return -EINVAL;
481 }
482
483 *temp = tsens_tz_code_to_degC(reg, tm_sensor->sensor_num);
484
485 return 0;
486}
487
488static int tsens_tz_get_crit_temp(struct thermal_zone_device *thermal,
489 unsigned long *temp)
490{
491 return tsens_tz_get_trip_temp(thermal, TSENS_TRIP_STAGE3, temp);
492}
493
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800494static int tsens_tz_notify(struct thermal_zone_device *thermal,
495 int count, enum thermal_trip_type type)
496{
497 /* TSENS driver does not shutdown the device.
498 All Thermal notification are sent to the
499 thermal daemon to take appropriate action */
500 return 1;
501}
502
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700503static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
504 int trip, long temp)
505{
506 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
507 unsigned int reg_th, reg_cntl;
508 int code, hi_code, lo_code, code_err_chk;
509
510 code_err_chk = code = tsens_tz_degC_to_code(temp,
511 tm_sensor->sensor_num);
512 if (!tm_sensor || trip < 0)
513 return -EINVAL;
514
515 lo_code = TSENS_THRESHOLD_MIN_CODE;
516 hi_code = TSENS_THRESHOLD_MAX_CODE;
517
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800518 if (tmdev->hw_type == APQ_8064)
519 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
520 else
521 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700522 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
523 switch (trip) {
524 case TSENS_TRIP_STAGE3:
525 code <<= TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
526 reg_th &= ~TSENS_THRESHOLD_MAX_LIMIT_MASK;
527
528 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
529 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
530 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
531 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
532 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
533 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
534 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
535 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
536 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
537 break;
538 case TSENS_TRIP_STAGE2:
539 code <<= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
540 reg_th &= ~TSENS_THRESHOLD_UPPER_LIMIT_MASK;
541
542 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
543 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
544 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
545 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
546 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
547 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
548 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
549 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
550 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
551 break;
552 case TSENS_TRIP_STAGE1:
553 code <<= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
554 reg_th &= ~TSENS_THRESHOLD_LOWER_LIMIT_MASK;
555
556 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
557 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
558 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
559 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
560 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
561 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
562 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
563 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
564 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
565 break;
566 case TSENS_TRIP_STAGE0:
567 code <<= TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
568 reg_th &= ~TSENS_THRESHOLD_MIN_LIMIT_MASK;
569
570 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
571 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
572 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
573 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
574 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
575 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
576 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
577 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
578 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
579 break;
580 default:
581 return -EINVAL;
582 }
583
584 if (code_err_chk < lo_code || code_err_chk > hi_code)
585 return -EINVAL;
586
587 writel_relaxed(reg_th | code, TSENS_THRESHOLD_ADDR);
588
589 return 0;
590}
591
592static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
593 .get_temp = tsens_tz_get_temp,
594 .get_mode = tsens_tz_get_mode,
595 .set_mode = tsens_tz_set_mode,
596 .get_trip_type = tsens_tz_get_trip_type,
597 .activate_trip_type = tsens_tz_activate_trip_type,
598 .get_trip_temp = tsens_tz_get_trip_temp,
599 .set_trip_temp = tsens_tz_set_trip_temp,
600 .get_crit_temp = tsens_tz_get_crit_temp,
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800601 .notify = tsens_tz_notify,
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700602};
603
604static void notify_uspace_tsens_fn(struct work_struct *work)
605{
606 struct tsens_tm_device_sensor *tm = container_of(work,
607 struct tsens_tm_device_sensor, work);
608
609 sysfs_notify(&tm->tz_dev->device.kobj,
610 NULL, "type");
611}
612
613static irqreturn_t tsens_isr(int irq, void *data)
614{
615 struct tsens_tm_device *tm = data;
616 unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800617 unsigned int sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700618 bool upper_th_x, lower_th_x;
619 int adc_code;
620
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800621 if (tmdev->hw_type == APQ_8064) {
622 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
623 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
624 TSENS_UPPER_STATUS_CLR, TSENS_8064_STATUS_CNTL);
625 } else {
626 reg = readl_relaxed(TSENS_CNTL_ADDR);
627 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
628 TSENS_UPPER_STATUS_CLR, TSENS_CNTL_ADDR);
629 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700630 mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
631 threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
632 threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
633 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
634 threshold = (threshold & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
635 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800636 sensor = readl_relaxed(TSENS_CNTL_ADDR);
637 if (tmdev->hw_type == APQ_8064) {
638 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
639 sensor &= (uint32_t) TSENS_8064_SENSORS_EN;
640 } else {
641 reg = sensor;
642 sensor &= (uint32_t) SENSORS_EN;
643 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700644 sensor >>= TSENS_SENSOR0_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800645 sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700646 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800647 if (i == TSENS_8064_SEQ_SENSORS)
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800648 sensor_addr += TSENS_8064_S4_S5_OFFSET;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700649 if (sensor & TSENS_MASK1) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800650 code = readl_relaxed(sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700651 upper_th_x = code >= threshold;
652 lower_th_x = code <= threshold_low;
653 if (upper_th_x)
654 mask |= TSENS_UPPER_STATUS_CLR;
655 if (lower_th_x)
656 mask |= TSENS_LOWER_STATUS_CLR;
657 if (upper_th_x || lower_th_x) {
658 /* Notify user space */
659 schedule_work(&tm->sensor[i].work);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800660 adc_code = readl_relaxed(sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700661 pr_info("\nTrip point triggered by "
662 "current temperature (%d degrees) "
663 "measured by Temperature-Sensor %d\n",
664 tsens_tz_code_to_degC(adc_code, i), i);
665 }
666 }
667 sensor >>= 1;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800668 sensor_addr += TSENS_SENSOR_STATUS_SIZE;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700669 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800670 if (tmdev->hw_type == APQ_8064)
671 writel_relaxed(reg & mask, TSENS_8064_STATUS_CNTL);
672 else
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700673 writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
674 mb();
675 return IRQ_HANDLED;
676}
677
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800678static void tsens8960_sensor_mode_init(void)
679{
680 unsigned int reg_cntl = 0;
681
682 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700683 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800684 tmdev->hw_type == APQ_8064) {
685 writel_relaxed(reg_cntl &
686 ~((((1 << tmdev->tsens_num_sensor) - 1) >> 1)
687 << (TSENS_SENSOR0_SHIFT + 1)), TSENS_CNTL_ADDR);
688 tmdev->sensor[TSENS_MAIN_SENSOR].mode = THERMAL_DEVICE_ENABLED;
689 }
690}
691
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700692#ifdef CONFIG_PM
693static int tsens_suspend(struct device *dev)
694{
695 int i = 0;
696
697 tmdev->pm_tsens_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
698 tmdev->pm_tsens_cntl = readl_relaxed(TSENS_CNTL_ADDR);
699 writel_relaxed(tmdev->pm_tsens_cntl &
700 ~(TSENS_8960_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
701 tmdev->prev_reading_avail = 0;
702 for (i = 0; i < tmdev->tsens_num_sensor; i++)
703 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
704 disable_irq_nosync(TSENS_UPPER_LOWER_INT);
705 mb();
706 return 0;
707}
708
709static int tsens_resume(struct device *dev)
710{
711 unsigned int reg_cntl = 0, reg_cfg = 0, reg_sensor_mask = 0;
712 unsigned int reg_status_cntl = 0, reg_thr_data = 0, i = 0;
713
714 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
715 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
716
717 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
718 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
719 (TSENS_MEASURE_PERIOD << 18) |
720 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
721 SENSORS_EN;
722 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
723 } else if (tmdev->hw_type == APQ_8064) {
724 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
725 (TSENS_MEASURE_PERIOD << 18) |
Siddartha Mohanadoss5a443502012-05-24 23:43:48 -0700726 (((1 << tmdev->tsens_num_sensor) - 1)
727 << TSENS_SENSOR0_SHIFT);
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700728 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
729 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
730 reg_status_cntl |= TSENS_MIN_STATUS_MASK |
731 TSENS_MAX_STATUS_MASK;
732 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
733 }
734
735 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
736 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
737 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
738 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
739
740 writel_relaxed((tmdev->pm_tsens_cntl & TSENS_CNTL_RESUME_MASK),
741 TSENS_CNTL_ADDR);
742 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
743 writel_relaxed(tmdev->pm_tsens_thr_data, TSENS_THRESHOLD_ADDR);
744 reg_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
745 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615)
746 reg_sensor_mask = ((reg_cntl & TSENS_8960_SENSOR_MASK)
747 >> TSENS_SENSOR0_SHIFT);
748 else {
749 reg_sensor_mask = ((reg_cntl & TSENS_8064_SENSOR_MASK)
750 >> TSENS_SENSOR0_SHIFT);
751 }
752
753 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
754 if (reg_sensor_mask & TSENS_MASK1)
755 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
756 reg_sensor_mask >>= 1;
757 }
758
759 enable_irq(TSENS_UPPER_LOWER_INT);
760 mb();
761 return 0;
762}
763
764static const struct dev_pm_ops tsens_pm_ops = {
765 .suspend = tsens_suspend,
766 .resume = tsens_resume,
767};
768#endif
769
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700770static void tsens_disable_mode(void)
771{
772 unsigned int reg_cntl = 0;
773
774 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700775 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800776 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700777 writel_relaxed(reg_cntl &
778 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
779 TSENS_SENSOR0_SHIFT) | TSENS_8960_SLP_CLK_ENA
780 | TSENS_EN), TSENS_CNTL_ADDR);
781 else if (tmdev->hw_type == MSM_8660)
782 writel_relaxed(reg_cntl &
783 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
784 TSENS_SENSOR0_SHIFT) | TSENS_8660_SLP_CLK_ENA
785 | TSENS_EN), TSENS_CNTL_ADDR);
786}
787
788static void tsens_hw_init(void)
789{
790 unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800791 unsigned int reg_status_cntl = 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700792
793 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
794 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
795
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700796 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700797 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700798 (TSENS_MEASURE_PERIOD << 18) |
799 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
800 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700801 SENSORS_EN;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700802 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700803 reg_cntl |= TSENS_EN;
804 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700805
806 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
807 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
808 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
809 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
810 } else if (tmdev->hw_type == MSM_8660) {
811 reg_cntl |= TSENS_8660_SLP_CLK_ENA | TSENS_EN |
812 (TSENS_MEASURE_PERIOD << 16) |
813 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
814 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
815 (((1 << tmdev->tsens_num_sensor) - 1) <<
816 TSENS_SENSOR0_SHIFT);
817
818 /* set TSENS_CONFIG bits (bits 29:28 of TSENS_CNTL) to '01';
819 this setting found to be optimal. */
820 reg_cntl = (reg_cntl & ~TSENS_8660_CONFIG_MASK) |
821 (TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT);
822
823 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800824 } else if (tmdev->hw_type == APQ_8064) {
825 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
826 (TSENS_MEASURE_PERIOD << 18) |
Siddartha Mohanadoss5a443502012-05-24 23:43:48 -0700827 (((1 << tmdev->tsens_num_sensor) - 1)
828 << TSENS_SENSOR0_SHIFT);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800829 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
830 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
831 reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
832 TSENS_UPPER_STATUS_CLR |
833 TSENS_MIN_STATUS_MASK |
834 TSENS_MAX_STATUS_MASK;
835 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
836 reg_cntl |= TSENS_EN;
837 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
838
839 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
840 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
841 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
842 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700843 }
844
845 reg_thr |= (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) |
846 (TSENS_UPPER_LIMIT_TH << TSENS_THRESHOLD_UPPER_LIMIT_SHIFT) |
847 (TSENS_MIN_LIMIT_TH << TSENS_THRESHOLD_MIN_LIMIT_SHIFT) |
848 (TSENS_MAX_LIMIT_TH << TSENS_THRESHOLD_MAX_LIMIT_SHIFT);
849 writel_relaxed(reg_thr, TSENS_THRESHOLD_ADDR);
850}
851
852static int tsens_calib_sensors8660(void)
853{
854 uint32_t *main_sensor_addr, sensor_shift, red_sensor_shift;
855 uint32_t sensor_mask, red_sensor_mask;
856
857 main_sensor_addr = TSENS_8660_QFPROM_ADDR;
858 sensor_shift = TSENS_SENSOR_SHIFT;
859 red_sensor_shift = sensor_shift + TSENS_RED_SHIFT;
860 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
861 red_sensor_mask = TSENS_THRESHOLD_MAX_CODE << red_sensor_shift;
862 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
863 (readl_relaxed(main_sensor_addr) & sensor_mask)
864 >> sensor_shift;
865 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup =
866 (readl_relaxed(main_sensor_addr)
867 & red_sensor_mask) >> red_sensor_shift;
868 if (tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup)
869 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
870 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
871 if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
872 pr_err("%s: No temperature sensor data for calibration"
873 " in QFPROM!\n", __func__);
874 return -ENODEV;
875 }
876
877 tmdev->sensor[TSENS_MAIN_SENSOR].offset = tmdev->tsens_factor *
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800878 TSENS_CAL_DEGC -
879 tmdev->sensor[TSENS_MAIN_SENSOR].slope_mul_tsens_factor *
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700880 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800881
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700882 tmdev->prev_reading_avail = false;
883 INIT_WORK(&tmdev->sensor[TSENS_MAIN_SENSOR].work,
884 notify_uspace_tsens_fn);
885
886 return 0;
887}
888
889static int tsens_calib_sensors8960(void)
890{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800891 uint32_t i;
892 uint8_t *main_sensor_addr, *backup_sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700893 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800894 main_sensor_addr = TSENS_8960_QFPROM_ADDR0 + i;
895 backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 + i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700896
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800897 tmdev->sensor[i].calib_data = readb_relaxed(main_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700898 tmdev->sensor[i].calib_data_backup =
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800899 readb_relaxed(backup_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700900 if (tmdev->sensor[i].calib_data_backup)
901 tmdev->sensor[i].calib_data =
902 tmdev->sensor[i].calib_data_backup;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700903 if (!tmdev->sensor[i].calib_data) {
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800904 WARN(1, "%s: No temperature sensor:%d data for"
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700905 " calibration in QFPROM!\n", __func__, i);
906 return -ENODEV;
907 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800908 tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
909 tmdev->tsens_factor)
910 - (tmdev->sensor[i].calib_data *
911 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700912 tmdev->prev_reading_avail = false;
913 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
914 }
915
916 return 0;
917}
918
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700919static int tsens_check_version_support(void)
920{
921 int rc = 0;
922
923 if (tmdev->hw_type == MSM_8960)
924 if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
925 rc = -ENODEV;
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700926
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700927 return rc;
928}
929
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700930static int tsens_calib_sensors(void)
931{
Siddartha Mohanadoss73010e52011-10-31 11:23:18 -0700932 int rc = -ENODEV;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700933
934 if (tmdev->hw_type == MSM_8660)
935 rc = tsens_calib_sensors8660();
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700936 else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800937 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700938 rc = tsens_calib_sensors8960();
939
940 return rc;
941}
942
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800943int msm_tsens_early_init(struct tsens_platform_data *pdata)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700944{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800945 int rc = 0, i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700946
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700947 if (!pdata) {
948 pr_err("No TSENS Platform data\n");
949 return -EINVAL;
950 }
951
952 tmdev = kzalloc(sizeof(struct tsens_tm_device) +
953 pdata->tsens_num_sensor *
954 sizeof(struct tsens_tm_device_sensor),
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800955 GFP_ATOMIC);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700956 if (tmdev == NULL) {
957 pr_err("%s: kzalloc() failed.\n", __func__);
958 return -ENOMEM;
959 }
960
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800961 for (i = 0; i < pdata->tsens_num_sensor; i++)
962 tmdev->sensor[i].slope_mul_tsens_factor = pdata->slope[i];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700963 tmdev->tsens_factor = pdata->tsens_factor;
964 tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
965 tmdev->hw_type = pdata->hw_type;
966
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700967 rc = tsens_check_version_support();
968 if (rc < 0) {
969 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800970 tmdev = NULL;
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700971 return rc;
972 }
973
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700974 rc = tsens_calib_sensors();
975 if (rc < 0) {
976 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800977 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700978 return rc;
979 }
980
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800981 if (tmdev->hw_type == APQ_8064)
982 tsens_status_cntl_start = 0;
983 else
984 tsens_status_cntl_start = TSENS_STATUS_CNTL_OFFSET;
985
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700986 tsens_hw_init();
987
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800988 pr_debug("msm_tsens_early_init: done\n");
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800989
990 return rc;
991}
992
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700993static int __devinit tsens_tm_probe(struct platform_device *pdev)
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800994{
995 int rc, i;
996
997 if (!tmdev) {
998 pr_info("%s : TSENS early init not done.\n", __func__);
999 return -EFAULT;
1000 }
1001
1002 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadoss4d94a442012-02-22 13:47:11 -08001003 char name[18];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001004 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
1005 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
1006 tmdev->sensor[i].sensor_num = i;
1007 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
1008 TSENS_TRIP_NUM, &tmdev->sensor[i],
1009 &tsens_thermal_zone_ops, 0, 0, 0, 0);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -08001010 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001011 pr_err("%s: thermal_zone_device_register() failed.\n",
1012 __func__);
1013 rc = -ENODEV;
1014 goto fail;
1015 }
1016 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
1017 }
1018
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -08001019 tsens8960_sensor_mode_init();
1020
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001021 rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
1022 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
1023 if (rc < 0) {
1024 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
1025 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1026 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1027 goto fail;
1028 }
1029
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -08001030 pr_debug("%s: OK\n", __func__);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001031 mb();
1032 return 0;
1033fail:
1034 tsens_disable_mode();
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001035 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -08001036 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001037 mb();
1038 return rc;
1039}
1040
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001041static int __devexit tsens_tm_remove(struct platform_device *pdev)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001042{
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001043 int i;
1044
1045 tsens_disable_mode();
1046 mb();
1047 free_irq(TSENS_UPPER_LOWER_INT, tmdev);
1048 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1049 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001050 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -08001051 tmdev = NULL;
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001052 return 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001053}
1054
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001055static struct platform_driver tsens_tm_driver = {
1056 .probe = tsens_tm_probe,
1057 .remove = tsens_tm_remove,
1058 .driver = {
1059 .name = "tsens8960-tm",
1060 .owner = THIS_MODULE,
1061#ifdef CONFIG_PM
1062 .pm = &tsens_pm_ops,
1063#endif
1064 },
1065};
1066
1067static int __init _tsens_tm_init(void)
1068{
1069 return platform_driver_register(&tsens_tm_driver);
1070}
1071module_init(_tsens_tm_init);
1072
1073static void __exit _tsens_tm_remove(void)
1074{
1075 platform_driver_unregister(&tsens_tm_driver);
1076}
1077module_exit(_tsens_tm_remove);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001078
1079MODULE_LICENSE("GPL v2");
1080MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
1081MODULE_VERSION("1.0");
1082MODULE_ALIAS("platform:tsens8960-tm");