blob: 837ac21a0802629f90af80a08a904f2e85932e22 [file] [log] [blame]
Siddartha Mohanadossde952f72013-04-09 10:21:57 -07001/* Copyright (c) 2011-2013, The Linux Foundation. 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 Mohanadoss11e5ce52012-09-27 16:09:02 -070067#define TSENS_MEASURE_PERIOD 1
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070068#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 Mohanadoss7dc2eb02012-08-19 18:15:17 -0700162 struct work_struct tsens_work;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700163 struct tsens_tm_device_sensor sensor[0];
164};
165
166struct tsens_tm_device *tmdev;
167
168/* Temperature on y axis and ADC-code on x-axis */
169static int tsens_tz_code_to_degC(int adc_code, int sensor_num)
170{
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800171 int degcbeforefactor, degc;
172 degcbeforefactor = (adc_code *
173 tmdev->sensor[sensor_num].slope_mul_tsens_factor
174 + tmdev->sensor[sensor_num].offset);
175
176 if (degcbeforefactor == 0)
177 degc = degcbeforefactor;
178 else if (degcbeforefactor > 0)
179 degc = (degcbeforefactor + tmdev->tsens_factor/2)
180 / tmdev->tsens_factor;
181 else
182 degc = (degcbeforefactor - tmdev->tsens_factor/2)
183 / tmdev->tsens_factor;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800184 return degc;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700185}
186
187static int tsens_tz_degC_to_code(int degC, int sensor_num)
188{
189 int code = (degC * tmdev->tsens_factor -
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800190 tmdev->sensor[sensor_num].offset
191 + tmdev->sensor[sensor_num].slope_mul_tsens_factor/2)
192 / tmdev->sensor[sensor_num].slope_mul_tsens_factor;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700193
194 if (code > TSENS_THRESHOLD_MAX_CODE)
195 code = TSENS_THRESHOLD_MAX_CODE;
196 else if (code < TSENS_THRESHOLD_MIN_CODE)
197 code = TSENS_THRESHOLD_MIN_CODE;
198 return code;
199}
200
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800201static void tsens8960_get_temp(int sensor_num, unsigned long *temp)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700202{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800203 unsigned int code, offset = 0, sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700204
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700205 if (!tmdev->prev_reading_avail) {
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800206 while (!(readl_relaxed(TSENS_INT_STATUS_ADDR)
207 & TSENS_TRDY_MASK))
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700208 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
209 TSENS_TRDY_RDY_MAX_TIME);
210 tmdev->prev_reading_avail = true;
211 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800212
213 sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
214 if (tmdev->hw_type == APQ_8064 &&
215 sensor_num >= TSENS_8064_SEQ_SENSORS)
216 offset = TSENS_8064_S4_S5_OFFSET;
217 code = readl_relaxed(sensor_addr + offset +
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800218 (sensor_num << TSENS_STATUS_ADDR_OFFSET));
219 *temp = tsens_tz_code_to_degC(code, sensor_num);
220}
221
222static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
223 unsigned long *temp)
224{
225 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
226
227 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
228 return -EINVAL;
229
230 tsens8960_get_temp(tm_sensor->sensor_num, temp);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700231
232 return 0;
233}
234
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800235int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
236{
237 if (!tmdev)
238 return -ENODEV;
239
240 tsens8960_get_temp(device->sensor_num, temp);
241
242 return 0;
243}
244EXPORT_SYMBOL(tsens_get_temp);
245
Siddartha Mohanadossde952f72013-04-09 10:21:57 -0700246int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors)
247{
248 if (!tmdev)
249 return -ENODEV;
250
251 *tsens_num_sensors = tmdev->tsens_num_sensor;
252
253 return 0;
254}
255EXPORT_SYMBOL(tsens_get_max_sensor_num);
256
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700257static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
258 enum thermal_device_mode *mode)
259{
260 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
261
262 if (!tm_sensor || !mode)
263 return -EINVAL;
264
265 *mode = tm_sensor->mode;
266
267 return 0;
268}
269
270/* Function to enable the mode.
271 * If the main sensor is disabled all the sensors are disable and
272 * the clock is disabled.
273 * If the main sensor is not enabled and sub sensor is enabled
274 * returns with an error stating the main sensor is not enabled.
275 */
276static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
277 enum thermal_device_mode mode)
278{
279 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
280 unsigned int reg, mask, i;
281
282 if (!tm_sensor)
283 return -EINVAL;
284
285 if (mode != tm_sensor->mode) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700286 reg = readl_relaxed(TSENS_CNTL_ADDR);
287
288 mask = 1 << (tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT);
289 if (mode == THERMAL_DEVICE_ENABLED) {
290 if ((mask != SENSOR0_EN) && !(reg & SENSOR0_EN)) {
291 pr_info("Main sensor not enabled\n");
292 return -EINVAL;
293 }
294 writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700295 if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700296 tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800297 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700298 reg |= mask | TSENS_8960_SLP_CLK_ENA
299 | TSENS_EN;
300 else
301 reg |= mask | TSENS_8660_SLP_CLK_ENA
302 | TSENS_EN;
303 tmdev->prev_reading_avail = false;
304 } else {
305 reg &= ~mask;
306 if (!(reg & SENSOR0_EN)) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800307 if (tmdev->hw_type == APQ_8064)
308 reg &= ~(TSENS_8064_SENSORS_EN |
309 TSENS_8960_SLP_CLK_ENA |
310 TSENS_EN);
311 else if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700312 tmdev->hw_type == MDM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700313 reg &= ~(SENSORS_EN |
314 TSENS_8960_SLP_CLK_ENA |
315 TSENS_EN);
316 else
317 reg &= ~(SENSORS_EN |
318 TSENS_8660_SLP_CLK_ENA |
319 TSENS_EN);
320
321 for (i = 1; i < tmdev->tsens_num_sensor; i++)
322 tmdev->sensor[i].mode = mode;
323
324 }
325 }
326 writel_relaxed(reg, TSENS_CNTL_ADDR);
327 }
328 tm_sensor->mode = mode;
329
330 return 0;
331}
332
333static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
334 int trip, enum thermal_trip_type *type)
335{
336 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
337
338 if (!tm_sensor || trip < 0 || !type)
339 return -EINVAL;
340
341 switch (trip) {
342 case TSENS_TRIP_STAGE3:
343 *type = THERMAL_TRIP_CRITICAL;
344 break;
345 case TSENS_TRIP_STAGE2:
346 *type = THERMAL_TRIP_CONFIGURABLE_HI;
347 break;
348 case TSENS_TRIP_STAGE1:
349 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
350 break;
351 case TSENS_TRIP_STAGE0:
352 *type = THERMAL_TRIP_CRITICAL_LOW;
353 break;
354 default:
355 return -EINVAL;
356 }
357
358 return 0;
359}
360
361static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
362 int trip, enum thermal_trip_activation_mode mode)
363{
364 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
365 unsigned int reg_cntl, reg_th, code, hi_code, lo_code, mask;
366
367 if (!tm_sensor || trip < 0)
368 return -EINVAL;
369
370 lo_code = TSENS_THRESHOLD_MIN_CODE;
371 hi_code = TSENS_THRESHOLD_MAX_CODE;
372
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800373 if (tmdev->hw_type == APQ_8064)
374 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
375 else
376 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
377
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700378 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
379 switch (trip) {
380 case TSENS_TRIP_STAGE3:
381 code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
382 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
383 mask = TSENS_MAX_STATUS_MASK;
384
385 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
386 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
387 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
388 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
389 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
390 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
391 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
392 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
393 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
394 break;
395 case TSENS_TRIP_STAGE2:
396 code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
397 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
398 mask = TSENS_UPPER_STATUS_CLR;
399
400 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
401 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
402 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
403 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
404 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
405 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
406 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
407 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
408 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
409 break;
410 case TSENS_TRIP_STAGE1:
411 code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
412 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
413 mask = TSENS_LOWER_STATUS_CLR;
414
415 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
416 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
417 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
418 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
419 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
420 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
421 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
422 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
423 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
424 break;
425 case TSENS_TRIP_STAGE0:
426 code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
427 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
428 mask = TSENS_MIN_STATUS_MASK;
429
430 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
431 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
432 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
433 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
434 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
435 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
436 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
437 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
438 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
439 break;
440 default:
441 return -EINVAL;
442 }
443
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800444 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) {
445 if (tmdev->hw_type == APQ_8064)
446 writel_relaxed(reg_cntl | mask, TSENS_8064_STATUS_CNTL);
447 else
448 writel_relaxed(reg_cntl | mask, TSENS_CNTL_ADDR);
449 } else {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700450 if (code < lo_code || code > hi_code) {
451 pr_info("%s with invalid code %x\n", __func__, code);
452 return -EINVAL;
453 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800454 if (tmdev->hw_type == APQ_8064)
455 writel_relaxed(reg_cntl & ~mask,
456 TSENS_8064_STATUS_CNTL);
457 else
458 writel_relaxed(reg_cntl & ~mask, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700459 }
460 mb();
461 return 0;
462}
463
464static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
465 int trip, unsigned long *temp)
466{
467 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
468 unsigned int reg;
469
470 if (!tm_sensor || trip < 0 || !temp)
471 return -EINVAL;
472
473 reg = readl_relaxed(TSENS_THRESHOLD_ADDR);
474 switch (trip) {
475 case TSENS_TRIP_STAGE3:
476 reg = (reg & TSENS_THRESHOLD_MAX_LIMIT_MASK)
477 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
478 break;
479 case TSENS_TRIP_STAGE2:
480 reg = (reg & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
481 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
482 break;
483 case TSENS_TRIP_STAGE1:
484 reg = (reg & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
485 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
486 break;
487 case TSENS_TRIP_STAGE0:
488 reg = (reg & TSENS_THRESHOLD_MIN_LIMIT_MASK)
489 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
490 break;
491 default:
492 return -EINVAL;
493 }
494
495 *temp = tsens_tz_code_to_degC(reg, tm_sensor->sensor_num);
496
497 return 0;
498}
499
500static int tsens_tz_get_crit_temp(struct thermal_zone_device *thermal,
501 unsigned long *temp)
502{
503 return tsens_tz_get_trip_temp(thermal, TSENS_TRIP_STAGE3, temp);
504}
505
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800506static int tsens_tz_notify(struct thermal_zone_device *thermal,
507 int count, enum thermal_trip_type type)
508{
509 /* TSENS driver does not shutdown the device.
510 All Thermal notification are sent to the
511 thermal daemon to take appropriate action */
512 return 1;
513}
514
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700515static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
516 int trip, long temp)
517{
518 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
519 unsigned int reg_th, reg_cntl;
520 int code, hi_code, lo_code, code_err_chk;
521
522 code_err_chk = code = tsens_tz_degC_to_code(temp,
523 tm_sensor->sensor_num);
524 if (!tm_sensor || trip < 0)
525 return -EINVAL;
526
527 lo_code = TSENS_THRESHOLD_MIN_CODE;
528 hi_code = TSENS_THRESHOLD_MAX_CODE;
529
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800530 if (tmdev->hw_type == APQ_8064)
531 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
532 else
533 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700534 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
535 switch (trip) {
536 case TSENS_TRIP_STAGE3:
537 code <<= TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
538 reg_th &= ~TSENS_THRESHOLD_MAX_LIMIT_MASK;
539
540 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
541 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
542 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
543 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
544 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
545 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
546 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
547 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
548 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
549 break;
550 case TSENS_TRIP_STAGE2:
551 code <<= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
552 reg_th &= ~TSENS_THRESHOLD_UPPER_LIMIT_MASK;
553
554 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
555 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
556 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
557 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
558 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
559 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
560 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
561 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
562 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
563 break;
564 case TSENS_TRIP_STAGE1:
565 code <<= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
566 reg_th &= ~TSENS_THRESHOLD_LOWER_LIMIT_MASK;
567
568 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
569 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
570 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
571 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
572 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
573 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
574 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
575 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
576 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
577 break;
578 case TSENS_TRIP_STAGE0:
579 code <<= TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
580 reg_th &= ~TSENS_THRESHOLD_MIN_LIMIT_MASK;
581
582 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
583 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
584 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
585 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
586 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
587 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
588 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
589 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
590 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
591 break;
592 default:
593 return -EINVAL;
594 }
595
596 if (code_err_chk < lo_code || code_err_chk > hi_code)
597 return -EINVAL;
598
599 writel_relaxed(reg_th | code, TSENS_THRESHOLD_ADDR);
600
601 return 0;
602}
603
604static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
605 .get_temp = tsens_tz_get_temp,
606 .get_mode = tsens_tz_get_mode,
607 .set_mode = tsens_tz_set_mode,
608 .get_trip_type = tsens_tz_get_trip_type,
609 .activate_trip_type = tsens_tz_activate_trip_type,
610 .get_trip_temp = tsens_tz_get_trip_temp,
611 .set_trip_temp = tsens_tz_set_trip_temp,
612 .get_crit_temp = tsens_tz_get_crit_temp,
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800613 .notify = tsens_tz_notify,
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700614};
615
616static void notify_uspace_tsens_fn(struct work_struct *work)
617{
618 struct tsens_tm_device_sensor *tm = container_of(work,
619 struct tsens_tm_device_sensor, work);
620
621 sysfs_notify(&tm->tz_dev->device.kobj,
622 NULL, "type");
623}
624
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700625static void tsens_scheduler_fn(struct work_struct *work)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700626{
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700627 struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
628 tsens_work);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700629 unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800630 unsigned int sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700631 bool upper_th_x, lower_th_x;
632 int adc_code;
633
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800634 if (tmdev->hw_type == APQ_8064) {
635 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
636 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
637 TSENS_UPPER_STATUS_CLR, TSENS_8064_STATUS_CNTL);
638 } else {
639 reg = readl_relaxed(TSENS_CNTL_ADDR);
640 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
641 TSENS_UPPER_STATUS_CLR, TSENS_CNTL_ADDR);
642 }
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700643
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700644 mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
645 threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
646 threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
647 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
648 threshold = (threshold & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
649 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800650 sensor = readl_relaxed(TSENS_CNTL_ADDR);
651 if (tmdev->hw_type == APQ_8064) {
652 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
653 sensor &= (uint32_t) TSENS_8064_SENSORS_EN;
654 } else {
655 reg = sensor;
656 sensor &= (uint32_t) SENSORS_EN;
657 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700658 sensor >>= TSENS_SENSOR0_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800659 sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700660 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800661 if (i == TSENS_8064_SEQ_SENSORS)
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800662 sensor_addr += TSENS_8064_S4_S5_OFFSET;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700663 if (sensor & TSENS_MASK1) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800664 code = readl_relaxed(sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700665 upper_th_x = code >= threshold;
666 lower_th_x = code <= threshold_low;
667 if (upper_th_x)
668 mask |= TSENS_UPPER_STATUS_CLR;
669 if (lower_th_x)
670 mask |= TSENS_LOWER_STATUS_CLR;
671 if (upper_th_x || lower_th_x) {
672 /* Notify user space */
673 schedule_work(&tm->sensor[i].work);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800674 adc_code = readl_relaxed(sensor_addr);
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700675 pr_debug("Trigger (%d degrees) for sensor %d\n",
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700676 tsens_tz_code_to_degC(adc_code, i), i);
677 }
678 }
679 sensor >>= 1;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800680 sensor_addr += TSENS_SENSOR_STATUS_SIZE;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700681 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800682 if (tmdev->hw_type == APQ_8064)
683 writel_relaxed(reg & mask, TSENS_8064_STATUS_CNTL);
684 else
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700685 writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
686 mb();
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700687}
688
689static irqreturn_t tsens_isr(int irq, void *data)
690{
691 schedule_work(&tmdev->tsens_work);
692
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700693 return IRQ_HANDLED;
694}
695
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700696#ifdef CONFIG_PM
697static int tsens_suspend(struct device *dev)
698{
699 int i = 0;
700
701 tmdev->pm_tsens_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
702 tmdev->pm_tsens_cntl = readl_relaxed(TSENS_CNTL_ADDR);
703 writel_relaxed(tmdev->pm_tsens_cntl &
704 ~(TSENS_8960_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
705 tmdev->prev_reading_avail = 0;
706 for (i = 0; i < tmdev->tsens_num_sensor; i++)
707 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
708 disable_irq_nosync(TSENS_UPPER_LOWER_INT);
709 mb();
710 return 0;
711}
712
713static int tsens_resume(struct device *dev)
714{
715 unsigned int reg_cntl = 0, reg_cfg = 0, reg_sensor_mask = 0;
716 unsigned int reg_status_cntl = 0, reg_thr_data = 0, i = 0;
717
718 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
719 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
720
721 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
722 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
723 (TSENS_MEASURE_PERIOD << 18) |
724 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
725 SENSORS_EN;
726 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
727 } else if (tmdev->hw_type == APQ_8064) {
728 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
729 (TSENS_MEASURE_PERIOD << 18) |
Siddartha Mohanadoss5a443502012-05-24 23:43:48 -0700730 (((1 << tmdev->tsens_num_sensor) - 1)
731 << TSENS_SENSOR0_SHIFT);
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700732 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
733 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
734 reg_status_cntl |= TSENS_MIN_STATUS_MASK |
735 TSENS_MAX_STATUS_MASK;
736 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
737 }
738
739 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
740 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
741 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
742 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
743
744 writel_relaxed((tmdev->pm_tsens_cntl & TSENS_CNTL_RESUME_MASK),
745 TSENS_CNTL_ADDR);
746 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
747 writel_relaxed(tmdev->pm_tsens_thr_data, TSENS_THRESHOLD_ADDR);
748 reg_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
749 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615)
750 reg_sensor_mask = ((reg_cntl & TSENS_8960_SENSOR_MASK)
751 >> TSENS_SENSOR0_SHIFT);
752 else {
753 reg_sensor_mask = ((reg_cntl & TSENS_8064_SENSOR_MASK)
754 >> TSENS_SENSOR0_SHIFT);
755 }
756
757 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
758 if (reg_sensor_mask & TSENS_MASK1)
759 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
760 reg_sensor_mask >>= 1;
761 }
762
763 enable_irq(TSENS_UPPER_LOWER_INT);
764 mb();
765 return 0;
766}
767
768static const struct dev_pm_ops tsens_pm_ops = {
769 .suspend = tsens_suspend,
770 .resume = tsens_resume,
771};
772#endif
773
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700774static void tsens_disable_mode(void)
775{
776 unsigned int reg_cntl = 0;
777
778 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700779 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800780 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700781 writel_relaxed(reg_cntl &
782 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
783 TSENS_SENSOR0_SHIFT) | TSENS_8960_SLP_CLK_ENA
784 | TSENS_EN), TSENS_CNTL_ADDR);
785 else if (tmdev->hw_type == MSM_8660)
786 writel_relaxed(reg_cntl &
787 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
788 TSENS_SENSOR0_SHIFT) | TSENS_8660_SLP_CLK_ENA
789 | TSENS_EN), TSENS_CNTL_ADDR);
790}
791
792static void tsens_hw_init(void)
793{
794 unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800795 unsigned int reg_status_cntl = 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700796
797 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
798 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
799
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700800 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700801 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700802 (TSENS_MEASURE_PERIOD << 18) |
803 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
804 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700805 SENSORS_EN;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700806 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700807 reg_cntl |= TSENS_EN;
808 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700809
810 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
811 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
812 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
813 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
814 } else if (tmdev->hw_type == MSM_8660) {
815 reg_cntl |= TSENS_8660_SLP_CLK_ENA | TSENS_EN |
816 (TSENS_MEASURE_PERIOD << 16) |
817 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
818 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
819 (((1 << tmdev->tsens_num_sensor) - 1) <<
820 TSENS_SENSOR0_SHIFT);
821
822 /* set TSENS_CONFIG bits (bits 29:28 of TSENS_CNTL) to '01';
823 this setting found to be optimal. */
824 reg_cntl = (reg_cntl & ~TSENS_8660_CONFIG_MASK) |
825 (TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT);
826
827 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800828 } else if (tmdev->hw_type == APQ_8064) {
829 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
830 (TSENS_MEASURE_PERIOD << 18) |
Siddartha Mohanadoss5a443502012-05-24 23:43:48 -0700831 (((1 << tmdev->tsens_num_sensor) - 1)
832 << TSENS_SENSOR0_SHIFT);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800833 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
834 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
835 reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
836 TSENS_UPPER_STATUS_CLR |
837 TSENS_MIN_STATUS_MASK |
838 TSENS_MAX_STATUS_MASK;
839 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
840 reg_cntl |= TSENS_EN;
841 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
842
843 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
844 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
845 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
846 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700847 }
848
849 reg_thr |= (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) |
850 (TSENS_UPPER_LIMIT_TH << TSENS_THRESHOLD_UPPER_LIMIT_SHIFT) |
851 (TSENS_MIN_LIMIT_TH << TSENS_THRESHOLD_MIN_LIMIT_SHIFT) |
852 (TSENS_MAX_LIMIT_TH << TSENS_THRESHOLD_MAX_LIMIT_SHIFT);
853 writel_relaxed(reg_thr, TSENS_THRESHOLD_ADDR);
854}
855
856static int tsens_calib_sensors8660(void)
857{
858 uint32_t *main_sensor_addr, sensor_shift, red_sensor_shift;
859 uint32_t sensor_mask, red_sensor_mask;
860
861 main_sensor_addr = TSENS_8660_QFPROM_ADDR;
862 sensor_shift = TSENS_SENSOR_SHIFT;
863 red_sensor_shift = sensor_shift + TSENS_RED_SHIFT;
864 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
865 red_sensor_mask = TSENS_THRESHOLD_MAX_CODE << red_sensor_shift;
866 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
867 (readl_relaxed(main_sensor_addr) & sensor_mask)
868 >> sensor_shift;
869 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup =
870 (readl_relaxed(main_sensor_addr)
871 & red_sensor_mask) >> red_sensor_shift;
872 if (tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup)
873 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
874 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
875 if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700876 pr_err("QFPROM TSENS calibration data not present\n");
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700877 return -ENODEV;
878 }
879
880 tmdev->sensor[TSENS_MAIN_SENSOR].offset = tmdev->tsens_factor *
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800881 TSENS_CAL_DEGC -
882 tmdev->sensor[TSENS_MAIN_SENSOR].slope_mul_tsens_factor *
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700883 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800884
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700885 tmdev->prev_reading_avail = false;
886 INIT_WORK(&tmdev->sensor[TSENS_MAIN_SENSOR].work,
887 notify_uspace_tsens_fn);
888
889 return 0;
890}
891
892static int tsens_calib_sensors8960(void)
893{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800894 uint32_t i;
895 uint8_t *main_sensor_addr, *backup_sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700896 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800897 main_sensor_addr = TSENS_8960_QFPROM_ADDR0 + i;
898 backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 + i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700899
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800900 tmdev->sensor[i].calib_data = readb_relaxed(main_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700901 tmdev->sensor[i].calib_data_backup =
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800902 readb_relaxed(backup_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700903 if (tmdev->sensor[i].calib_data_backup)
904 tmdev->sensor[i].calib_data =
905 tmdev->sensor[i].calib_data_backup;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700906 if (!tmdev->sensor[i].calib_data) {
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700907 pr_err("QFPROM TSENS calibration data not present\n");
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700908 return -ENODEV;
909 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800910 tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
911 tmdev->tsens_factor)
912 - (tmdev->sensor[i].calib_data *
913 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700914 tmdev->prev_reading_avail = false;
915 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
916 }
917
918 return 0;
919}
920
921static int tsens_calib_sensors(void)
922{
Siddartha Mohanadoss73010e52011-10-31 11:23:18 -0700923 int rc = -ENODEV;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700924
925 if (tmdev->hw_type == MSM_8660)
926 rc = tsens_calib_sensors8660();
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700927 else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800928 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700929 rc = tsens_calib_sensors8960();
930
931 return rc;
932}
933
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800934int msm_tsens_early_init(struct tsens_platform_data *pdata)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700935{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800936 int rc = 0, i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700937
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700938 if (!pdata) {
939 pr_err("No TSENS Platform data\n");
940 return -EINVAL;
941 }
942
943 tmdev = kzalloc(sizeof(struct tsens_tm_device) +
944 pdata->tsens_num_sensor *
945 sizeof(struct tsens_tm_device_sensor),
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800946 GFP_ATOMIC);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700947 if (tmdev == NULL) {
948 pr_err("%s: kzalloc() failed.\n", __func__);
949 return -ENOMEM;
950 }
951
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800952 for (i = 0; i < pdata->tsens_num_sensor; i++)
953 tmdev->sensor[i].slope_mul_tsens_factor = pdata->slope[i];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700954 tmdev->tsens_factor = pdata->tsens_factor;
955 tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
956 tmdev->hw_type = pdata->hw_type;
957
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700958 rc = tsens_calib_sensors();
959 if (rc < 0) {
960 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800961 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700962 return rc;
963 }
964
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800965 if (tmdev->hw_type == APQ_8064)
966 tsens_status_cntl_start = 0;
967 else
968 tsens_status_cntl_start = TSENS_STATUS_CNTL_OFFSET;
969
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700970 tsens_hw_init();
971
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800972 pr_debug("msm_tsens_early_init: done\n");
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800973
974 return rc;
975}
976
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700977static int __devinit tsens_tm_probe(struct platform_device *pdev)
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800978{
979 int rc, i;
980
981 if (!tmdev) {
982 pr_info("%s : TSENS early init not done.\n", __func__);
983 return -EFAULT;
984 }
985
986 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadoss4d94a442012-02-22 13:47:11 -0800987 char name[18];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700988 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
989 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
990 tmdev->sensor[i].sensor_num = i;
991 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
992 TSENS_TRIP_NUM, &tmdev->sensor[i],
993 &tsens_thermal_zone_ops, 0, 0, 0, 0);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800994 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700995 pr_err("%s: thermal_zone_device_register() failed.\n",
996 __func__);
997 rc = -ENODEV;
998 goto fail;
999 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001000 }
1001
1002 rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
1003 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
1004 if (rc < 0) {
1005 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
1006 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1007 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1008 goto fail;
1009 }
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -07001010 INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001011
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -08001012 pr_debug("%s: OK\n", __func__);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001013 mb();
1014 return 0;
1015fail:
1016 tsens_disable_mode();
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001017 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -08001018 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001019 mb();
1020 return rc;
1021}
1022
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001023static int __devexit tsens_tm_remove(struct platform_device *pdev)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001024{
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001025 int i;
1026
1027 tsens_disable_mode();
1028 mb();
1029 free_irq(TSENS_UPPER_LOWER_INT, tmdev);
1030 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1031 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001032 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -08001033 tmdev = NULL;
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001034 return 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001035}
1036
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001037static struct platform_driver tsens_tm_driver = {
1038 .probe = tsens_tm_probe,
1039 .remove = tsens_tm_remove,
1040 .driver = {
1041 .name = "tsens8960-tm",
1042 .owner = THIS_MODULE,
1043#ifdef CONFIG_PM
1044 .pm = &tsens_pm_ops,
1045#endif
1046 },
1047};
1048
1049static int __init _tsens_tm_init(void)
1050{
1051 return platform_driver_register(&tsens_tm_driver);
1052}
1053module_init(_tsens_tm_init);
1054
1055static void __exit _tsens_tm_remove(void)
1056{
1057 platform_driver_unregister(&tsens_tm_driver);
1058}
1059module_exit(_tsens_tm_remove);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001060
1061MODULE_LICENSE("GPL v2");
1062MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
1063MODULE_VERSION("1.0");
1064MODULE_ALIAS("platform:tsens8960-tm");