blob: fbb377e3880298a6cbf6745199d4c3ed20d966f4 [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) |
726 TSENS_8064_SENSORS_EN;
727 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
728 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
729 reg_status_cntl |= TSENS_MIN_STATUS_MASK |
730 TSENS_MAX_STATUS_MASK;
731 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
732 }
733
734 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
735 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
736 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
737 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
738
739 writel_relaxed((tmdev->pm_tsens_cntl & TSENS_CNTL_RESUME_MASK),
740 TSENS_CNTL_ADDR);
741 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
742 writel_relaxed(tmdev->pm_tsens_thr_data, TSENS_THRESHOLD_ADDR);
743 reg_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
744 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615)
745 reg_sensor_mask = ((reg_cntl & TSENS_8960_SENSOR_MASK)
746 >> TSENS_SENSOR0_SHIFT);
747 else {
748 reg_sensor_mask = ((reg_cntl & TSENS_8064_SENSOR_MASK)
749 >> TSENS_SENSOR0_SHIFT);
750 }
751
752 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
753 if (reg_sensor_mask & TSENS_MASK1)
754 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
755 reg_sensor_mask >>= 1;
756 }
757
758 enable_irq(TSENS_UPPER_LOWER_INT);
759 mb();
760 return 0;
761}
762
763static const struct dev_pm_ops tsens_pm_ops = {
764 .suspend = tsens_suspend,
765 .resume = tsens_resume,
766};
767#endif
768
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700769static void tsens_disable_mode(void)
770{
771 unsigned int reg_cntl = 0;
772
773 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700774 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800775 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700776 writel_relaxed(reg_cntl &
777 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
778 TSENS_SENSOR0_SHIFT) | TSENS_8960_SLP_CLK_ENA
779 | TSENS_EN), TSENS_CNTL_ADDR);
780 else if (tmdev->hw_type == MSM_8660)
781 writel_relaxed(reg_cntl &
782 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
783 TSENS_SENSOR0_SHIFT) | TSENS_8660_SLP_CLK_ENA
784 | TSENS_EN), TSENS_CNTL_ADDR);
785}
786
787static void tsens_hw_init(void)
788{
789 unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800790 unsigned int reg_status_cntl = 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700791
792 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
793 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
794
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700795 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700796 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700797 (TSENS_MEASURE_PERIOD << 18) |
798 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
799 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700800 SENSORS_EN;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700801 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700802 reg_cntl |= TSENS_EN;
803 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700804
805 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
806 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
807 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
808 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
809 } else if (tmdev->hw_type == MSM_8660) {
810 reg_cntl |= TSENS_8660_SLP_CLK_ENA | TSENS_EN |
811 (TSENS_MEASURE_PERIOD << 16) |
812 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
813 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
814 (((1 << tmdev->tsens_num_sensor) - 1) <<
815 TSENS_SENSOR0_SHIFT);
816
817 /* set TSENS_CONFIG bits (bits 29:28 of TSENS_CNTL) to '01';
818 this setting found to be optimal. */
819 reg_cntl = (reg_cntl & ~TSENS_8660_CONFIG_MASK) |
820 (TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT);
821
822 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800823 } else if (tmdev->hw_type == APQ_8064) {
824 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
825 (TSENS_MEASURE_PERIOD << 18) |
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700826 TSENS_8064_SENSORS_EN;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800827 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
828 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
829 reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
830 TSENS_UPPER_STATUS_CLR |
831 TSENS_MIN_STATUS_MASK |
832 TSENS_MAX_STATUS_MASK;
833 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
834 reg_cntl |= TSENS_EN;
835 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
836
837 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
838 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
839 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
840 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700841 }
842
843 reg_thr |= (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) |
844 (TSENS_UPPER_LIMIT_TH << TSENS_THRESHOLD_UPPER_LIMIT_SHIFT) |
845 (TSENS_MIN_LIMIT_TH << TSENS_THRESHOLD_MIN_LIMIT_SHIFT) |
846 (TSENS_MAX_LIMIT_TH << TSENS_THRESHOLD_MAX_LIMIT_SHIFT);
847 writel_relaxed(reg_thr, TSENS_THRESHOLD_ADDR);
848}
849
850static int tsens_calib_sensors8660(void)
851{
852 uint32_t *main_sensor_addr, sensor_shift, red_sensor_shift;
853 uint32_t sensor_mask, red_sensor_mask;
854
855 main_sensor_addr = TSENS_8660_QFPROM_ADDR;
856 sensor_shift = TSENS_SENSOR_SHIFT;
857 red_sensor_shift = sensor_shift + TSENS_RED_SHIFT;
858 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
859 red_sensor_mask = TSENS_THRESHOLD_MAX_CODE << red_sensor_shift;
860 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
861 (readl_relaxed(main_sensor_addr) & sensor_mask)
862 >> sensor_shift;
863 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup =
864 (readl_relaxed(main_sensor_addr)
865 & red_sensor_mask) >> red_sensor_shift;
866 if (tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup)
867 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
868 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
869 if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
870 pr_err("%s: No temperature sensor data for calibration"
871 " in QFPROM!\n", __func__);
872 return -ENODEV;
873 }
874
875 tmdev->sensor[TSENS_MAIN_SENSOR].offset = tmdev->tsens_factor *
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800876 TSENS_CAL_DEGC -
877 tmdev->sensor[TSENS_MAIN_SENSOR].slope_mul_tsens_factor *
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700878 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800879
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700880 tmdev->prev_reading_avail = false;
881 INIT_WORK(&tmdev->sensor[TSENS_MAIN_SENSOR].work,
882 notify_uspace_tsens_fn);
883
884 return 0;
885}
886
887static int tsens_calib_sensors8960(void)
888{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800889 uint32_t i;
890 uint8_t *main_sensor_addr, *backup_sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700891 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800892 main_sensor_addr = TSENS_8960_QFPROM_ADDR0 + i;
893 backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 + i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700894
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800895 tmdev->sensor[i].calib_data = readb_relaxed(main_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700896 tmdev->sensor[i].calib_data_backup =
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800897 readb_relaxed(backup_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700898 if (tmdev->sensor[i].calib_data_backup)
899 tmdev->sensor[i].calib_data =
900 tmdev->sensor[i].calib_data_backup;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700901 if (!tmdev->sensor[i].calib_data) {
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800902 WARN(1, "%s: No temperature sensor:%d data for"
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700903 " calibration in QFPROM!\n", __func__, i);
904 return -ENODEV;
905 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800906 tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
907 tmdev->tsens_factor)
908 - (tmdev->sensor[i].calib_data *
909 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700910 tmdev->prev_reading_avail = false;
911 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
912 }
913
914 return 0;
915}
916
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700917static int tsens_check_version_support(void)
918{
919 int rc = 0;
920
921 if (tmdev->hw_type == MSM_8960)
922 if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
923 rc = -ENODEV;
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700924
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700925 return rc;
926}
927
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700928static int tsens_calib_sensors(void)
929{
Siddartha Mohanadoss73010e52011-10-31 11:23:18 -0700930 int rc = -ENODEV;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700931
932 if (tmdev->hw_type == MSM_8660)
933 rc = tsens_calib_sensors8660();
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700934 else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800935 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700936 rc = tsens_calib_sensors8960();
937
938 return rc;
939}
940
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800941int msm_tsens_early_init(struct tsens_platform_data *pdata)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700942{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800943 int rc = 0, i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700944
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700945 if (!pdata) {
946 pr_err("No TSENS Platform data\n");
947 return -EINVAL;
948 }
949
950 tmdev = kzalloc(sizeof(struct tsens_tm_device) +
951 pdata->tsens_num_sensor *
952 sizeof(struct tsens_tm_device_sensor),
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800953 GFP_ATOMIC);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700954 if (tmdev == NULL) {
955 pr_err("%s: kzalloc() failed.\n", __func__);
956 return -ENOMEM;
957 }
958
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800959 for (i = 0; i < pdata->tsens_num_sensor; i++)
960 tmdev->sensor[i].slope_mul_tsens_factor = pdata->slope[i];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700961 tmdev->tsens_factor = pdata->tsens_factor;
962 tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
963 tmdev->hw_type = pdata->hw_type;
964
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700965 rc = tsens_check_version_support();
966 if (rc < 0) {
967 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800968 tmdev = NULL;
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700969 return rc;
970 }
971
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700972 rc = tsens_calib_sensors();
973 if (rc < 0) {
974 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800975 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700976 return rc;
977 }
978
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800979 if (tmdev->hw_type == APQ_8064)
980 tsens_status_cntl_start = 0;
981 else
982 tsens_status_cntl_start = TSENS_STATUS_CNTL_OFFSET;
983
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700984 tsens_hw_init();
985
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800986 pr_debug("msm_tsens_early_init: done\n");
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800987
988 return rc;
989}
990
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700991static int __devinit tsens_tm_probe(struct platform_device *pdev)
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800992{
993 int rc, i;
994
995 if (!tmdev) {
996 pr_info("%s : TSENS early init not done.\n", __func__);
997 return -EFAULT;
998 }
999
1000 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadoss4d94a442012-02-22 13:47:11 -08001001 char name[18];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001002 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
1003 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
1004 tmdev->sensor[i].sensor_num = i;
1005 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
1006 TSENS_TRIP_NUM, &tmdev->sensor[i],
1007 &tsens_thermal_zone_ops, 0, 0, 0, 0);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -08001008 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001009 pr_err("%s: thermal_zone_device_register() failed.\n",
1010 __func__);
1011 rc = -ENODEV;
1012 goto fail;
1013 }
1014 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
1015 }
1016
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -08001017 tsens8960_sensor_mode_init();
1018
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001019 rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
1020 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
1021 if (rc < 0) {
1022 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
1023 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1024 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1025 goto fail;
1026 }
1027
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -08001028 pr_debug("%s: OK\n", __func__);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001029 mb();
1030 return 0;
1031fail:
1032 tsens_disable_mode();
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001033 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -08001034 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001035 mb();
1036 return rc;
1037}
1038
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001039static int __devexit tsens_tm_remove(struct platform_device *pdev)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001040{
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001041 int i;
1042
1043 tsens_disable_mode();
1044 mb();
1045 free_irq(TSENS_UPPER_LOWER_INT, tmdev);
1046 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1047 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001048 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -08001049 tmdev = NULL;
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001050 return 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001051}
1052
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001053static struct platform_driver tsens_tm_driver = {
1054 .probe = tsens_tm_probe,
1055 .remove = tsens_tm_remove,
1056 .driver = {
1057 .name = "tsens8960-tm",
1058 .owner = THIS_MODULE,
1059#ifdef CONFIG_PM
1060 .pm = &tsens_pm_ops,
1061#endif
1062 },
1063};
1064
1065static int __init _tsens_tm_init(void)
1066{
1067 return platform_driver_register(&tsens_tm_driver);
1068}
1069module_init(_tsens_tm_init);
1070
1071static void __exit _tsens_tm_remove(void)
1072{
1073 platform_driver_unregister(&tsens_tm_driver);
1074}
1075module_exit(_tsens_tm_remove);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001076
1077MODULE_LICENSE("GPL v2");
1078MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
1079MODULE_VERSION("1.0");
1080MODULE_ALIAS("platform:tsens8960-tm");