blob: 67e0181f8e7d9e447f547e9017f08f15107dcbce [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2011-2012, 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 Mohanadossacd24262011-08-18 11:19:00 -0700246static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
247 enum thermal_device_mode *mode)
248{
249 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
250
251 if (!tm_sensor || !mode)
252 return -EINVAL;
253
254 *mode = tm_sensor->mode;
255
256 return 0;
257}
258
259/* Function to enable the mode.
260 * If the main sensor is disabled all the sensors are disable and
261 * the clock is disabled.
262 * If the main sensor is not enabled and sub sensor is enabled
263 * returns with an error stating the main sensor is not enabled.
264 */
265static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
266 enum thermal_device_mode mode)
267{
268 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
269 unsigned int reg, mask, i;
270
271 if (!tm_sensor)
272 return -EINVAL;
273
274 if (mode != tm_sensor->mode) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700275 reg = readl_relaxed(TSENS_CNTL_ADDR);
276
277 mask = 1 << (tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT);
278 if (mode == THERMAL_DEVICE_ENABLED) {
279 if ((mask != SENSOR0_EN) && !(reg & SENSOR0_EN)) {
280 pr_info("Main sensor not enabled\n");
281 return -EINVAL;
282 }
283 writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700284 if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700285 tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800286 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700287 reg |= mask | TSENS_8960_SLP_CLK_ENA
288 | TSENS_EN;
289 else
290 reg |= mask | TSENS_8660_SLP_CLK_ENA
291 | TSENS_EN;
292 tmdev->prev_reading_avail = false;
293 } else {
294 reg &= ~mask;
295 if (!(reg & SENSOR0_EN)) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800296 if (tmdev->hw_type == APQ_8064)
297 reg &= ~(TSENS_8064_SENSORS_EN |
298 TSENS_8960_SLP_CLK_ENA |
299 TSENS_EN);
300 else if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700301 tmdev->hw_type == MDM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700302 reg &= ~(SENSORS_EN |
303 TSENS_8960_SLP_CLK_ENA |
304 TSENS_EN);
305 else
306 reg &= ~(SENSORS_EN |
307 TSENS_8660_SLP_CLK_ENA |
308 TSENS_EN);
309
310 for (i = 1; i < tmdev->tsens_num_sensor; i++)
311 tmdev->sensor[i].mode = mode;
312
313 }
314 }
315 writel_relaxed(reg, TSENS_CNTL_ADDR);
316 }
317 tm_sensor->mode = mode;
318
319 return 0;
320}
321
322static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
323 int trip, enum thermal_trip_type *type)
324{
325 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
326
327 if (!tm_sensor || trip < 0 || !type)
328 return -EINVAL;
329
330 switch (trip) {
331 case TSENS_TRIP_STAGE3:
332 *type = THERMAL_TRIP_CRITICAL;
333 break;
334 case TSENS_TRIP_STAGE2:
335 *type = THERMAL_TRIP_CONFIGURABLE_HI;
336 break;
337 case TSENS_TRIP_STAGE1:
338 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
339 break;
340 case TSENS_TRIP_STAGE0:
341 *type = THERMAL_TRIP_CRITICAL_LOW;
342 break;
343 default:
344 return -EINVAL;
345 }
346
347 return 0;
348}
349
350static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
351 int trip, enum thermal_trip_activation_mode mode)
352{
353 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
354 unsigned int reg_cntl, reg_th, code, hi_code, lo_code, mask;
355
356 if (!tm_sensor || trip < 0)
357 return -EINVAL;
358
359 lo_code = TSENS_THRESHOLD_MIN_CODE;
360 hi_code = TSENS_THRESHOLD_MAX_CODE;
361
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800362 if (tmdev->hw_type == APQ_8064)
363 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
364 else
365 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
366
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700367 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
368 switch (trip) {
369 case TSENS_TRIP_STAGE3:
370 code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
371 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
372 mask = TSENS_MAX_STATUS_MASK;
373
374 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
375 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
376 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
377 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
378 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
379 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
380 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
381 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
382 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
383 break;
384 case TSENS_TRIP_STAGE2:
385 code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
386 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
387 mask = TSENS_UPPER_STATUS_CLR;
388
389 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
390 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
391 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
392 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
393 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
394 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
395 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
396 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
397 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
398 break;
399 case TSENS_TRIP_STAGE1:
400 code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
401 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
402 mask = TSENS_LOWER_STATUS_CLR;
403
404 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
405 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
406 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
407 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
408 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
409 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
410 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
411 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
412 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
413 break;
414 case TSENS_TRIP_STAGE0:
415 code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
416 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
417 mask = TSENS_MIN_STATUS_MASK;
418
419 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
420 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
421 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
422 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
423 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
424 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
425 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
426 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
427 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
428 break;
429 default:
430 return -EINVAL;
431 }
432
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800433 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) {
434 if (tmdev->hw_type == APQ_8064)
435 writel_relaxed(reg_cntl | mask, TSENS_8064_STATUS_CNTL);
436 else
437 writel_relaxed(reg_cntl | mask, TSENS_CNTL_ADDR);
438 } else {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700439 if (code < lo_code || code > hi_code) {
440 pr_info("%s with invalid code %x\n", __func__, code);
441 return -EINVAL;
442 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800443 if (tmdev->hw_type == APQ_8064)
444 writel_relaxed(reg_cntl & ~mask,
445 TSENS_8064_STATUS_CNTL);
446 else
447 writel_relaxed(reg_cntl & ~mask, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700448 }
449 mb();
450 return 0;
451}
452
453static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
454 int trip, unsigned long *temp)
455{
456 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
457 unsigned int reg;
458
459 if (!tm_sensor || trip < 0 || !temp)
460 return -EINVAL;
461
462 reg = readl_relaxed(TSENS_THRESHOLD_ADDR);
463 switch (trip) {
464 case TSENS_TRIP_STAGE3:
465 reg = (reg & TSENS_THRESHOLD_MAX_LIMIT_MASK)
466 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
467 break;
468 case TSENS_TRIP_STAGE2:
469 reg = (reg & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
470 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
471 break;
472 case TSENS_TRIP_STAGE1:
473 reg = (reg & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
474 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
475 break;
476 case TSENS_TRIP_STAGE0:
477 reg = (reg & TSENS_THRESHOLD_MIN_LIMIT_MASK)
478 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
479 break;
480 default:
481 return -EINVAL;
482 }
483
484 *temp = tsens_tz_code_to_degC(reg, tm_sensor->sensor_num);
485
486 return 0;
487}
488
489static int tsens_tz_get_crit_temp(struct thermal_zone_device *thermal,
490 unsigned long *temp)
491{
492 return tsens_tz_get_trip_temp(thermal, TSENS_TRIP_STAGE3, temp);
493}
494
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800495static int tsens_tz_notify(struct thermal_zone_device *thermal,
496 int count, enum thermal_trip_type type)
497{
498 /* TSENS driver does not shutdown the device.
499 All Thermal notification are sent to the
500 thermal daemon to take appropriate action */
501 return 1;
502}
503
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700504static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
505 int trip, long temp)
506{
507 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
508 unsigned int reg_th, reg_cntl;
509 int code, hi_code, lo_code, code_err_chk;
510
511 code_err_chk = code = tsens_tz_degC_to_code(temp,
512 tm_sensor->sensor_num);
513 if (!tm_sensor || trip < 0)
514 return -EINVAL;
515
516 lo_code = TSENS_THRESHOLD_MIN_CODE;
517 hi_code = TSENS_THRESHOLD_MAX_CODE;
518
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800519 if (tmdev->hw_type == APQ_8064)
520 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
521 else
522 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700523 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
524 switch (trip) {
525 case TSENS_TRIP_STAGE3:
526 code <<= TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
527 reg_th &= ~TSENS_THRESHOLD_MAX_LIMIT_MASK;
528
529 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
530 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
531 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
532 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
533 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
534 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
535 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
536 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
537 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
538 break;
539 case TSENS_TRIP_STAGE2:
540 code <<= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
541 reg_th &= ~TSENS_THRESHOLD_UPPER_LIMIT_MASK;
542
543 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
544 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
545 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
546 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
547 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
548 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
549 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
550 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
551 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
552 break;
553 case TSENS_TRIP_STAGE1:
554 code <<= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
555 reg_th &= ~TSENS_THRESHOLD_LOWER_LIMIT_MASK;
556
557 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
558 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
559 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
560 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
561 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
562 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
563 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
564 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
565 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
566 break;
567 case TSENS_TRIP_STAGE0:
568 code <<= TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
569 reg_th &= ~TSENS_THRESHOLD_MIN_LIMIT_MASK;
570
571 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
572 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
573 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
574 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
575 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
576 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
577 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
578 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
579 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
580 break;
581 default:
582 return -EINVAL;
583 }
584
585 if (code_err_chk < lo_code || code_err_chk > hi_code)
586 return -EINVAL;
587
588 writel_relaxed(reg_th | code, TSENS_THRESHOLD_ADDR);
589
590 return 0;
591}
592
593static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
594 .get_temp = tsens_tz_get_temp,
595 .get_mode = tsens_tz_get_mode,
596 .set_mode = tsens_tz_set_mode,
597 .get_trip_type = tsens_tz_get_trip_type,
598 .activate_trip_type = tsens_tz_activate_trip_type,
599 .get_trip_temp = tsens_tz_get_trip_temp,
600 .set_trip_temp = tsens_tz_set_trip_temp,
601 .get_crit_temp = tsens_tz_get_crit_temp,
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800602 .notify = tsens_tz_notify,
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700603};
604
605static void notify_uspace_tsens_fn(struct work_struct *work)
606{
607 struct tsens_tm_device_sensor *tm = container_of(work,
608 struct tsens_tm_device_sensor, work);
609
610 sysfs_notify(&tm->tz_dev->device.kobj,
611 NULL, "type");
612}
613
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700614static void tsens_scheduler_fn(struct work_struct *work)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700615{
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700616 struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
617 tsens_work);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700618 unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800619 unsigned int sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700620 bool upper_th_x, lower_th_x;
621 int adc_code;
622
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800623 if (tmdev->hw_type == APQ_8064) {
624 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
625 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
626 TSENS_UPPER_STATUS_CLR, TSENS_8064_STATUS_CNTL);
627 } else {
628 reg = readl_relaxed(TSENS_CNTL_ADDR);
629 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
630 TSENS_UPPER_STATUS_CLR, TSENS_CNTL_ADDR);
631 }
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700632
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700633 mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
634 threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
635 threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
636 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
637 threshold = (threshold & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
638 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800639 sensor = readl_relaxed(TSENS_CNTL_ADDR);
640 if (tmdev->hw_type == APQ_8064) {
641 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
642 sensor &= (uint32_t) TSENS_8064_SENSORS_EN;
643 } else {
644 reg = sensor;
645 sensor &= (uint32_t) SENSORS_EN;
646 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700647 sensor >>= TSENS_SENSOR0_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800648 sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700649 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800650 if (i == TSENS_8064_SEQ_SENSORS)
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800651 sensor_addr += TSENS_8064_S4_S5_OFFSET;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700652 if (sensor & TSENS_MASK1) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800653 code = readl_relaxed(sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700654 upper_th_x = code >= threshold;
655 lower_th_x = code <= threshold_low;
656 if (upper_th_x)
657 mask |= TSENS_UPPER_STATUS_CLR;
658 if (lower_th_x)
659 mask |= TSENS_LOWER_STATUS_CLR;
660 if (upper_th_x || lower_th_x) {
661 /* Notify user space */
662 schedule_work(&tm->sensor[i].work);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800663 adc_code = readl_relaxed(sensor_addr);
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700664 pr_debug("Trigger (%d degrees) for sensor %d\n",
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700665 tsens_tz_code_to_degC(adc_code, i), i);
666 }
667 }
668 sensor >>= 1;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800669 sensor_addr += TSENS_SENSOR_STATUS_SIZE;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700670 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800671 if (tmdev->hw_type == APQ_8064)
672 writel_relaxed(reg & mask, TSENS_8064_STATUS_CNTL);
673 else
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700674 writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
675 mb();
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700676}
677
678static irqreturn_t tsens_isr(int irq, void *data)
679{
680 schedule_work(&tmdev->tsens_work);
681
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700682 return IRQ_HANDLED;
683}
684
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700685#ifdef CONFIG_PM
686static int tsens_suspend(struct device *dev)
687{
688 int i = 0;
689
690 tmdev->pm_tsens_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
691 tmdev->pm_tsens_cntl = readl_relaxed(TSENS_CNTL_ADDR);
692 writel_relaxed(tmdev->pm_tsens_cntl &
693 ~(TSENS_8960_SLP_CLK_ENA | TSENS_EN), TSENS_CNTL_ADDR);
694 tmdev->prev_reading_avail = 0;
695 for (i = 0; i < tmdev->tsens_num_sensor; i++)
696 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
697 disable_irq_nosync(TSENS_UPPER_LOWER_INT);
698 mb();
699 return 0;
700}
701
702static int tsens_resume(struct device *dev)
703{
704 unsigned int reg_cntl = 0, reg_cfg = 0, reg_sensor_mask = 0;
705 unsigned int reg_status_cntl = 0, reg_thr_data = 0, i = 0;
706
707 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
708 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
709
710 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
711 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
712 (TSENS_MEASURE_PERIOD << 18) |
713 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
714 SENSORS_EN;
715 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
716 } else if (tmdev->hw_type == APQ_8064) {
717 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
718 (TSENS_MEASURE_PERIOD << 18) |
Siddartha Mohanadoss5a443502012-05-24 23:43:48 -0700719 (((1 << tmdev->tsens_num_sensor) - 1)
720 << TSENS_SENSOR0_SHIFT);
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700721 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
722 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
723 reg_status_cntl |= TSENS_MIN_STATUS_MASK |
724 TSENS_MAX_STATUS_MASK;
725 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
726 }
727
728 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
729 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
730 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
731 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
732
733 writel_relaxed((tmdev->pm_tsens_cntl & TSENS_CNTL_RESUME_MASK),
734 TSENS_CNTL_ADDR);
735 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
736 writel_relaxed(tmdev->pm_tsens_thr_data, TSENS_THRESHOLD_ADDR);
737 reg_thr_data = readl_relaxed(TSENS_THRESHOLD_ADDR);
738 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615)
739 reg_sensor_mask = ((reg_cntl & TSENS_8960_SENSOR_MASK)
740 >> TSENS_SENSOR0_SHIFT);
741 else {
742 reg_sensor_mask = ((reg_cntl & TSENS_8064_SENSOR_MASK)
743 >> TSENS_SENSOR0_SHIFT);
744 }
745
746 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
747 if (reg_sensor_mask & TSENS_MASK1)
748 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
749 reg_sensor_mask >>= 1;
750 }
751
752 enable_irq(TSENS_UPPER_LOWER_INT);
753 mb();
754 return 0;
755}
756
757static const struct dev_pm_ops tsens_pm_ops = {
758 .suspend = tsens_suspend,
759 .resume = tsens_resume,
760};
761#endif
762
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700763static void tsens_disable_mode(void)
764{
765 unsigned int reg_cntl = 0;
766
767 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700768 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800769 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700770 writel_relaxed(reg_cntl &
771 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
772 TSENS_SENSOR0_SHIFT) | TSENS_8960_SLP_CLK_ENA
773 | TSENS_EN), TSENS_CNTL_ADDR);
774 else if (tmdev->hw_type == MSM_8660)
775 writel_relaxed(reg_cntl &
776 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
777 TSENS_SENSOR0_SHIFT) | TSENS_8660_SLP_CLK_ENA
778 | TSENS_EN), TSENS_CNTL_ADDR);
779}
780
781static void tsens_hw_init(void)
782{
783 unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800784 unsigned int reg_status_cntl = 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700785
786 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
787 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
788
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700789 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615) {
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700790 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700791 (TSENS_MEASURE_PERIOD << 18) |
792 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
793 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700794 SENSORS_EN;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700795 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700796 reg_cntl |= TSENS_EN;
797 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700798
799 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
800 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
801 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
802 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
803 } else if (tmdev->hw_type == MSM_8660) {
804 reg_cntl |= TSENS_8660_SLP_CLK_ENA | TSENS_EN |
805 (TSENS_MEASURE_PERIOD << 16) |
806 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
807 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
808 (((1 << tmdev->tsens_num_sensor) - 1) <<
809 TSENS_SENSOR0_SHIFT);
810
811 /* set TSENS_CONFIG bits (bits 29:28 of TSENS_CNTL) to '01';
812 this setting found to be optimal. */
813 reg_cntl = (reg_cntl & ~TSENS_8660_CONFIG_MASK) |
814 (TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT);
815
816 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800817 } else if (tmdev->hw_type == APQ_8064) {
818 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
819 (TSENS_MEASURE_PERIOD << 18) |
Siddartha Mohanadoss5a443502012-05-24 23:43:48 -0700820 (((1 << tmdev->tsens_num_sensor) - 1)
821 << TSENS_SENSOR0_SHIFT);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800822 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
823 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
824 reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
825 TSENS_UPPER_STATUS_CLR |
826 TSENS_MIN_STATUS_MASK |
827 TSENS_MAX_STATUS_MASK;
828 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
829 reg_cntl |= TSENS_EN;
830 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
831
832 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
833 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
834 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
835 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700836 }
837
838 reg_thr |= (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) |
839 (TSENS_UPPER_LIMIT_TH << TSENS_THRESHOLD_UPPER_LIMIT_SHIFT) |
840 (TSENS_MIN_LIMIT_TH << TSENS_THRESHOLD_MIN_LIMIT_SHIFT) |
841 (TSENS_MAX_LIMIT_TH << TSENS_THRESHOLD_MAX_LIMIT_SHIFT);
842 writel_relaxed(reg_thr, TSENS_THRESHOLD_ADDR);
843}
844
845static int tsens_calib_sensors8660(void)
846{
847 uint32_t *main_sensor_addr, sensor_shift, red_sensor_shift;
848 uint32_t sensor_mask, red_sensor_mask;
849
850 main_sensor_addr = TSENS_8660_QFPROM_ADDR;
851 sensor_shift = TSENS_SENSOR_SHIFT;
852 red_sensor_shift = sensor_shift + TSENS_RED_SHIFT;
853 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
854 red_sensor_mask = TSENS_THRESHOLD_MAX_CODE << red_sensor_shift;
855 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
856 (readl_relaxed(main_sensor_addr) & sensor_mask)
857 >> sensor_shift;
858 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup =
859 (readl_relaxed(main_sensor_addr)
860 & red_sensor_mask) >> red_sensor_shift;
861 if (tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup)
862 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
863 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
864 if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700865 pr_err("QFPROM TSENS calibration data not present\n");
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700866 return -ENODEV;
867 }
868
869 tmdev->sensor[TSENS_MAIN_SENSOR].offset = tmdev->tsens_factor *
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800870 TSENS_CAL_DEGC -
871 tmdev->sensor[TSENS_MAIN_SENSOR].slope_mul_tsens_factor *
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700872 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800873
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700874 tmdev->prev_reading_avail = false;
875 INIT_WORK(&tmdev->sensor[TSENS_MAIN_SENSOR].work,
876 notify_uspace_tsens_fn);
877
878 return 0;
879}
880
881static int tsens_calib_sensors8960(void)
882{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800883 uint32_t i;
884 uint8_t *main_sensor_addr, *backup_sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700885 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800886 main_sensor_addr = TSENS_8960_QFPROM_ADDR0 + i;
887 backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 + i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700888
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800889 tmdev->sensor[i].calib_data = readb_relaxed(main_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700890 tmdev->sensor[i].calib_data_backup =
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800891 readb_relaxed(backup_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700892 if (tmdev->sensor[i].calib_data_backup)
893 tmdev->sensor[i].calib_data =
894 tmdev->sensor[i].calib_data_backup;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700895 if (!tmdev->sensor[i].calib_data) {
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700896 pr_err("QFPROM TSENS calibration data not present\n");
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700897 return -ENODEV;
898 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800899 tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
900 tmdev->tsens_factor)
901 - (tmdev->sensor[i].calib_data *
902 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700903 tmdev->prev_reading_avail = false;
904 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
905 }
906
907 return 0;
908}
909
910static int tsens_calib_sensors(void)
911{
Siddartha Mohanadoss73010e52011-10-31 11:23:18 -0700912 int rc = -ENODEV;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700913
914 if (tmdev->hw_type == MSM_8660)
915 rc = tsens_calib_sensors8660();
Siddartha Mohanadoss7e25dc12012-03-19 11:19:27 -0700916 else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MDM_9615 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800917 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700918 rc = tsens_calib_sensors8960();
919
920 return rc;
921}
922
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800923int msm_tsens_early_init(struct tsens_platform_data *pdata)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700924{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800925 int rc = 0, i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700926
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700927 if (!pdata) {
928 pr_err("No TSENS Platform data\n");
929 return -EINVAL;
930 }
931
932 tmdev = kzalloc(sizeof(struct tsens_tm_device) +
933 pdata->tsens_num_sensor *
934 sizeof(struct tsens_tm_device_sensor),
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800935 GFP_ATOMIC);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700936 if (tmdev == NULL) {
937 pr_err("%s: kzalloc() failed.\n", __func__);
938 return -ENOMEM;
939 }
940
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800941 for (i = 0; i < pdata->tsens_num_sensor; i++)
942 tmdev->sensor[i].slope_mul_tsens_factor = pdata->slope[i];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700943 tmdev->tsens_factor = pdata->tsens_factor;
944 tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
945 tmdev->hw_type = pdata->hw_type;
946
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700947 rc = tsens_calib_sensors();
948 if (rc < 0) {
949 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800950 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700951 return rc;
952 }
953
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800954 if (tmdev->hw_type == APQ_8064)
955 tsens_status_cntl_start = 0;
956 else
957 tsens_status_cntl_start = TSENS_STATUS_CNTL_OFFSET;
958
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700959 tsens_hw_init();
960
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800961 pr_debug("msm_tsens_early_init: done\n");
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800962
963 return rc;
964}
965
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -0700966static int __devinit tsens_tm_probe(struct platform_device *pdev)
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800967{
968 int rc, i;
969
970 if (!tmdev) {
971 pr_info("%s : TSENS early init not done.\n", __func__);
972 return -EFAULT;
973 }
974
975 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadoss4d94a442012-02-22 13:47:11 -0800976 char name[18];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700977 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
978 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
979 tmdev->sensor[i].sensor_num = i;
980 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
981 TSENS_TRIP_NUM, &tmdev->sensor[i],
982 &tsens_thermal_zone_ops, 0, 0, 0, 0);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800983 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700984 pr_err("%s: thermal_zone_device_register() failed.\n",
985 __func__);
986 rc = -ENODEV;
987 goto fail;
988 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700989 }
990
991 rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
992 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
993 if (rc < 0) {
994 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
995 for (i = 0; i < tmdev->tsens_num_sensor; i++)
996 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
997 goto fail;
998 }
Siddartha Mohanadoss7dc2eb02012-08-19 18:15:17 -0700999 INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001000
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -08001001 pr_debug("%s: OK\n", __func__);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001002 mb();
1003 return 0;
1004fail:
1005 tsens_disable_mode();
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001006 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -08001007 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001008 mb();
1009 return rc;
1010}
1011
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001012static int __devexit tsens_tm_remove(struct platform_device *pdev)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001013{
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001014 int i;
1015
1016 tsens_disable_mode();
1017 mb();
1018 free_irq(TSENS_UPPER_LOWER_INT, tmdev);
1019 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1020 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001021 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -08001022 tmdev = NULL;
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001023 return 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001024}
1025
Siddartha Mohanadoss48cad912012-04-05 21:29:54 -07001026static struct platform_driver tsens_tm_driver = {
1027 .probe = tsens_tm_probe,
1028 .remove = tsens_tm_remove,
1029 .driver = {
1030 .name = "tsens8960-tm",
1031 .owner = THIS_MODULE,
1032#ifdef CONFIG_PM
1033 .pm = &tsens_pm_ops,
1034#endif
1035 },
1036};
1037
1038static int __init _tsens_tm_init(void)
1039{
1040 return platform_driver_register(&tsens_tm_driver);
1041}
1042module_init(_tsens_tm_init);
1043
1044static void __exit _tsens_tm_remove(void)
1045{
1046 platform_driver_unregister(&tsens_tm_driver);
1047}
1048module_exit(_tsens_tm_remove);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -07001049
1050MODULE_LICENSE("GPL v2");
1051MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
1052MODULE_VERSION("1.0");
1053MODULE_ALIAS("platform:tsens8960-tm");