blob: 12edb3e418bbd253fb6c2222c9e967e1c77060b7 [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 Mohanadosscaeaa922012-02-07 16:41:38 -0800164 int degc;
165 degc = (adc_code * tmdev->sensor[sensor_num].slope_mul_tsens_factor
166 + tmdev->sensor[sensor_num].offset)
167 / tmdev->tsens_factor;
168 return degc;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700169}
170
171static int tsens_tz_degC_to_code(int degC, int sensor_num)
172{
173 int code = (degC * tmdev->tsens_factor -
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800174 tmdev->sensor[sensor_num].offset)
175 / tmdev->sensor[sensor_num].slope_mul_tsens_factor;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700176
177 if (code > TSENS_THRESHOLD_MAX_CODE)
178 code = TSENS_THRESHOLD_MAX_CODE;
179 else if (code < TSENS_THRESHOLD_MIN_CODE)
180 code = TSENS_THRESHOLD_MIN_CODE;
181 return code;
182}
183
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800184static void tsens8960_get_temp(int sensor_num, unsigned long *temp)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700185{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800186 unsigned int code, offset = 0, sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700187
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700188 if (!tmdev->prev_reading_avail) {
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800189 while (!(readl_relaxed(TSENS_INT_STATUS_ADDR)
190 & TSENS_TRDY_MASK))
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700191 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
192 TSENS_TRDY_RDY_MAX_TIME);
193 tmdev->prev_reading_avail = true;
194 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800195
196 sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
197 if (tmdev->hw_type == APQ_8064 &&
198 sensor_num >= TSENS_8064_SEQ_SENSORS)
199 offset = TSENS_8064_S4_S5_OFFSET;
200 code = readl_relaxed(sensor_addr + offset +
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800201 (sensor_num << TSENS_STATUS_ADDR_OFFSET));
202 *temp = tsens_tz_code_to_degC(code, sensor_num);
203}
204
205static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
206 unsigned long *temp)
207{
208 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
209
210 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
211 return -EINVAL;
212
213 tsens8960_get_temp(tm_sensor->sensor_num, temp);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700214
215 return 0;
216}
217
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800218int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
219{
220 if (!tmdev)
221 return -ENODEV;
222
223 tsens8960_get_temp(device->sensor_num, temp);
224
225 return 0;
226}
227EXPORT_SYMBOL(tsens_get_temp);
228
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700229static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
230 enum thermal_device_mode *mode)
231{
232 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
233
234 if (!tm_sensor || !mode)
235 return -EINVAL;
236
237 *mode = tm_sensor->mode;
238
239 return 0;
240}
241
242/* Function to enable the mode.
243 * If the main sensor is disabled all the sensors are disable and
244 * the clock is disabled.
245 * If the main sensor is not enabled and sub sensor is enabled
246 * returns with an error stating the main sensor is not enabled.
247 */
248static int tsens_tz_set_mode(struct thermal_zone_device *thermal,
249 enum thermal_device_mode mode)
250{
251 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
252 unsigned int reg, mask, i;
253
254 if (!tm_sensor)
255 return -EINVAL;
256
257 if (mode != tm_sensor->mode) {
258 pr_info("%s: mode: %d --> %d\n", __func__, tm_sensor->mode,
259 mode);
260
261 reg = readl_relaxed(TSENS_CNTL_ADDR);
262
263 mask = 1 << (tm_sensor->sensor_num + TSENS_SENSOR0_SHIFT);
264 if (mode == THERMAL_DEVICE_ENABLED) {
265 if ((mask != SENSOR0_EN) && !(reg & SENSOR0_EN)) {
266 pr_info("Main sensor not enabled\n");
267 return -EINVAL;
268 }
269 writel_relaxed(reg | TSENS_SW_RST, TSENS_CNTL_ADDR);
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700270 if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800271 tmdev->hw_type == MSM_9615 ||
272 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700273 reg |= mask | TSENS_8960_SLP_CLK_ENA
274 | TSENS_EN;
275 else
276 reg |= mask | TSENS_8660_SLP_CLK_ENA
277 | TSENS_EN;
278 tmdev->prev_reading_avail = false;
279 } else {
280 reg &= ~mask;
281 if (!(reg & SENSOR0_EN)) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800282 if (tmdev->hw_type == APQ_8064)
283 reg &= ~(TSENS_8064_SENSORS_EN |
284 TSENS_8960_SLP_CLK_ENA |
285 TSENS_EN);
286 else if (tmdev->hw_type == MSM_8960 ||
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700287 tmdev->hw_type == MSM_9615)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700288 reg &= ~(SENSORS_EN |
289 TSENS_8960_SLP_CLK_ENA |
290 TSENS_EN);
291 else
292 reg &= ~(SENSORS_EN |
293 TSENS_8660_SLP_CLK_ENA |
294 TSENS_EN);
295
296 for (i = 1; i < tmdev->tsens_num_sensor; i++)
297 tmdev->sensor[i].mode = mode;
298
299 }
300 }
301 writel_relaxed(reg, TSENS_CNTL_ADDR);
302 }
303 tm_sensor->mode = mode;
304
305 return 0;
306}
307
308static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
309 int trip, enum thermal_trip_type *type)
310{
311 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
312
313 if (!tm_sensor || trip < 0 || !type)
314 return -EINVAL;
315
316 switch (trip) {
317 case TSENS_TRIP_STAGE3:
318 *type = THERMAL_TRIP_CRITICAL;
319 break;
320 case TSENS_TRIP_STAGE2:
321 *type = THERMAL_TRIP_CONFIGURABLE_HI;
322 break;
323 case TSENS_TRIP_STAGE1:
324 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
325 break;
326 case TSENS_TRIP_STAGE0:
327 *type = THERMAL_TRIP_CRITICAL_LOW;
328 break;
329 default:
330 return -EINVAL;
331 }
332
333 return 0;
334}
335
336static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
337 int trip, enum thermal_trip_activation_mode mode)
338{
339 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
340 unsigned int reg_cntl, reg_th, code, hi_code, lo_code, mask;
341
342 if (!tm_sensor || trip < 0)
343 return -EINVAL;
344
345 lo_code = TSENS_THRESHOLD_MIN_CODE;
346 hi_code = TSENS_THRESHOLD_MAX_CODE;
347
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800348 if (tmdev->hw_type == APQ_8064)
349 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
350 else
351 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
352
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700353 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
354 switch (trip) {
355 case TSENS_TRIP_STAGE3:
356 code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
357 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
358 mask = TSENS_MAX_STATUS_MASK;
359
360 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
361 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
362 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
363 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
364 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
365 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
366 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
367 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
368 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
369 break;
370 case TSENS_TRIP_STAGE2:
371 code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
372 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
373 mask = TSENS_UPPER_STATUS_CLR;
374
375 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
376 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
377 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
378 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
379 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
380 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
381 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
382 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
383 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
384 break;
385 case TSENS_TRIP_STAGE1:
386 code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
387 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
388 mask = TSENS_LOWER_STATUS_CLR;
389
390 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
391 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
392 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
393 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
394 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
395 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
396 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
397 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
398 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
399 break;
400 case TSENS_TRIP_STAGE0:
401 code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
402 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
403 mask = TSENS_MIN_STATUS_MASK;
404
405 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
406 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
407 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
408 else if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
409 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
410 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
411 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
412 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
413 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
414 break;
415 default:
416 return -EINVAL;
417 }
418
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800419 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) {
420 if (tmdev->hw_type == APQ_8064)
421 writel_relaxed(reg_cntl | mask, TSENS_8064_STATUS_CNTL);
422 else
423 writel_relaxed(reg_cntl | mask, TSENS_CNTL_ADDR);
424 } else {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700425 if (code < lo_code || code > hi_code) {
426 pr_info("%s with invalid code %x\n", __func__, code);
427 return -EINVAL;
428 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800429 if (tmdev->hw_type == APQ_8064)
430 writel_relaxed(reg_cntl & ~mask,
431 TSENS_8064_STATUS_CNTL);
432 else
433 writel_relaxed(reg_cntl & ~mask, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700434 }
435 mb();
436 return 0;
437}
438
439static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
440 int trip, unsigned long *temp)
441{
442 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
443 unsigned int reg;
444
445 if (!tm_sensor || trip < 0 || !temp)
446 return -EINVAL;
447
448 reg = readl_relaxed(TSENS_THRESHOLD_ADDR);
449 switch (trip) {
450 case TSENS_TRIP_STAGE3:
451 reg = (reg & TSENS_THRESHOLD_MAX_LIMIT_MASK)
452 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
453 break;
454 case TSENS_TRIP_STAGE2:
455 reg = (reg & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
456 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
457 break;
458 case TSENS_TRIP_STAGE1:
459 reg = (reg & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
460 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
461 break;
462 case TSENS_TRIP_STAGE0:
463 reg = (reg & TSENS_THRESHOLD_MIN_LIMIT_MASK)
464 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
465 break;
466 default:
467 return -EINVAL;
468 }
469
470 *temp = tsens_tz_code_to_degC(reg, tm_sensor->sensor_num);
471
472 return 0;
473}
474
475static int tsens_tz_get_crit_temp(struct thermal_zone_device *thermal,
476 unsigned long *temp)
477{
478 return tsens_tz_get_trip_temp(thermal, TSENS_TRIP_STAGE3, temp);
479}
480
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800481static int tsens_tz_notify(struct thermal_zone_device *thermal,
482 int count, enum thermal_trip_type type)
483{
484 /* TSENS driver does not shutdown the device.
485 All Thermal notification are sent to the
486 thermal daemon to take appropriate action */
487 return 1;
488}
489
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700490static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
491 int trip, long temp)
492{
493 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
494 unsigned int reg_th, reg_cntl;
495 int code, hi_code, lo_code, code_err_chk;
496
497 code_err_chk = code = tsens_tz_degC_to_code(temp,
498 tm_sensor->sensor_num);
499 if (!tm_sensor || trip < 0)
500 return -EINVAL;
501
502 lo_code = TSENS_THRESHOLD_MIN_CODE;
503 hi_code = TSENS_THRESHOLD_MAX_CODE;
504
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800505 if (tmdev->hw_type == APQ_8064)
506 reg_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
507 else
508 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700509 reg_th = readl_relaxed(TSENS_THRESHOLD_ADDR);
510 switch (trip) {
511 case TSENS_TRIP_STAGE3:
512 code <<= TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
513 reg_th &= ~TSENS_THRESHOLD_MAX_LIMIT_MASK;
514
515 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
516 lo_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
517 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
518 else if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
519 lo_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
520 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
521 else if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
522 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
523 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
524 break;
525 case TSENS_TRIP_STAGE2:
526 code <<= TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
527 reg_th &= ~TSENS_THRESHOLD_UPPER_LIMIT_MASK;
528
529 if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
530 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
531 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
532 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_STAGE1:
540 code <<= TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
541 reg_th &= ~TSENS_THRESHOLD_LOWER_LIMIT_MASK;
542
543 if (!(reg_cntl & TSENS_MIN_STATUS_MASK))
544 lo_code = (reg_th & TSENS_THRESHOLD_MIN_LIMIT_MASK)
545 >> TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
546 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
547 hi_code = (reg_th & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
548 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
549 else if (!(reg_cntl & TSENS_MAX_STATUS_MASK))
550 hi_code = (reg_th & TSENS_THRESHOLD_MAX_LIMIT_MASK)
551 >> TSENS_THRESHOLD_MAX_LIMIT_SHIFT;
552 break;
553 case TSENS_TRIP_STAGE0:
554 code <<= TSENS_THRESHOLD_MIN_LIMIT_SHIFT;
555 reg_th &= ~TSENS_THRESHOLD_MIN_LIMIT_MASK;
556
557 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
558 hi_code = (reg_th & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
559 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
560 else 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 default:
568 return -EINVAL;
569 }
570
571 if (code_err_chk < lo_code || code_err_chk > hi_code)
572 return -EINVAL;
573
574 writel_relaxed(reg_th | code, TSENS_THRESHOLD_ADDR);
575
576 return 0;
577}
578
579static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
580 .get_temp = tsens_tz_get_temp,
581 .get_mode = tsens_tz_get_mode,
582 .set_mode = tsens_tz_set_mode,
583 .get_trip_type = tsens_tz_get_trip_type,
584 .activate_trip_type = tsens_tz_activate_trip_type,
585 .get_trip_temp = tsens_tz_get_trip_temp,
586 .set_trip_temp = tsens_tz_set_trip_temp,
587 .get_crit_temp = tsens_tz_get_crit_temp,
Siddartha Mohanadoss51c6ab42012-01-09 10:14:28 -0800588 .notify = tsens_tz_notify,
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700589};
590
591static void notify_uspace_tsens_fn(struct work_struct *work)
592{
593 struct tsens_tm_device_sensor *tm = container_of(work,
594 struct tsens_tm_device_sensor, work);
595
596 sysfs_notify(&tm->tz_dev->device.kobj,
597 NULL, "type");
598}
599
600static irqreturn_t tsens_isr(int irq, void *data)
601{
602 struct tsens_tm_device *tm = data;
603 unsigned int threshold, threshold_low, i, code, reg, sensor, mask;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800604 unsigned int sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700605 bool upper_th_x, lower_th_x;
606 int adc_code;
607
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800608 if (tmdev->hw_type == APQ_8064) {
609 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
610 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
611 TSENS_UPPER_STATUS_CLR, TSENS_8064_STATUS_CNTL);
612 } else {
613 reg = readl_relaxed(TSENS_CNTL_ADDR);
614 writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
615 TSENS_UPPER_STATUS_CLR, TSENS_CNTL_ADDR);
616 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700617 mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
618 threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
619 threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
620 >> TSENS_THRESHOLD_LOWER_LIMIT_SHIFT;
621 threshold = (threshold & TSENS_THRESHOLD_UPPER_LIMIT_MASK)
622 >> TSENS_THRESHOLD_UPPER_LIMIT_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800623 sensor = readl_relaxed(TSENS_CNTL_ADDR);
624 if (tmdev->hw_type == APQ_8064) {
625 reg = readl_relaxed(TSENS_8064_STATUS_CNTL);
626 sensor &= (uint32_t) TSENS_8064_SENSORS_EN;
627 } else {
628 reg = sensor;
629 sensor &= (uint32_t) SENSORS_EN;
630 }
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700631 sensor >>= TSENS_SENSOR0_SHIFT;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800632 sensor_addr = (unsigned int)TSENS_S0_STATUS_ADDR;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700633 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800634 if (i == TSENS_8064_SEQ_SENSORS)
635 sensor_addr += 40;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700636 if (sensor & TSENS_MASK1) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800637 code = readl_relaxed(sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700638 upper_th_x = code >= threshold;
639 lower_th_x = code <= threshold_low;
640 if (upper_th_x)
641 mask |= TSENS_UPPER_STATUS_CLR;
642 if (lower_th_x)
643 mask |= TSENS_LOWER_STATUS_CLR;
644 if (upper_th_x || lower_th_x) {
645 /* Notify user space */
646 schedule_work(&tm->sensor[i].work);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800647 adc_code = readl_relaxed(sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700648 pr_info("\nTrip point triggered by "
649 "current temperature (%d degrees) "
650 "measured by Temperature-Sensor %d\n",
651 tsens_tz_code_to_degC(adc_code, i), i);
652 }
653 }
654 sensor >>= 1;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800655 sensor_addr += TSENS_SENSOR_STATUS_SIZE;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700656 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800657 if (tmdev->hw_type == APQ_8064)
658 writel_relaxed(reg & mask, TSENS_8064_STATUS_CNTL);
659 else
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700660 writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
661 mb();
662 return IRQ_HANDLED;
663}
664
665static void tsens_disable_mode(void)
666{
667 unsigned int reg_cntl = 0;
668
669 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800670 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
671 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700672 writel_relaxed(reg_cntl &
673 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
674 TSENS_SENSOR0_SHIFT) | TSENS_8960_SLP_CLK_ENA
675 | TSENS_EN), TSENS_CNTL_ADDR);
676 else if (tmdev->hw_type == MSM_8660)
677 writel_relaxed(reg_cntl &
678 ~((((1 << tmdev->tsens_num_sensor) - 1) <<
679 TSENS_SENSOR0_SHIFT) | TSENS_8660_SLP_CLK_ENA
680 | TSENS_EN), TSENS_CNTL_ADDR);
681}
682
683static void tsens_hw_init(void)
684{
685 unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800686 unsigned int reg_status_cntl = 0;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700687
688 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
689 writel_relaxed(reg_cntl | TSENS_SW_RST, TSENS_CNTL_ADDR);
690
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700691 if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615) {
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700692 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700693 (TSENS_MEASURE_PERIOD << 18) |
694 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
695 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
696 (((1 << tmdev->tsens_num_sensor) - 1) <<
697 TSENS_SENSOR0_SHIFT);
698 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossd8e6db72011-10-27 00:26:18 -0700699 reg_cntl |= TSENS_EN;
700 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700701
702 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
703 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
704 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
705 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
706 } else if (tmdev->hw_type == MSM_8660) {
707 reg_cntl |= TSENS_8660_SLP_CLK_ENA | TSENS_EN |
708 (TSENS_MEASURE_PERIOD << 16) |
709 TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR |
710 TSENS_MIN_STATUS_MASK | TSENS_MAX_STATUS_MASK |
711 (((1 << tmdev->tsens_num_sensor) - 1) <<
712 TSENS_SENSOR0_SHIFT);
713
714 /* set TSENS_CONFIG bits (bits 29:28 of TSENS_CNTL) to '01';
715 this setting found to be optimal. */
716 reg_cntl = (reg_cntl & ~TSENS_8660_CONFIG_MASK) |
717 (TSENS_8660_CONFIG << TSENS_8660_CONFIG_SHIFT);
718
719 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800720 } else if (tmdev->hw_type == APQ_8064) {
721 reg_cntl |= TSENS_8960_SLP_CLK_ENA |
722 (TSENS_MEASURE_PERIOD << 18) |
723 (((1 << tmdev->tsens_num_sensor) - 1) <<
724 TSENS_SENSOR0_SHIFT);
725 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
726 reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
727 reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
728 TSENS_UPPER_STATUS_CLR |
729 TSENS_MIN_STATUS_MASK |
730 TSENS_MAX_STATUS_MASK;
731 writel_relaxed(reg_status_cntl, TSENS_8064_STATUS_CNTL);
732 reg_cntl |= TSENS_EN;
733 writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
734
735 reg_cfg = readl_relaxed(TSENS_8960_CONFIG_ADDR);
736 reg_cfg = (reg_cfg & ~TSENS_8960_CONFIG_MASK) |
737 (TSENS_8960_CONFIG << TSENS_8960_CONFIG_SHIFT);
738 writel_relaxed(reg_cfg, TSENS_8960_CONFIG_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700739 }
740
741 reg_thr |= (TSENS_LOWER_LIMIT_TH << TSENS_THRESHOLD_LOWER_LIMIT_SHIFT) |
742 (TSENS_UPPER_LIMIT_TH << TSENS_THRESHOLD_UPPER_LIMIT_SHIFT) |
743 (TSENS_MIN_LIMIT_TH << TSENS_THRESHOLD_MIN_LIMIT_SHIFT) |
744 (TSENS_MAX_LIMIT_TH << TSENS_THRESHOLD_MAX_LIMIT_SHIFT);
745 writel_relaxed(reg_thr, TSENS_THRESHOLD_ADDR);
746}
747
748static int tsens_calib_sensors8660(void)
749{
750 uint32_t *main_sensor_addr, sensor_shift, red_sensor_shift;
751 uint32_t sensor_mask, red_sensor_mask;
752
753 main_sensor_addr = TSENS_8660_QFPROM_ADDR;
754 sensor_shift = TSENS_SENSOR_SHIFT;
755 red_sensor_shift = sensor_shift + TSENS_RED_SHIFT;
756 sensor_mask = TSENS_THRESHOLD_MAX_CODE << sensor_shift;
757 red_sensor_mask = TSENS_THRESHOLD_MAX_CODE << red_sensor_shift;
758 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
759 (readl_relaxed(main_sensor_addr) & sensor_mask)
760 >> sensor_shift;
761 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup =
762 (readl_relaxed(main_sensor_addr)
763 & red_sensor_mask) >> red_sensor_shift;
764 if (tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup)
765 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
766 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
767 if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
768 pr_err("%s: No temperature sensor data for calibration"
769 " in QFPROM!\n", __func__);
770 return -ENODEV;
771 }
772
773 tmdev->sensor[TSENS_MAIN_SENSOR].offset = tmdev->tsens_factor *
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800774 TSENS_CAL_DEGC -
775 tmdev->sensor[TSENS_MAIN_SENSOR].slope_mul_tsens_factor *
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700776 tmdev->sensor[TSENS_MAIN_SENSOR].calib_data;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800777
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700778 tmdev->prev_reading_avail = false;
779 INIT_WORK(&tmdev->sensor[TSENS_MAIN_SENSOR].work,
780 notify_uspace_tsens_fn);
781
782 return 0;
783}
784
785static int tsens_calib_sensors8960(void)
786{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800787 uint32_t i;
788 uint8_t *main_sensor_addr, *backup_sensor_addr;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700789 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800790 main_sensor_addr = TSENS_8960_QFPROM_ADDR0 + i;
791 backup_sensor_addr = TSENS_8960_QFPROM_SPARE_ADDR0 + i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700792
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800793 tmdev->sensor[i].calib_data = readb_relaxed(main_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700794 tmdev->sensor[i].calib_data_backup =
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800795 readb_relaxed(backup_sensor_addr);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700796 if (tmdev->sensor[i].calib_data_backup)
797 tmdev->sensor[i].calib_data =
798 tmdev->sensor[i].calib_data_backup;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700799 if (!tmdev->sensor[i].calib_data) {
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800800 WARN(1, "%s: No temperature sensor:%d data for"
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700801 " calibration in QFPROM!\n", __func__, i);
802 return -ENODEV;
803 }
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800804 tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
805 tmdev->tsens_factor)
806 - (tmdev->sensor[i].calib_data *
807 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700808 tmdev->prev_reading_avail = false;
809 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
810 }
811
812 return 0;
813}
814
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700815static int tsens_check_version_support(void)
816{
817 int rc = 0;
818
819 if (tmdev->hw_type == MSM_8960)
820 if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
821 rc = -ENODEV;
Siddartha Mohanadoss0b9e5172011-09-29 18:54:13 -0700822
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700823 return rc;
824}
825
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700826static int tsens_calib_sensors(void)
827{
Siddartha Mohanadoss73010e52011-10-31 11:23:18 -0700828 int rc = -ENODEV;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700829
830 if (tmdev->hw_type == MSM_8660)
831 rc = tsens_calib_sensors8660();
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800832 else if (tmdev->hw_type == MSM_8960 || tmdev->hw_type == MSM_9615 ||
833 tmdev->hw_type == APQ_8064)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700834 rc = tsens_calib_sensors8960();
835
836 return rc;
837}
838
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800839int msm_tsens_early_init(struct tsens_platform_data *pdata)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700840{
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800841 int rc = 0, i;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700842
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700843 if (!pdata) {
844 pr_err("No TSENS Platform data\n");
845 return -EINVAL;
846 }
847
848 tmdev = kzalloc(sizeof(struct tsens_tm_device) +
849 pdata->tsens_num_sensor *
850 sizeof(struct tsens_tm_device_sensor),
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800851 GFP_ATOMIC);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700852 if (tmdev == NULL) {
853 pr_err("%s: kzalloc() failed.\n", __func__);
854 return -ENOMEM;
855 }
856
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800857 for (i = 0; i < pdata->tsens_num_sensor; i++)
858 tmdev->sensor[i].slope_mul_tsens_factor = pdata->slope[i];
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700859 tmdev->tsens_factor = pdata->tsens_factor;
860 tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
861 tmdev->hw_type = pdata->hw_type;
862
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700863 rc = tsens_check_version_support();
864 if (rc < 0) {
865 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800866 tmdev = NULL;
Siddartha Mohanadoss6f8c4922011-09-21 12:16:33 -0700867 return rc;
868 }
869
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700870 rc = tsens_calib_sensors();
871 if (rc < 0) {
872 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800873 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700874 return rc;
875 }
876
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800877 if (tmdev->hw_type == APQ_8064)
878 tsens_status_cntl_start = 0;
879 else
880 tsens_status_cntl_start = TSENS_STATUS_CNTL_OFFSET;
881
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700882 tsens_hw_init();
883
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800884 pr_debug("msm_tsens_early_init: done\n");
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800885
886 return rc;
887}
888
889static int __init tsens_tm_init(void)
890{
891 int rc, i;
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800892 unsigned int reg_cntl, reg_status;
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800893
894 if (!tmdev) {
895 pr_info("%s : TSENS early init not done.\n", __func__);
896 return -EFAULT;
897 }
898
899 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700900 char name[17];
901 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
902 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
903 tmdev->sensor[i].sensor_num = i;
904 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
905 TSENS_TRIP_NUM, &tmdev->sensor[i],
906 &tsens_thermal_zone_ops, 0, 0, 0, 0);
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800907 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700908 pr_err("%s: thermal_zone_device_register() failed.\n",
909 __func__);
910 rc = -ENODEV;
911 goto fail;
912 }
913 tmdev->sensor[i].mode = THERMAL_DEVICE_DISABLED;
914 }
915
916 rc = request_irq(TSENS_UPPER_LOWER_INT, tsens_isr,
917 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
918 if (rc < 0) {
919 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
920 for (i = 0; i < tmdev->tsens_num_sensor; i++)
921 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
922 goto fail;
923 }
924
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800925 reg_status = readl_relaxed(TSENS_8064_STATUS_CNTL);
926 pr_debug("%s: OK\n", __func__);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700927 mb();
Siddartha Mohanadosscaeaa922012-02-07 16:41:38 -0800928 reg_status = readl_relaxed(TSENS_8064_STATUS_CNTL);
929 reg_cntl = readl_relaxed(TSENS_CNTL_ADDR);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700930 return 0;
931fail:
932 tsens_disable_mode();
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700933 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800934 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700935 mb();
936 return rc;
937}
938
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800939static void __exit tsens_tm_remove(void)
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700940{
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700941 int i;
942
943 tsens_disable_mode();
944 mb();
945 free_irq(TSENS_UPPER_LOWER_INT, tmdev);
946 for (i = 0; i < tmdev->tsens_num_sensor; i++)
947 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700948 kfree(tmdev);
Jeff Ohlsteinf744c862012-02-01 17:52:44 -0800949 tmdev = NULL;
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700950}
951
Siddartha Mohanadossccd49852012-01-20 15:06:40 -0800952module_init(tsens_tm_init);
953module_exit(tsens_tm_remove);
Siddartha Mohanadossacd24262011-08-18 11:19:00 -0700954
955MODULE_LICENSE("GPL v2");
956MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
957MODULE_VERSION("1.0");
958MODULE_ALIAS("platform:tsens8960-tm");