blob: 0e279b861d5737a6aafd539d8fd7abec2ba830be [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 Mohanadossacd24262011-08-18 11:19:00 -070027
28#include <mach/msm_iomap.h>
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -070029#include <mach/socinfo.h>
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070030
31/* Trips: from very hot to very cold */
32enum tsens_trip_type {
33 TSENS_TRIP_STAGE3 = 0,
34 TSENS_TRIP_STAGE2,
35 TSENS_TRIP_STAGE1,
36 TSENS_TRIP_STAGE0,
37 TSENS_TRIP_NUM,
38};
39
40/* MSM8960 TSENS register info */
41#define TSENS_CAL_DEGC 30
42#define TSENS_MAIN_SENSOR 0
43
44#define TSENS_8960_QFPROM_ADDR0 (MSM_QFPROM_BASE + 0x00000404)
Siddartha Mohanadoss7201a162011-10-18 19:39:49 -070045#define TSENS_8960_QFPROM_SPARE_ADDR0 (MSM_QFPROM_BASE + 0x00000414)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070046#define TSENS_8960_CONFIG 0x9b
47#define TSENS_8960_CONFIG_SHIFT 0
48#define TSENS_8960_CONFIG_MASK (0xf << TSENS_8960_CONFIG_SHIFT)
49#define TSENS_CNTL_ADDR (MSM_CLK_CTL_BASE + 0x00003620)
50#define TSENS_EN BIT(0)
51#define TSENS_SW_RST BIT(1)
52#define TSENS_ADC_CLK_SEL BIT(2)
53#define SENSOR0_EN BIT(3)
54#define SENSOR1_EN BIT(4)
55#define SENSOR2_EN BIT(5)
56#define SENSOR3_EN BIT(6)
57#define SENSOR4_EN BIT(7)
58#define SENSORS_EN (SENSOR0_EN | SENSOR1_EN | \
59 SENSOR2_EN | SENSOR3_EN | SENSOR4_EN)
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -080060#define TSENS_STATUS_CNTL_OFFSET 8
61#define TSENS_MIN_STATUS_MASK BIT((tsens_status_cntl_start))
62#define TSENS_LOWER_STATUS_CLR BIT((tsens_status_cntl_start + 1))
63#define TSENS_UPPER_STATUS_CLR BIT((tsens_status_cntl_start + 2))
64#define TSENS_MAX_STATUS_MASK BIT((tsens_status_cntl_start + 3))
65
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070066#define TSENS_MEASURE_PERIOD 4 /* 1 sec. default */
67#define TSENS_8960_SLP_CLK_ENA BIT(26)
68
69#define TSENS_THRESHOLD_ADDR (MSM_CLK_CTL_BASE + 0x00003624)
70#define TSENS_THRESHOLD_MAX_CODE 0xff
71#define TSENS_THRESHOLD_MIN_CODE 0
72#define TSENS_THRESHOLD_MAX_LIMIT_SHIFT 24
73#define TSENS_THRESHOLD_MIN_LIMIT_SHIFT 16
74#define TSENS_THRESHOLD_UPPER_LIMIT_SHIFT 8
75#define TSENS_THRESHOLD_LOWER_LIMIT_SHIFT 0
76#define TSENS_THRESHOLD_MAX_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
77 TSENS_THRESHOLD_MAX_LIMIT_SHIFT)
78#define TSENS_THRESHOLD_MIN_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
79 TSENS_THRESHOLD_MIN_LIMIT_SHIFT)
80#define TSENS_THRESHOLD_UPPER_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
81 TSENS_THRESHOLD_UPPER_LIMIT_SHIFT)
82#define TSENS_THRESHOLD_LOWER_LIMIT_MASK (TSENS_THRESHOLD_MAX_CODE << \
83 TSENS_THRESHOLD_LOWER_LIMIT_SHIFT)
84/* Initial temperature threshold values */
85#define TSENS_LOWER_LIMIT_TH 0x50
86#define TSENS_UPPER_LIMIT_TH 0xdf
Siddartha Mohanadossf34b4562012-01-10 15:11:28 -080087#define TSENS_MIN_LIMIT_TH 0x0
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070088#define TSENS_MAX_LIMIT_TH 0xff
89
90#define TSENS_S0_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003628)
91#define TSENS_STATUS_ADDR_OFFSET 2
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -080092#define TSENS_SENSOR_STATUS_SIZE 4
Siddartha Mohanadossacd24262011-08-18 11:19:00 -070093#define TSENS_INT_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x0000363c)
94
95#define TSENS_LOWER_INT_MASK BIT(1)
96#define TSENS_UPPER_INT_MASK BIT(2)
97#define TSENS_MAX_INT_MASK BIT(3)
98#define TSENS_TRDY_MASK BIT(7)
99
100#define TSENS_8960_CONFIG_ADDR (MSM_CLK_CTL_BASE + 0x00003640)
101#define TSENS_TRDY_RDY_MIN_TIME 1000
102#define TSENS_TRDY_RDY_MAX_TIME 1100
103#define TSENS_SENSOR_SHIFT 16
104#define TSENS_RED_SHIFT 8
105#define TSENS_8960_QFPROM_SHIFT 4
Siddartha Mohanadoss3e1ffc32011-11-30 17:10:44 -0800106#define TSENS_SENSOR_QFPROM_SHIFT 2
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700107#define TSENS_SENSOR0_SHIFT 3
108#define TSENS_MASK1 1
109
110#define TSENS_8660_QFPROM_ADDR (MSM_QFPROM_BASE + 0x000000bc)
111#define TSENS_8660_QFPROM_RED_TEMP_SENSOR0_SHIFT 24
112#define TSENS_8660_QFPROM_TEMP_SENSOR0_SHIFT 16
113#define TSENS_8660_QFPROM_TEMP_SENSOR0_MASK (255 \
114 << TSENS_8660_QFPROM_TEMP_SENSOR0_SHIFT)
115#define TSENS_8660_CONFIG 01
116#define TSENS_8660_CONFIG_SHIFT 28
117#define TSENS_8660_CONFIG_MASK (3 << TSENS_8660_CONFIG_SHIFT)
118#define TSENS_8660_SLP_CLK_ENA BIT(24)
119
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800120#define TSENS_8064_SENSOR5_EN BIT(8)
121#define TSENS_8064_SENSOR6_EN BIT(9)
122#define TSENS_8064_SENSOR7_EN BIT(10)
123#define TSENS_8064_SENSOR8_EN BIT(11)
124#define TSENS_8064_SENSOR9_EN BIT(12)
125#define TSENS_8064_SENSOR10_EN BIT(13)
126#define TSENS_8064_SENSORS_EN (SENSORS_EN | \
127 TSENS_8064_SENSOR5_EN | \
128 TSENS_8064_SENSOR6_EN | \
129 TSENS_8064_SENSOR7_EN | \
130 TSENS_8064_SENSOR8_EN | \
131 TSENS_8064_SENSOR9_EN | \
132 TSENS_8064_SENSOR10_EN)
133#define TSENS_8064_STATUS_CNTL (MSM_CLK_CTL_BASE + 0x00003660)
134#define TSENS_8064_S5_STATUS_ADDR (MSM_CLK_CTL_BASE + 0x00003664)
135#define TSENS_8064_SEQ_SENSORS 5
136#define TSENS_8064_S4_S5_OFFSET 40
137
138static int tsens_status_cntl_start;
139
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700140struct tsens_tm_device_sensor {
141 struct thermal_zone_device *tz_dev;
142 enum thermal_device_mode mode;
143 unsigned int sensor_num;
144 struct work_struct work;
145 int offset;
146 int calib_data;
147 int calib_data_backup;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800148 uint32_t slope_mul_tsens_factor;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700149};
150
151struct tsens_tm_device {
152 bool prev_reading_avail;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700153 int tsens_factor;
154 uint32_t tsens_num_sensor;
155 enum platform_type hw_type;
156 struct tsens_tm_device_sensor sensor[0];
157};
158
159struct tsens_tm_device *tmdev;
160
161/* Temperature on y axis and ADC-code on x-axis */
162static int tsens_tz_code_to_degC(int adc_code, int sensor_num)
163{
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800164 int degcbeforefactor, degc;
165 degcbeforefactor = (adc_code *
166 tmdev->sensor[sensor_num].slope_mul_tsens_factor
167 + tmdev->sensor[sensor_num].offset);
168
169 if (degcbeforefactor == 0)
170 degc = degcbeforefactor;
171 else if (degcbeforefactor > 0)
172 degc = (degcbeforefactor + tmdev->tsens_factor/2)
173 / tmdev->tsens_factor;
174 else
175 degc = (degcbeforefactor - tmdev->tsens_factor/2)
176 / tmdev->tsens_factor;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800177 return degc;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700178}
179
180static int tsens_tz_degC_to_code(int degC, int sensor_num)
181{
182 int code = (degC * tmdev->tsens_factor -
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800183 tmdev->sensor[sensor_num].offset
184 + tmdev->sensor[sensor_num].slope_mul_tsens_factor/2)
185 / tmdev->sensor[sensor_num].slope_mul_tsens_factor;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700186
187 if (code > TSENS_THRESHOLD_MAX_CODE)
188 code = TSENS_THRESHOLD_MAX_CODE;
189 else if (code < TSENS_THRESHOLD_MIN_CODE)
190 code = TSENS_THRESHOLD_MIN_CODE;
191 return code;
192}
193
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800194static void tsens8960_get_temp(int sensor_num, unsigned long *temp)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700195{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800196 unsigned int code, offset = 0, sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700197
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700198 if (!tmdev->prev_reading_avail) {
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800199 while (!(readl_relaxed(TSENS_INT_STATUS_ADDR)
200 & TSENS_TRDY_MASK))
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700201 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
202 TSENS_TRDY_RDY_MAX_TIME);
203 tmdev->prev_reading_avail = true;
204 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800205
206 sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
207 if (tmdev->hw_type == APQ_8064 &&
208 sensor_num >= TSENS_8064_SEQ_SENSORS)
209 offset = TSENS_8064_S4_S5_OFFSET;
210 code = readl_relaxed(sensor_addr + offset +
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800211 (sensor_num << TSENS_STATUS_ADDR_OFFSET));
212 *temp = tsens_tz_code_to_degC(code, sensor_num);
213}
214
215static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
216 unsigned long *temp)
217{
218 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
219
220 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
221 return -EINVAL;
222
223 tsens8960_get_temp(tm_sensor->sensor_num, temp);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700224
225 return 0;
226}
227
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800228int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
229{
230 if (!tmdev)
231 return -ENODEV;
232
233 tsens8960_get_temp(device->sensor_num, temp);
234
235 return 0;
236}
237EXPORT_SYMBOL(tsens_get_temp);
238
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700239static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
240 enum thermal_device_mode *mode)
241{
242 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
243
244 if (!tm_sensor || !mode)
245 return -EINVAL;
246
247 *mode = tm_sensor->mode;
248
249 return 0;
250}
251
252/* Function to enable the mode.
253 * If the main sensor is disabled all the sensors are disable and
254 * the clock is disabled.
255 * If the main sensor is not enabled and sub sensor is enabled
256 * returns with an error stating the main sensor is not enabled.
257 */
258static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
259 enum thermal_device_mode mode)
260{
261 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
262 unsigned int reg, mask, i;
263
264 if (!tm_sensor)
265 return -EINVAL;
266
267 if (mode != tm_sensor->mode) {
268 pr_info("%s: mode: %d --> %d\n", __func__, tm_sensor->mode,
269 mode);
270
271 reg = readl_relaxed(TSENS_CNTL_ADDR);
272
273 mask = 1 << (tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT);
274 if (mode == THERMAL_DEVICE_ENABLED) {
275 if ((mask != SENSOR0_EN) && !(reg & SENSOR0_EN)) {
276 pr_info("Main sensor not enabled\n");
277 return -EINVAL;
278 }
279 writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700280 if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800281 tmdev->hw_type == MSM_9615 ||
282 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700283 reg |= mask | TSENS_8960_SLP_CLK_ENA
284 | TSENS_EN;
285 else
286 reg |= mask | TSENS_8660_SLP_CLK_ENA
287 | TSENS_EN;
288 tmdev->prev_reading_avail = false;
289 } else {
290 reg &= ~mask;
291 if (!(reg & SENSOR0_EN)) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800292 if (tmdev->hw_type == APQ_8064)
293 reg &= ~(TSENS_8064_SENSORS_EN |
294 TSENS_8960_SLP_CLK_ENA |
295 TSENS_EN);
296 else if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700297 tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700298 reg &= ~(SENSORS_EN |
299 TSENS_8960_SLP_CLK_ENA |
300 TSENS_EN);
301 else
302 reg &= ~(SENSORS_EN |
303 TSENS_8660_SLP_CLK_ENA |
304 TSENS_EN);
305
306 for (i = 1; i < tmdev->tsens_num_sensor; i++)
307 tmdev->sensor[i].mode = mode;
308
309 }
310 }
311 writel_relaxed(reg, TSENS_CNTL_ADDR);
312 }
313 tm_sensor->mode = mode;
314
315 return 0;
316}
317
318static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
319 int trip, enum thermal_trip_type *type)
320{
321 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
322
323 if (!tm_sensor || trip < 0 || !type)
324 return -EINVAL;
325
326 switch (trip) {
327 case TSENS_TRIP_STAGE3:
328 *type = THERMAL_TRIP_CRITICAL;
329 break;
330 case TSENS_TRIP_STAGE2:
331 *type = THERMAL_TRIP_CONFIGURABLE_HI;
332 break;
333 case TSENS_TRIP_STAGE1:
334 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
335 break;
336 case TSENS_TRIP_STAGE0:
337 *type = THERMAL_TRIP_CRITICAL_LOW;
338 break;
339 default:
340 return -EINVAL;
341 }
342
343 return 0;
344}
345
346static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
347 int trip, enum thermal_trip_activation_mode mode)
348{
349 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
350 unsigned int reg_cntl, reg_th, code, hi_code, lo_code, mask;
351
352 if (!tm_sensor || trip < 0)
353 return -EINVAL;
354
355 lo_code = TSENS_THRESHOLD_MIN_CODE;
356 hi_code = TSENS_THRESHOLD_MAX_CODE;
357
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800358 if (tmdev->hw_type == APQ_8064)
359 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
360 else
361 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
362
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700363 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
364 switch (trip) {
365 case TSENS_TRIP_STAGE3:
366 code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
367 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
368 mask = TSENS_MAX_STATUS_MASK;
369
370 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
371 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
372 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
373 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
374 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
375 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
376 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
377 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
378 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
379 break;
380 case TSENS_TRIP_STAGE2:
381 code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
382 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
383 mask = TSENS_UPPER_STATUS_CLR;
384
385 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
386 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
387 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
388 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_STAGE1:
396 code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
397 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
398 mask = TSENS_LOWER_STATUS_CLR;
399
400 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
401 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
402 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
403 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
404 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
405 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
406 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
407 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
408 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
409 break;
410 case TSENS_TRIP_STAGE0:
411 code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
412 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
413 mask = TSENS_MIN_STATUS_MASK;
414
415 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
416 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
417 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
418 else 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 default:
426 return -EINVAL;
427 }
428
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800429 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) {
430 if (tmdev->hw_type == APQ_8064)
431 writel_relaxed(reg_cntl | mask, TSENS_8064_STATUS_CNTL);
432 else
433 writel_relaxed(reg_cntl | mask, TSENS_CNTL_ADDR);
434 } else {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700435 if (code < lo_code || code > hi_code) {
436 pr_info("%s with invalid code %x\n", __func__, code);
437 return -EINVAL;
438 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800439 if (tmdev->hw_type == APQ_8064)
440 writel_relaxed(reg_cntl & ~mask,
441 TSENS_8064_STATUS_CNTL);
442 else
443 writel_relaxed(reg_cntl & ~mask, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700444 }
445 mb();
446 return 0;
447}
448
449static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
450 int trip, unsigned long *temp)
451{
452 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
453 unsigned int reg;
454
455 if (!tm_sensor || trip < 0 || !temp)
456 return -EINVAL;
457
458 reg = readl_relaxed(TSENS_THRESHOLD_ADDR);
459 switch (trip) {
460 case TSENS_TRIP_STAGE3:
461 reg = (reg & TSENS_THRESHOLD_MAX_LIMIT_MASK)
462 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
463 break;
464 case TSENS_TRIP_STAGE2:
465 reg = (reg & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
466 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
467 break;
468 case TSENS_TRIP_STAGE1:
469 reg = (reg & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
470 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
471 break;
472 case TSENS_TRIP_STAGE0:
473 reg = (reg & TSENS_THRESHOLD_MIN_LIMIT_MASK)
474 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
475 break;
476 default:
477 return -EINVAL;
478 }
479
480 *temp = tsens_tz_code_to_degC(reg, tm_sensor->sensor_num);
481
482 return 0;
483}
484
485static int tsens_tz_get_crit_temp(struct thermal_zone_device *thermal,
486 unsigned long *temp)
487{
488 return tsens_tz_get_trip_temp(thermal, TSENS_TRIP_STAGE3, temp);
489}
490
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800491static int tsens_tz_notify(struct thermal_zone_device *thermal,
492 int count, enum thermal_trip_type type)
493{
494 /* TSENS driver does not shutdown the device.
495 All Thermal notification are sent to the
496 thermal daemon to take appropriate action */
497 return 1;
498}
499
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700500static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
501 int trip, long temp)
502{
503 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
504 unsigned int reg_th, reg_cntl;
505 int code, hi_code, lo_code, code_err_chk;
506
507 code_err_chk = code = tsens_tz_degC_to_code(temp,
508 tm_sensor->sensor_num);
509 if (!tm_sensor || trip < 0)
510 return -EINVAL;
511
512 lo_code = TSENS_THRESHOLD_MIN_CODE;
513 hi_code = TSENS_THRESHOLD_MAX_CODE;
514
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800515 if (tmdev->hw_type == APQ_8064)
516 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
517 else
518 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700519 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
520 switch (trip) {
521 case TSENS_TRIP_STAGE3:
522 code <<= TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
523 reg_th &= ~TSENS_THRESHOLD_MAX_LIMIT_MASK;
524
525 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
526 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
527 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
528 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
529 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
530 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
531 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
532 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
533 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
534 break;
535 case TSENS_TRIP_STAGE2:
536 code <<= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
537 reg_th &= ~TSENS_THRESHOLD_UPPER_LIMIT_MASK;
538
539 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
540 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
541 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
542 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
543 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
544 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
545 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
546 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
547 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
548 break;
549 case TSENS_TRIP_STAGE1:
550 code <<= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
551 reg_th &= ~TSENS_THRESHOLD_LOWER_LIMIT_MASK;
552
553 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
554 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
555 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
556 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
557 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
558 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
559 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
560 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
561 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
562 break;
563 case TSENS_TRIP_STAGE0:
564 code <<= TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
565 reg_th &= ~TSENS_THRESHOLD_MIN_LIMIT_MASK;
566
567 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
568 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
569 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
570 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
571 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
572 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
573 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
574 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
575 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
576 break;
577 default:
578 return -EINVAL;
579 }
580
581 if (code_err_chk < lo_code || code_err_chk > hi_code)
582 return -EINVAL;
583
584 writel_relaxed(reg_th | code, TSENS_THRESHOLD_ADDR);
585
586 return 0;
587}
588
589static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
590 .get_temp = tsens_tz_get_temp,
591 .get_mode = tsens_tz_get_mode,
592 .set_mode = tsens_tz_set_mode,
593 .get_trip_type = tsens_tz_get_trip_type,
594 .activate_trip_type = tsens_tz_activate_trip_type,
595 .get_trip_temp = tsens_tz_get_trip_temp,
596 .set_trip_temp = tsens_tz_set_trip_temp,
597 .get_crit_temp = tsens_tz_get_crit_temp,
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800598 .notify = tsens_tz_notify,
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700599};
600
601static void notify_uspace_tsens_fn(struct work_struct *work)
602{
603 struct tsens_tm_device_sensor *tm = container_of(work,
604 struct tsens_tm_device_sensor, work);
605
606 sysfs_notify(&tm->tz_dev->device.kobj,
607 NULL, "type");
608}
609
610static irqreturn_t tsens_isr(int irq, void *data)
611{
612 struct tsens_tm_device *tm = data;
613 unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800614 unsigned int sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700615 bool upper_th_x, lower_th_x;
616 int adc_code;
617
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800618 if (tmdev->hw_type == APQ_8064) {
619 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
620 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
621 TSENS_UPPER_STATUS_CLR, TSENS_8064_STATUS_CNTL);
622 } else {
623 reg = readl_relaxed(TSENS_CNTL_ADDR);
624 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
625 TSENS_UPPER_STATUS_CLR, TSENS_CNTL_ADDR);
626 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700627 mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
628 threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
629 threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
630 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
631 threshold = (threshold & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
632 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800633 sensor = readl_relaxed(TSENS_CNTL_ADDR);
634 if (tmdev->hw_type == APQ_8064) {
635 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
636 sensor &= (uint32_t) TSENS_8064_SENSORS_EN;
637 } else {
638 reg = sensor;
639 sensor &= (uint32_t) SENSORS_EN;
640 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700641 sensor >>= TSENS_SENSOR0_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800642 sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700643 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800644 if (i == TSENS_8064_SEQ_SENSORS)
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800645 sensor_addr += TSENS_8064_S4_S5_OFFSET;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700646 if (sensor & TSENS_MASK1) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800647 code = readl_relaxed(sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700648 upper_th_x = code >= threshold;
649 lower_th_x = code <= threshold_low;
650 if (upper_th_x)
651 mask |= TSENS_UPPER_STATUS_CLR;
652 if (lower_th_x)
653 mask |= TSENS_LOWER_STATUS_CLR;
654 if (upper_th_x || lower_th_x) {
655 /* Notify user space */
656 schedule_work(&tm->sensor[i].work);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800657 adc_code = readl_relaxed(sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700658 pr_info("\nTrip point triggered by "
659 "current temperature (%d degrees) "
660 "measured by Temperature-Sensor %d\n",
661 tsens_tz_code_to_degC(adc_code, i), i);
662 }
663 }
664 sensor >>= 1;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800665 sensor_addr += TSENS_SENSOR_STATUS_SIZE;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700666 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800667 if (tmdev->hw_type == APQ_8064)
668 writel_relaxed(reg & mask, TSENS_8064_STATUS_CNTL);
669 else
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700670 writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
671 mb();
672 return IRQ_HANDLED;
673}
674
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800675static void tsens8960_sensor_mode_init(void)
676{
677 unsigned int reg_cntl = 0;
678
679 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
680 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
681 tmdev->hw_type == APQ_8064) {
682 writel_relaxed(reg_cntl &
683 ~((((1 << tmdev->tsens_num_sensor) - 1) >> 1)
684 << (TSENS_SENSOR0_SHIFT + 1)), TSENS_CNTL_ADDR);
685 tmdev->sensor[TSENS_MAIN_SENSOR].mode = THERMAL_DEVICE_ENABLED;
686 }
687}
688
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700689static void tsens_disable_mode(void)
690{
691 unsigned int reg_cntl = 0;
692
693 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800694 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
695 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700696 writel_relaxed(reg_cntl &
697 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
698 TSENS_SENSOR0_SHIFT) | TSENS_8960_SLP_CLK_ENA
699 | TSENS_EN), TSENS_CNTL_ADDR);
700 else if (tmdev->hw_type == MSM_8660)
701 writel_relaxed(reg_cntl &
702 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
703 TSENS_SENSOR0_SHIFT) | TSENS_8660_SLP_CLK_ENA
704 | TSENS_EN), TSENS_CNTL_ADDR);
705}
706
707static void tsens_hw_init(void)
708{
709 unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800710 unsigned int reg_status_cntl = 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700711
712 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
713 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
714
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700715 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615) {
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700716 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700717 (TSENS_MEASURE_PERIOD << 18) |
718 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
719 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
720 (((1 << tmdev->tsens_num_sensor) - 1) <<
721 TSENS_SENSOR0_SHIFT);
722 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700723 reg_cntl |= TSENS_EN;
724 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700725
726 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
727 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
728 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
729 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
730 } else if (tmdev->hw_type == MSM_8660) {
731 reg_cntl |= TSENS_8660_SLP_CLK_ENA | TSENS_EN |
732 (TSENS_MEASURE_PERIOD << 16) |
733 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
734 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
735 (((1 << tmdev->tsens_num_sensor) - 1) <<
736 TSENS_SENSOR0_SHIFT);
737
738 /* set TSENS_CONFIG bits (bits 29:28 of TSENS_CNTL) to '01';
739 this setting found to be optimal. */
740 reg_cntl = (reg_cntl & ~TSENS_8660_CONFIG_MASK) |
741 (TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT);
742
743 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800744 } else if (tmdev->hw_type == APQ_8064) {
745 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
746 (TSENS_MEASURE_PERIOD << 18) |
747 (((1 << tmdev->tsens_num_sensor) - 1) <<
748 TSENS_SENSOR0_SHIFT);
749 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
750 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
751 reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
752 TSENS_UPPER_STATUS_CLR |
753 TSENS_MIN_STATUS_MASK |
754 TSENS_MAX_STATUS_MASK;
755 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
756 reg_cntl |= TSENS_EN;
757 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
758
759 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
760 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
761 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
762 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700763 }
764
765 reg_thr |= (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) |
766 (TSENS_UPPER_LIMIT_TH << TSENS_THRESHOLD_UPPER_LIMIT_SHIFT) |
767 (TSENS_MIN_LIMIT_TH << TSENS_THRESHOLD_MIN_LIMIT_SHIFT) |
768 (TSENS_MAX_LIMIT_TH << TSENS_THRESHOLD_MAX_LIMIT_SHIFT);
769 writel_relaxed(reg_thr, TSENS_THRESHOLD_ADDR);
770}
771
772static int tsens_calib_sensors8660(void)
773{
774 uint32_t *main_sensor_addr, sensor_shift, red_sensor_shift;
775 uint32_t sensor_mask, red_sensor_mask;
776
777 main_sensor_addr = TSENS_8660_QFPROM_ADDR;
778 sensor_shift = TSENS_SENSOR_SHIFT;
779 red_sensor_shift = sensor_shift + TSENS_RED_SHIFT;
780 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
781 red_sensor_mask = TSENS_THRESHOLD_MAX_CODE << red_sensor_shift;
782 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
783 (readl_relaxed(main_sensor_addr) & sensor_mask)
784 >> sensor_shift;
785 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup =
786 (readl_relaxed(main_sensor_addr)
787 & red_sensor_mask) >> red_sensor_shift;
788 if (tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup)
789 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
790 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
791 if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
792 pr_err("%s: No temperature sensor data for calibration"
793 " in QFPROM!\n", __func__);
794 return -ENODEV;
795 }
796
797 tmdev->sensor[TSENS_MAIN_SENSOR].offset = tmdev->tsens_factor *
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800798 TSENS_CAL_DEGC -
799 tmdev->sensor[TSENS_MAIN_SENSOR].slope_mul_tsens_factor *
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700800 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800801
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700802 tmdev->prev_reading_avail = false;
803 INIT_WORK(&tmdev->sensor[TSENS_MAIN_SENSOR].work,
804 notify_uspace_tsens_fn);
805
806 return 0;
807}
808
809static int tsens_calib_sensors8960(void)
810{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800811 uint32_t i;
812 uint8_t *main_sensor_addr, *backup_sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700813 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800814 main_sensor_addr = TSENS_8960_QFPROM_ADDR0 + i;
815 backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 + i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700816
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800817 tmdev->sensor[i].calib_data = readb_relaxed(main_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700818 tmdev->sensor[i].calib_data_backup =
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800819 readb_relaxed(backup_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700820 if (tmdev->sensor[i].calib_data_backup)
821 tmdev->sensor[i].calib_data =
822 tmdev->sensor[i].calib_data_backup;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700823 if (!tmdev->sensor[i].calib_data) {
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800824 WARN(1, "%s: No temperature sensor:%d data for"
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700825 " calibration in QFPROM!\n", __func__, i);
826 return -ENODEV;
827 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800828 tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
829 tmdev->tsens_factor)
830 - (tmdev->sensor[i].calib_data *
831 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700832 tmdev->prev_reading_avail = false;
833 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
834 }
835
836 return 0;
837}
838
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700839static int tsens_check_version_support(void)
840{
841 int rc = 0;
842
843 if (tmdev->hw_type == MSM_8960)
844 if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
845 rc = -ENODEV;
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700846
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700847 return rc;
848}
849
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700850static int tsens_calib_sensors(void)
851{
Siddartha Mohanadoss73010e52011-10-31 11:23:18 -0700852 int rc = -ENODEV;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700853
854 if (tmdev->hw_type == MSM_8660)
855 rc = tsens_calib_sensors8660();
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800856 else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
857 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700858 rc = tsens_calib_sensors8960();
859
860 return rc;
861}
862
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800863int msm_tsens_early_init(struct tsens_platform_data *pdata)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700864{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800865 int rc = 0, i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700866
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700867 if (!pdata) {
868 pr_err("No TSENS Platform data\n");
869 return -EINVAL;
870 }
871
872 tmdev = kzalloc(sizeof(struct tsens_tm_device) +
873 pdata->tsens_num_sensor *
874 sizeof(struct tsens_tm_device_sensor),
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800875 GFP_ATOMIC);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700876 if (tmdev == NULL) {
877 pr_err("%s: kzalloc() failed.\n", __func__);
878 return -ENOMEM;
879 }
880
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800881 for (i = 0; i < pdata->tsens_num_sensor; i++)
882 tmdev->sensor[i].slope_mul_tsens_factor = pdata->slope[i];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700883 tmdev->tsens_factor = pdata->tsens_factor;
884 tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
885 tmdev->hw_type = pdata->hw_type;
886
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700887 rc = tsens_check_version_support();
888 if (rc < 0) {
889 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800890 tmdev = NULL;
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700891 return rc;
892 }
893
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700894 rc = tsens_calib_sensors();
895 if (rc < 0) {
896 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800897 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700898 return rc;
899 }
900
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800901 if (tmdev->hw_type == APQ_8064)
902 tsens_status_cntl_start = 0;
903 else
904 tsens_status_cntl_start = TSENS_STATUS_CNTL_OFFSET;
905
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700906 tsens_hw_init();
907
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800908 pr_debug("msm_tsens_early_init: done\n");
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800909
910 return rc;
911}
912
913static int __init tsens_tm_init(void)
914{
915 int rc, i;
916
917 if (!tmdev) {
918 pr_info("%s : TSENS early init not done.\n", __func__);
919 return -EFAULT;
920 }
921
922 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700923 char name[17];
924 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
925 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
926 tmdev->sensor[i].sensor_num = i;
927 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
928 TSENS_TRIP_NUM, &tmdev->sensor[i],
929 &tsens_thermal_zone_ops, 0, 0, 0, 0);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800930 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700931 pr_err("%s: thermal_zone_device_register() failed.\n",
932 __func__);
933 rc = -ENODEV;
934 goto fail;
935 }
936 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
937 }
938
Siddartha Mohanadossc0d64ce2012-02-17 09:23:16 -0800939 tsens8960_sensor_mode_init();
940
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700941 rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
942 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
943 if (rc < 0) {
944 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
945 for (i = 0; i < tmdev->tsens_num_sensor; i++)
946 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
947 goto fail;
948 }
949
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800950 pr_debug("%s: OK\n", __func__);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700951 mb();
952 return 0;
953fail:
954 tsens_disable_mode();
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700955 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800956 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700957 mb();
958 return rc;
959}
960
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800961static void __exit tsens_tm_remove(void)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700962{
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700963 int i;
964
965 tsens_disable_mode();
966 mb();
967 free_irq(TSENS_UPPER_LOWER_INT, tmdev);
968 for (i = 0; i < tmdev->tsens_num_sensor; i++)
969 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700970 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800971 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700972}
973
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800974module_init(tsens_tm_init);
975module_exit(tsens_tm_remove);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700976
977MODULE_LICENSE("GPL v2");
978MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
979MODULE_VERSION("1.0");
980MODULE_ALIAS("platform:tsens8960-tm");