blob: e37b3c4d960d5813378da9aa8af18adab57f350e [file] [log] [blame]
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -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 */
Michael Bohanb89167e2012-10-04 16:24:23 -070013
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070016#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/thermal.h>
19#include <linux/interrupt.h>
20#include <linux/delay.h>
21#include <linux/kernel.h>
22#include <linux/io.h>
23#include <linux/slab.h>
24#include <linux/msm_tsens.h>
25#include <linux/err.h>
26#include <linux/of.h>
27
28#include <mach/msm_iomap.h>
29
30#define TSENS_DRIVER_NAME "msm-tsens"
31/* TSENS register info */
32#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n) ((n) + 0x1000)
33#define TSENS_INTERRUPT_EN BIT(0)
34
35#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n) ((n) + 0x1004)
36#define TSENS_UPPER_STATUS_CLR BIT(21)
37#define TSENS_LOWER_STATUS_CLR BIT(20)
38#define TSENS_UPPER_THRESHOLD_MASK 0xffc00
39#define TSENS_LOWER_THRESHOLD_MASK 0x3ff
40#define TSENS_UPPER_THRESHOLD_SHIFT 10
41
42#define TSENS_S0_STATUS_ADDR(n) ((n) + 0x1030)
43#define TSENS_SN_ADDR_OFFSET 0x4
44#define TSENS_SN_STATUS_TEMP_MASK 0x3ff
45#define TSENS_SN_STATUS_LOWER_STATUS BIT(11)
46#define TSENS_SN_STATUS_UPPER_STATUS BIT(12)
47#define TSENS_STATUS_ADDR_OFFSET 2
48
49#define TSENS_TRDY_ADDR(n) ((n) + 0x105c)
50#define TSENS_TRDY_MASK BIT(0)
51
52#define TSENS_CTRL_ADDR(n) (n)
Siddartha Mohanadossa0d74c62012-10-23 10:38:41 -070053#define TSENS_EN BIT(0)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070054#define TSENS_SW_RST BIT(1)
Siddartha Mohanadossa0d74c62012-10-23 10:38:41 -070055#define TSENS_ADC_CLK_SEL BIT(2)
56#define TSENS_SENSOR0_SHIFT 3
57#define TSENS_312_5_MS_MEAS_PERIOD 2
58#define TSENS_MEAS_PERIOD_SHIFT 18
59
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070060#define TSENS_SN_MIN_MAX_STATUS_CTRL(n) ((n) + 4)
61#define TSENS_GLOBAL_CONFIG(n) ((n) + 0x34)
62#define TSENS_S0_MAIN_CONFIG(n) ((n) + 0x38)
63#define TSENS_SN_REMOTE_CONFIG(n) ((n) + 0x3c)
64
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070065#define TSENS_EEPROM(n) ((n) + 0xd0)
66#define TSENS_EEPROM_REDUNDANCY_SEL(n) ((n) + 0x1cc)
67#define TSENS_EEPROM_BACKUP_REGION(n) ((n) + 0x440)
68
69#define TSENS_MAIN_CALIB_ADDR_RANGE 6
70#define TSENS_BACKUP_CALIB_ADDR_RANGE 4
71
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -080072#define TSENS_EEPROM_8X26_1(n) ((n) + 0x1c0)
73#define TSENS_EEPROM_8X26_2(n) ((n) + 0x444)
74#define TSENS_8X26_MAIN_CALIB_ADDR_RANGE 4
75
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070076/* TSENS calibration Mask data */
77#define TSENS_BASE1_MASK 0xff
78#define TSENS0_POINT1_MASK 0x3f00
79#define TSENS1_POINT1_MASK 0xfc000
80#define TSENS2_POINT1_MASK 0x3f00000
81#define TSENS3_POINT1_MASK 0xfc000000
82#define TSENS4_POINT1_MASK 0x3f
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070083#define TSENS5_POINT1_MASK 0xfc0
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070084#define TSENS6_POINT1_MASK 0x3f000
85#define TSENS7_POINT1_MASK 0xfc0000
86#define TSENS8_POINT1_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070087#define TSENS8_POINT1_MASK_BACKUP 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070088#define TSENS9_POINT1_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070089#define TSENS9_POINT1_MASK_BACKUP 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -080090#define TSENS10_POINT1_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070091#define TSENS10_POINT1_MASK_BACKUP 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070092#define TSENS_CAL_SEL_0_1 0xc0000000
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070093#define TSENS_CAL_SEL_2 0x40000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070094#define TSENS_CAL_SEL_SHIFT 30
95#define TSENS_CAL_SEL_SHIFT_2 28
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070096#define TSENS_ONE_POINT_CALIB 0x1
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -070097#define TSENS_ONE_POINT_CALIB_OPTION_2 0x2
98#define TSENS_TWO_POINT_CALIB 0x3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070099
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700100#define TSENS0_POINT1_SHIFT 8
101#define TSENS1_POINT1_SHIFT 14
102#define TSENS2_POINT1_SHIFT 20
103#define TSENS3_POINT1_SHIFT 26
104#define TSENS5_POINT1_SHIFT 6
105#define TSENS6_POINT1_SHIFT 12
106#define TSENS7_POINT1_SHIFT 18
107#define TSENS8_POINT1_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700108#define TSENS9_POINT1_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700109#define TSENS10_POINT1_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700110#define TSENS10_POINT1_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700111
112#define TSENS_POINT2_BASE_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700113#define TSENS_POINT2_BASE_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700114#define TSENS0_POINT2_SHIFT 20
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700115#define TSENS0_POINT2_BACKUP_SHIFT 26
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700116#define TSENS1_POINT2_SHIFT 26
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700117#define TSENS2_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700118#define TSENS3_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700119#define TSENS3_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700120#define TSENS4_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700121#define TSENS4_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700122#define TSENS5_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700123#define TSENS5_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700124#define TSENS6_POINT2_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700125#define TSENS7_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700126#define TSENS8_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700127#define TSENS8_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700128#define TSENS9_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700129#define TSENS9_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700130#define TSENS10_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700131#define TSENS10_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700132
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700133#define TSENS_BASE2_MASK 0xff000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700134#define TSENS_BASE2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700135#define TSENS0_POINT2_MASK 0x3f00000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700136#define TSENS0_POINT2_BACKUP_MASK 0xfc000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700137#define TSENS1_POINT2_MASK 0xfc000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700138#define TSENS1_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700139#define TSENS2_POINT2_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700140#define TSENS2_POINT2_BACKUP_MASK 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800141#define TSENS3_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700142#define TSENS3_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700143#define TSENS4_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700144#define TSENS4_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700145#define TSENS5_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700146#define TSENS5_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700147#define TSENS6_POINT2_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700148#define TSENS6_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700149#define TSENS7_POINT2_MASK 0x3f
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800150#define TSENS7_POINT2_BACKUP_MASK 0xfc0
151#define TSENS8_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700152#define TSENS8_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700153#define TSENS9_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700154#define TSENS9_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700155#define TSENS10_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700156#define TSENS10_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700157
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800158#define TSENS_8X26_BASE0_MASK 0x1fe000
159#define TSENS0_8X26_POINT1_MASK 0x7f00000
160#define TSENS1_8X26_POINT1_MASK 0x3f
161#define TSENS2_8X26_POINT1_MASK 0xfc0
162#define TSENS3_8X26_POINT1_MASK 0x3f000
163#define TSENS4_8X26_POINT1_MASK 0xfc0000
164#define TSENS5_8X26_POINT1_MASK 0x3f000000
165#define TSENS6_8X26_POINT1_MASK 0x3f00000
166#define TSENS_8X26_TSENS_CAL_SEL 0xe0000000
167#define TSENS_8X26_BASE1_MASK 0xff
168#define TSENS0_8X26_POINT2_MASK 0x3f00
169#define TSENS1_8X26_POINT2_MASK 0xfc00
170#define TSENS2_8X26_POINT2_MASK 0x3f00000
171#define TSENS3_8X26_POINT2_MASK 0xfc000000
172#define TSENS4_8X26_POINT2_MASK 0xfc000000
173#define TSENS5_8X26_POINT2_MASK 0x3f00000
174#define TSENS6_8X26_POINT2_MASK 0x7e0000
175
176#define TSENS_8X26_CAL_SEL_SHIFT 29
177#define TSENS_8X26_BASE0_SHIFT 13
178#define TSENS0_8X26_POINT1_SHIFT 21
179#define TSENS2_8X26_POINT1_SHIFT 6
180#define TSENS3_8X26_POINT1_SHIFT 12
181#define TSENS4_8X26_POINT1_SHIFT 18
182#define TSENS5_8X26_POINT1_SHIFT 24
183#define TSENS6_8X26_POINT1_SHIFT 20
184
185#define TSENS0_8X26_POINT2_SHIFT 8
186#define TSENS1_8X26_POINT2_SHIFT 14
187#define TSENS2_8X26_POINT2_SHIFT 20
188#define TSENS3_8X26_POINT2_SHIFT 26
189#define TSENS4_8X26_POINT2_SHIFT 20
190#define TSENS5_8X26_POINT2_SHIFT 26
191#define TSENS6_8X26_POINT2_SHIFT 17
192
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700193#define TSENS_BIT_APPEND 0x3
194#define TSENS_CAL_DEGC_POINT1 30
195#define TSENS_CAL_DEGC_POINT2 120
196#define TSENS_SLOPE_FACTOR 1000
197
198/* TSENS register data */
199#define TSENS_TRDY_RDY_MIN_TIME 2000
200#define TSENS_TRDY_RDY_MAX_TIME 2100
201#define TSENS_THRESHOLD_MAX_CODE 0x3ff
202#define TSENS_THRESHOLD_MIN_CODE 0x0
203
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700204#define TSENS_GLOBAL_INIT_DATA 0x302f16c
205#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700206#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700207#define TSENS_SN_REMOTE_CFG_DATA 0x11c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700208
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700209#define TSENS_QFPROM_BACKUP_SEL 0x3
210#define TSENS_QFPROM_BACKUP_REDUN_SEL 0xe0000000
211#define TSENS_QFPROM_BACKUP_REDUN_SHIFT 29
212
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800213enum tsens_calib_fuse_map_type {
214 TSENS_CALIB_FUSE_MAP_8974 = 0,
215 TSENS_CALIB_FUSE_MAP_8X26,
216 TSENS_CALIB_FUSE_MAP_8X10,
217 TSENS_CALIB_FUSE_MAP_NUM,
218};
219
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700220/* Trips: warm and cool */
221enum tsens_trip_type {
222 TSENS_TRIP_WARM = 0,
223 TSENS_TRIP_COOL,
224 TSENS_TRIP_NUM,
225};
226
227struct tsens_tm_device_sensor {
228 struct thermal_zone_device *tz_dev;
229 enum thermal_device_mode mode;
230 unsigned int sensor_num;
231 struct work_struct work;
232 int offset;
233 int calib_data_point1;
234 int calib_data_point2;
235 uint32_t slope_mul_tsens_factor;
236};
237
238struct tsens_tm_device {
239 struct platform_device *pdev;
240 bool prev_reading_avail;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -0700241 bool calibration_less_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700242 int tsens_factor;
243 uint32_t tsens_num_sensor;
244 int tsens_irq;
245 void *tsens_addr;
246 void *tsens_calib_addr;
247 int tsens_len;
248 int calib_len;
249 struct resource *res_tsens_mem;
250 struct resource *res_calib_mem;
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700251 struct work_struct tsens_work;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800252 uint32_t calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700253 struct tsens_tm_device_sensor sensor[0];
254};
255
256struct tsens_tm_device *tmdev;
257
258static int tsens_tz_code_to_degc(int adc_code, int sensor_num)
259{
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700260 int degc, num, den;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700261
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700262 num = ((adc_code * tmdev->tsens_factor) -
263 tmdev->sensor[sensor_num].offset);
264 den = (int) tmdev->sensor[sensor_num].slope_mul_tsens_factor;
265 degc = num/den;
266
267 if ((degc >= 0) && (num % den != 0))
268 degc++;
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -0700269
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700270 return degc;
271}
272
273static int tsens_tz_degc_to_code(int degc, int sensor_num)
274{
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -0700275 int code = ((degc * tmdev->sensor[sensor_num].slope_mul_tsens_factor)
276 + tmdev->sensor[sensor_num].offset)/tmdev->tsens_factor;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700277
278 if (code > TSENS_THRESHOLD_MAX_CODE)
279 code = TSENS_THRESHOLD_MAX_CODE;
280 else if (code < TSENS_THRESHOLD_MIN_CODE)
281 code = TSENS_THRESHOLD_MIN_CODE;
282 return code;
283}
284
285static void msm_tsens_get_temp(int sensor_num, unsigned long *temp)
286{
287 unsigned int code, sensor_addr;
288
289 if (!tmdev->prev_reading_avail) {
290 while (!(readl_relaxed(TSENS_TRDY_ADDR(tmdev->tsens_addr))
291 & TSENS_TRDY_MASK))
292 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
293 TSENS_TRDY_RDY_MAX_TIME);
294 tmdev->prev_reading_avail = true;
295 }
296
297 sensor_addr =
298 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
299 code = readl_relaxed(sensor_addr +
300 (sensor_num << TSENS_STATUS_ADDR_OFFSET));
301 *temp = tsens_tz_code_to_degc((code & TSENS_SN_STATUS_TEMP_MASK),
302 sensor_num);
303}
304
305static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
306 unsigned long *temp)
307{
308 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
309
310 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
311 return -EINVAL;
312
313 msm_tsens_get_temp(tm_sensor->sensor_num, temp);
314
315 return 0;
316}
317
318int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
319{
320 if (!tmdev)
321 return -ENODEV;
322
323 msm_tsens_get_temp(device->sensor_num, temp);
324
325 return 0;
326}
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700327EXPORT_SYMBOL(tsens_get_temp);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700328
329static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
330 enum thermal_device_mode *mode)
331{
332 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
333
334 if (!tm_sensor || !mode)
335 return -EINVAL;
336
337 *mode = tm_sensor->mode;
338
339 return 0;
340}
341
342static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
343 int trip, enum thermal_trip_type *type)
344{
345 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
346
347 if (!tm_sensor || trip < 0 || !type)
348 return -EINVAL;
349
350 switch (trip) {
351 case TSENS_TRIP_WARM:
352 *type = THERMAL_TRIP_CONFIGURABLE_HI;
353 break;
354 case TSENS_TRIP_COOL:
355 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
356 break;
357 default:
358 return -EINVAL;
359 }
360
361 return 0;
362}
363
364static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
365 int trip, enum thermal_trip_activation_mode mode)
366{
367 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
368 unsigned int reg_cntl, code, hi_code, lo_code, mask;
369
370 if (!tm_sensor || trip < 0)
371 return -EINVAL;
372
373 lo_code = TSENS_THRESHOLD_MIN_CODE;
374 hi_code = TSENS_THRESHOLD_MAX_CODE;
375
376 reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
377 (tmdev->tsens_addr) +
378 (tm_sensor->sensor_num * 4)));
379 switch (trip) {
380 case TSENS_TRIP_WARM:
381 code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
382 >> TSENS_UPPER_THRESHOLD_SHIFT;
383 mask = TSENS_UPPER_STATUS_CLR;
384
385 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
386 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
387 break;
388 case TSENS_TRIP_COOL:
389 code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
390 mask = TSENS_LOWER_STATUS_CLR;
391
392 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
393 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
394 >> TSENS_UPPER_THRESHOLD_SHIFT;
395 break;
396 default:
397 return -EINVAL;
398 }
399
400 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
401 writel_relaxed(reg_cntl | mask,
402 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
403 (tmdev->tsens_addr) +
404 (tm_sensor->sensor_num * 4)));
405 else {
406 if (code < lo_code || code > hi_code) {
407 pr_err("%s with invalid code %x\n", __func__, code);
408 return -EINVAL;
409 }
410 writel_relaxed(reg_cntl & ~mask,
411 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr) +
412 (tm_sensor->sensor_num * 4)));
413 }
414 mb();
415 return 0;
416}
417
418static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
419 int trip, unsigned long *temp)
420{
421 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
422 unsigned int reg;
423
424 if (!tm_sensor || trip < 0 || !temp)
425 return -EINVAL;
426
427 reg = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
428 (tmdev->tsens_addr) +
429 (tm_sensor->sensor_num * TSENS_SN_ADDR_OFFSET));
430 switch (trip) {
431 case TSENS_TRIP_WARM:
432 reg = (reg & TSENS_UPPER_THRESHOLD_MASK) >>
433 TSENS_UPPER_THRESHOLD_SHIFT;
434 break;
435 case TSENS_TRIP_COOL:
436 reg = (reg & TSENS_LOWER_THRESHOLD_MASK);
437 break;
438 default:
439 return -EINVAL;
440 }
441
442 *temp = tsens_tz_code_to_degc(reg, tm_sensor->sensor_num);
443
444 return 0;
445}
446
447static int tsens_tz_notify(struct thermal_zone_device *thermal,
448 int count, enum thermal_trip_type type)
449{
450 /* TSENS driver does not shutdown the device.
451 All Thermal notification are sent to the
452 thermal daemon to take appropriate action */
453 pr_debug("%s debug\n", __func__);
454 return 1;
455}
456
457static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
458 int trip, long temp)
459{
460 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
461 unsigned int reg_cntl;
462 int code, hi_code, lo_code, code_err_chk;
463
464 code_err_chk = code = tsens_tz_degc_to_code(temp,
465 tm_sensor->sensor_num);
466 if (!tm_sensor || trip < 0)
467 return -EINVAL;
468
469 lo_code = TSENS_THRESHOLD_MIN_CODE;
470 hi_code = TSENS_THRESHOLD_MAX_CODE;
471
472 reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
473 (tmdev->tsens_addr) +
474 (tm_sensor->sensor_num * TSENS_SN_ADDR_OFFSET));
475 switch (trip) {
476 case TSENS_TRIP_WARM:
477 code <<= TSENS_UPPER_THRESHOLD_SHIFT;
478 reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
479 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
480 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
481 break;
482 case TSENS_TRIP_COOL:
483 reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
484 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
485 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
486 >> TSENS_UPPER_THRESHOLD_SHIFT;
487 break;
488 default:
489 return -EINVAL;
490 }
491
492 if (code_err_chk < lo_code || code_err_chk > hi_code)
493 return -EINVAL;
494
495 writel_relaxed(reg_cntl | code, (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
496 (tmdev->tsens_addr) +
497 (tm_sensor->sensor_num *
498 TSENS_SN_ADDR_OFFSET)));
499 mb();
500 return 0;
501}
502
503static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
504 .get_temp = tsens_tz_get_temp,
505 .get_mode = tsens_tz_get_mode,
506 .get_trip_type = tsens_tz_get_trip_type,
507 .activate_trip_type = tsens_tz_activate_trip_type,
508 .get_trip_temp = tsens_tz_get_trip_temp,
509 .set_trip_temp = tsens_tz_set_trip_temp,
510 .notify = tsens_tz_notify,
511};
512
513static void notify_uspace_tsens_fn(struct work_struct *work)
514{
515 struct tsens_tm_device_sensor *tm = container_of(work,
516 struct tsens_tm_device_sensor, work);
517
518 sysfs_notify(&tm->tz_dev->device.kobj,
519 NULL, "type");
520}
521
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700522static void tsens_scheduler_fn(struct work_struct *work)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700523{
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700524 struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
525 tsens_work);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700526 unsigned int i, status, threshold;
527 unsigned int sensor_status_addr, sensor_status_ctrl_addr;
528
529 sensor_status_addr =
530 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
531 sensor_status_ctrl_addr =
532 (unsigned int)TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
533 (tmdev->tsens_addr);
534 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
535 bool upper_thr = false, lower_thr = false;
536 status = readl_relaxed(sensor_status_addr);
537 threshold = readl_relaxed(sensor_status_ctrl_addr);
538 if (status & TSENS_SN_STATUS_UPPER_STATUS) {
539 writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
540 sensor_status_ctrl_addr);
541 upper_thr = true;
542 }
543 if (status & TSENS_SN_STATUS_LOWER_STATUS) {
544 writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
545 sensor_status_ctrl_addr);
546 lower_thr = true;
547 }
548 if (upper_thr || lower_thr) {
549 /* Notify user space */
550 schedule_work(&tm->sensor[i].work);
551 pr_debug("sensor:%d trigger temp (%d degC)\n", i,
552 tsens_tz_code_to_degc((status &
553 TSENS_SN_STATUS_TEMP_MASK), i));
554 }
555 sensor_status_addr += TSENS_SN_ADDR_OFFSET;
556 sensor_status_ctrl_addr += TSENS_SN_ADDR_OFFSET;
557 }
558 mb();
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700559}
560
561static irqreturn_t tsens_isr(int irq, void *data)
562{
563 schedule_work(&tmdev->tsens_work);
564
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700565 return IRQ_HANDLED;
566}
567
568static void tsens_hw_init(void)
569{
570 unsigned int reg_cntl = 0;
571 unsigned int i;
572
573 reg_cntl = readl_relaxed(TSENS_CTRL_ADDR(tmdev->tsens_addr));
574 writel_relaxed(reg_cntl | TSENS_SW_RST,
575 TSENS_CTRL_ADDR(tmdev->tsens_addr));
Siddartha Mohanadossa0d74c62012-10-23 10:38:41 -0700576 reg_cntl |= ((TSENS_312_5_MS_MEAS_PERIOD << TSENS_MEAS_PERIOD_SHIFT) |
577 (((1 << tmdev->tsens_num_sensor) - 1) << TSENS_SENSOR0_SHIFT) |
578 TSENS_EN);
579 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700580 writel_relaxed(TSENS_GLOBAL_INIT_DATA,
581 TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
582 writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
583 TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
584 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
585 writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
586 TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
587 + (i * TSENS_SN_ADDR_OFFSET));
588 writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
589 TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
590 + (i * TSENS_SN_ADDR_OFFSET));
591 }
592 writel_relaxed(TSENS_INTERRUPT_EN,
593 TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
594}
595
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800596static int tsens_calib_8x26_sensors(void)
597{
598 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
599 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
600 int tsens5_point1 = 0, tsens6_point1 = 0, tsens6_point2 = 0;
601 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
602 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
603 int tsens_base1_data = 0, tsens_calibration_mode = 0;
604 uint32_t calib_data[6];
605 uint32_t calib_tsens_point1_data[7], calib_tsens_point2_data[7];
606
607 if (tmdev->calibration_less_mode)
608 goto calibration_less_mode;
609
610 for (i = 0; i < TSENS_8X26_MAIN_CALIB_ADDR_RANGE; i++)
611 calib_data[i] = readl_relaxed(
612 (TSENS_EEPROM_8X26_1(tmdev->tsens_calib_addr))
613 + (i * TSENS_SN_ADDR_OFFSET));
614 calib_data[4] = readl_relaxed(
615 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)));
616 calib_data[5] = readl_relaxed(
617 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
618
619 tsens_calibration_mode = calib_data[5] & TSENS_8X26_TSENS_CAL_SEL;
620
621 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
622 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
623 pr_debug("backup one point calibrationless mode\n");
624 tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
625 >> TSENS_8X26_BASE0_SHIFT;
626 tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
627 TSENS0_8X26_POINT1_SHIFT;
628 tsens1_point1 = calib_data[1] & TSENS1_8X26_POINT1_MASK;
629 tsens2_point1 = (calib_data[1] & TSENS2_8X26_POINT1_MASK) >>
630 TSENS2_8X26_POINT1_SHIFT;
631 tsens3_point1 = (calib_data[1] & TSENS3_8X26_POINT1_MASK) >>
632 TSENS3_8X26_POINT1_SHIFT;
633 tsens4_point1 = (calib_data[1] & TSENS4_8X26_POINT1_MASK) >>
634 TSENS4_8X26_POINT1_SHIFT;
635 tsens5_point1 = (calib_data[1] & TSENS5_8X26_POINT1_MASK) >>
636 TSENS5_8X26_POINT1_SHIFT;
637 tsens6_point1 = (calib_data[2] & TSENS6_8X26_POINT1_MASK) >>
638 TSENS6_8X26_POINT1_SHIFT;
639 } else
640 goto calibration_less_mode;
641
642 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
643 pr_debug("backup two point calibrationless mode\n");
644 tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
645 tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
646 TSENS0_8X26_POINT2_SHIFT;
647 tsens1_point2 = (calib_data[3] & TSENS1_8X26_POINT2_MASK) >>
648 TSENS1_8X26_POINT2_SHIFT;
649 tsens2_point2 = (calib_data[3] & TSENS2_8X26_POINT2_MASK) >>
650 TSENS2_8X26_POINT2_SHIFT;
651 tsens3_point2 = (calib_data[3] & TSENS3_8X26_POINT2_MASK) >>
652 TSENS3_8X26_POINT2_SHIFT;
653 tsens4_point2 = (calib_data[4] & TSENS4_8X26_POINT2_MASK) >>
654 TSENS4_8X26_POINT2_SHIFT;
655 tsens5_point2 = (calib_data[4] & TSENS5_8X26_POINT2_MASK) >>
656 TSENS5_8X26_POINT2_SHIFT;
657 tsens6_point2 = (calib_data[5] & TSENS6_8X26_POINT2_MASK) >>
658 TSENS6_8X26_POINT2_SHIFT;
659 }
660
661 if (tsens_calibration_mode == 0) {
662calibration_less_mode:
663 pr_debug("TSENS is calibrationless mode\n");
664 for (i = 0; i < tmdev->tsens_num_sensor; i++)
665 calib_tsens_point2_data[i] = 780;
666 calib_tsens_point1_data[0] = 502;
667 calib_tsens_point1_data[1] = 509;
668 calib_tsens_point1_data[2] = 503;
669 calib_tsens_point1_data[3] = 509;
670 calib_tsens_point1_data[4] = 505;
671 calib_tsens_point1_data[5] = 509;
672 calib_tsens_point1_data[6] = 507;
673 goto compute_intercept_slope;
674 }
675
676 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
677 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
678 pr_debug("one and two point calibration calculation\n");
679 calib_tsens_point1_data[0] =
680 ((((tsens_base0_data) + tsens0_point1) << 2) |
681 TSENS_BIT_APPEND);
682 calib_tsens_point1_data[1] =
683 ((((tsens_base0_data) + tsens1_point1) << 2) |
684 TSENS_BIT_APPEND);
685 calib_tsens_point1_data[2] =
686 ((((tsens_base0_data) + tsens2_point1) << 2) |
687 TSENS_BIT_APPEND);
688 calib_tsens_point1_data[3] =
689 ((((tsens_base0_data) + tsens3_point1) << 2) |
690 TSENS_BIT_APPEND);
691 calib_tsens_point1_data[4] =
692 ((((tsens_base0_data) + tsens4_point1) << 2) |
693 TSENS_BIT_APPEND);
694 calib_tsens_point1_data[5] =
695 ((((tsens_base0_data) + tsens5_point1) << 2) |
696 TSENS_BIT_APPEND);
697 calib_tsens_point1_data[6] =
698 ((((tsens_base0_data) + tsens6_point1) << 2) |
699 TSENS_BIT_APPEND);
700 }
701
702 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
703 pr_debug("two point calibration calculation\n");
704 calib_tsens_point2_data[0] =
705 (((tsens_base1_data + tsens0_point2) << 2) |
706 TSENS_BIT_APPEND);
707 calib_tsens_point2_data[1] =
708 (((tsens_base1_data + tsens1_point2) << 2) |
709 TSENS_BIT_APPEND);
710 calib_tsens_point2_data[2] =
711 (((tsens_base1_data + tsens2_point2) << 2) |
712 TSENS_BIT_APPEND);
713 calib_tsens_point2_data[3] =
714 (((tsens_base1_data + tsens3_point2) << 2) |
715 TSENS_BIT_APPEND);
716 calib_tsens_point2_data[4] =
717 (((tsens_base1_data + tsens4_point2) << 2) |
718 TSENS_BIT_APPEND);
719 calib_tsens_point2_data[5] =
720 (((tsens_base1_data + tsens5_point2) << 2) |
721 TSENS_BIT_APPEND);
722 calib_tsens_point2_data[6] =
723 (((tsens_base1_data + tsens6_point2) << 2) |
724 TSENS_BIT_APPEND);
725 }
726
727compute_intercept_slope:
728 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
729 int32_t num = 0, den = 0;
730 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
731 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
732 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
733 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
734 temp_120_degc - temp_30_degc (x2 - x1) */
735 num = tmdev->sensor[i].calib_data_point2 -
736 tmdev->sensor[i].calib_data_point1;
737 num *= tmdev->tsens_factor;
738 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
739 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
740 }
741 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
742 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
743 tmdev->sensor[i].slope_mul_tsens_factor);
744 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
745 tmdev->prev_reading_avail = false;
746 }
747
748 return 0;
749}
750
751static int tsens_calib_8974_sensors(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700752{
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700753 int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
754 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
755 int tsens5_point1 = 0, tsens6_point1 = 0, tsens7_point1 = 0;
756 int tsens8_point1 = 0, tsens9_point1 = 0, tsens10_point1 = 0;
757 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
758 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
759 int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
760 int tsens9_point2 = 0, tsens10_point2 = 0;
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700761 int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700762 uint32_t calib_data[6], calib_redun_sel, calib_data_backup[4];
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700763 uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11];
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700764
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -0700765 if (tmdev->calibration_less_mode)
766 goto calibration_less_mode;
767
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700768 calib_redun_sel = readl_relaxed(
769 TSENS_EEPROM_REDUNDANCY_SEL(tmdev->tsens_calib_addr));
770 calib_redun_sel = calib_redun_sel & TSENS_QFPROM_BACKUP_REDUN_SEL;
771 calib_redun_sel >>= TSENS_QFPROM_BACKUP_REDUN_SHIFT;
772
773 for (i = 0; i < TSENS_MAIN_CALIB_ADDR_RANGE; i++)
774 calib_data[i] = readl_relaxed(
775 (TSENS_EEPROM(tmdev->tsens_calib_addr))
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700776 + (i * TSENS_SN_ADDR_OFFSET));
777
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700778 if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) {
779 tsens_calibration_mode = (calib_data[4] & TSENS_CAL_SEL_0_1)
780 >> TSENS_CAL_SEL_SHIFT;
781 temp = (calib_data[5] & TSENS_CAL_SEL_2)
782 >> TSENS_CAL_SEL_SHIFT_2;
783 tsens_calibration_mode |= temp;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700784
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700785 for (i = 0; i < TSENS_BACKUP_CALIB_ADDR_RANGE; i++)
786 calib_data_backup[i] = readl_relaxed(
787 (TSENS_EEPROM_BACKUP_REGION(
788 tmdev->tsens_calib_addr))
789 + (i * TSENS_SN_ADDR_OFFSET));
790
791 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB)
792 || (tsens_calibration_mode ==
793 TSENS_TWO_POINT_CALIB) ||
794 (tsens_calibration_mode ==
795 TSENS_ONE_POINT_CALIB_OPTION_2)) {
796 pr_debug("backup one point calibrationless mode\n");
797 tsens_base1_data = (calib_data_backup[0] &
798 TSENS_BASE1_MASK);
799 tsens0_point1 = (calib_data_backup[0] &
800 TSENS0_POINT1_MASK) >>
801 TSENS0_POINT1_SHIFT;
802 tsens1_point1 = (calib_data_backup[0] &
803 TSENS1_POINT1_MASK) >> TSENS1_POINT1_SHIFT;
804 tsens2_point1 = (calib_data_backup[0] &
805 TSENS2_POINT1_MASK) >> TSENS2_POINT1_SHIFT;
806 tsens3_point1 = (calib_data_backup[0] &
807 TSENS3_POINT1_MASK) >> TSENS3_POINT1_SHIFT;
808 tsens4_point1 = (calib_data_backup[1] &
809 TSENS4_POINT1_MASK);
810 tsens5_point1 = (calib_data_backup[1] &
811 TSENS5_POINT1_MASK) >> TSENS5_POINT1_SHIFT;
812 tsens6_point1 = (calib_data_backup[1] &
813 TSENS6_POINT1_MASK) >> TSENS6_POINT1_SHIFT;
814 tsens7_point1 = (calib_data_backup[1] &
815 TSENS7_POINT1_MASK) >> TSENS7_POINT1_SHIFT;
816 tsens8_point1 = (calib_data_backup[2] &
817 TSENS8_POINT1_MASK_BACKUP) >>
818 TSENS8_POINT1_SHIFT;
819 tsens9_point1 = (calib_data_backup[2] &
820 TSENS9_POINT1_MASK_BACKUP) >>
821 TSENS9_POINT1_BACKUP_SHIFT;
822 tsens10_point1 = (calib_data_backup[2] &
823 TSENS10_POINT1_MASK_BACKUP) >>
824 TSENS10_POINT1_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700825 } else
826 goto calibration_less_mode;
827
828 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
829 pr_debug("backup two point calibrationless mode\n");
830 tsens_base2_data = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700831 TSENS_BASE2_BACKUP_MASK) >>
832 TSENS_POINT2_BASE_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700833 tsens0_point2 = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700834 TSENS0_POINT2_BACKUP_MASK) >>
835 TSENS0_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700836 tsens1_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700837 TSENS1_POINT2_BACKUP_MASK);
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700838 tsens2_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700839 TSENS2_POINT2_BACKUP_MASK) >>
840 TSENS2_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700841 tsens3_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700842 TSENS3_POINT2_BACKUP_MASK) >>
843 TSENS3_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700844 tsens4_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700845 TSENS4_POINT2_BACKUP_MASK) >>
846 TSENS4_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700847 tsens5_point2 = (calib_data[4] &
848 TSENS5_POINT2_BACKUP_MASK) >>
849 TSENS5_POINT2_BACKUP_SHIFT;
850 tsens6_point2 = (calib_data[5] &
851 TSENS6_POINT2_BACKUP_MASK);
852 tsens7_point2 = (calib_data[5] &
853 TSENS7_POINT2_BACKUP_MASK) >>
854 TSENS7_POINT2_BACKUP_SHIFT;
855 tsens8_point2 = (calib_data[5] &
856 TSENS8_POINT2_BACKUP_MASK) >>
857 TSENS8_POINT2_BACKUP_SHIFT;
858 tsens9_point2 = (calib_data[5] &
859 TSENS9_POINT2_BACKUP_MASK) >>
860 TSENS9_POINT2_BACKUP_SHIFT;
861 tsens10_point2 = (calib_data[5] &
862 TSENS10_POINT2_BACKUP_MASK)
863 >> TSENS10_POINT2_BACKUP_SHIFT;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700864 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700865 } else {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700866 tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
867 >> TSENS_CAL_SEL_SHIFT;
868 temp = (calib_data[3] & TSENS_CAL_SEL_2)
869 >> TSENS_CAL_SEL_SHIFT_2;
870 tsens_calibration_mode |= temp;
871 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) ||
872 (tsens_calibration_mode ==
873 TSENS_ONE_POINT_CALIB_OPTION_2) ||
874 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
875 pr_debug("TSENS is one point calibrationless mode\n");
876 tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
877 tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
878 TSENS0_POINT1_SHIFT;
879 tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
880 TSENS1_POINT1_SHIFT;
881 tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
882 TSENS2_POINT1_SHIFT;
883 tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
884 TSENS3_POINT1_SHIFT;
885 tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
886 tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
887 TSENS5_POINT1_SHIFT;
888 tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
889 TSENS6_POINT1_SHIFT;
890 tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
891 TSENS7_POINT1_SHIFT;
892 tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
893 TSENS8_POINT1_SHIFT;
894 tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
895 tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK)
896 >> TSENS10_POINT1_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700897 } else
898 goto calibration_less_mode;
899
900 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700901 pr_debug("TSENS is two point calibrationless mode\n");
902 tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
903 TSENS_POINT2_BASE_SHIFT;
904 tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
905 TSENS0_POINT2_SHIFT;
906 tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
907 TSENS1_POINT2_SHIFT;
908 tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
909 tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
910 TSENS3_POINT2_SHIFT;
911 tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
912 TSENS4_POINT2_SHIFT;
913 tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
914 TSENS5_POINT2_SHIFT;
915 tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
916 TSENS6_POINT2_SHIFT;
917 tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
918 tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
919 TSENS8_POINT2_SHIFT;
920 tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
921 TSENS9_POINT2_SHIFT;
922 tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK)
923 >> TSENS10_POINT2_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700924 }
925
926 if (tsens_calibration_mode == 0) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700927calibration_less_mode:
928 pr_debug("TSENS is calibrationless mode\n");
929 for (i = 0; i < tmdev->tsens_num_sensor; i++)
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700930 calib_tsens_point2_data[i] = 780;
931 calib_tsens_point1_data[0] = 502;
932 calib_tsens_point1_data[1] = 509;
933 calib_tsens_point1_data[2] = 503;
934 calib_tsens_point1_data[3] = 509;
935 calib_tsens_point1_data[4] = 505;
936 calib_tsens_point1_data[5] = 509;
937 calib_tsens_point1_data[6] = 507;
938 calib_tsens_point1_data[7] = 510;
939 calib_tsens_point1_data[8] = 508;
940 calib_tsens_point1_data[9] = 509;
941 calib_tsens_point1_data[10] = 508;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700942 goto compute_intercept_slope;
943 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700944 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700945
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700946 if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700947 pr_debug("old one point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700948 calib_tsens_point1_data[0] =
949 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
950 + tsens0_point1;
951 calib_tsens_point1_data[1] =
952 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
953 + tsens1_point1;
954 calib_tsens_point1_data[2] =
955 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
956 + tsens2_point1;
957 calib_tsens_point1_data[3] =
958 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
959 + tsens3_point1;
960 calib_tsens_point1_data[4] =
961 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
962 + tsens4_point1;
963 calib_tsens_point1_data[5] =
964 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
965 + tsens5_point1;
966 calib_tsens_point1_data[6] =
967 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
968 + tsens6_point1;
969 calib_tsens_point1_data[7] =
970 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
971 + tsens7_point1;
972 calib_tsens_point1_data[8] =
973 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
974 + tsens8_point1;
975 calib_tsens_point1_data[9] =
976 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
977 + tsens9_point1;
978 calib_tsens_point1_data[10] =
979 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
980 + tsens10_point1;
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700981 }
982
Siddartha Mohanadoss4d9815a2012-09-09 17:16:05 -0700983 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
984 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700985 pr_debug("one and two point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700986 calib_tsens_point1_data[0] =
987 ((((tsens_base1_data) + tsens0_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700988 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700989 calib_tsens_point1_data[1] =
990 ((((tsens_base1_data) + tsens1_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700991 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700992 calib_tsens_point1_data[2] =
993 ((((tsens_base1_data) + tsens2_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700994 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700995 calib_tsens_point1_data[3] =
996 ((((tsens_base1_data) + tsens3_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700997 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700998 calib_tsens_point1_data[4] =
999 ((((tsens_base1_data) + tsens4_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001000 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001001 calib_tsens_point1_data[5] =
1002 ((((tsens_base1_data) + tsens5_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001003 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001004 calib_tsens_point1_data[6] =
1005 ((((tsens_base1_data) + tsens6_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001006 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001007 calib_tsens_point1_data[7] =
1008 ((((tsens_base1_data) + tsens7_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001009 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001010 calib_tsens_point1_data[8] =
1011 ((((tsens_base1_data) + tsens8_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001012 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001013 calib_tsens_point1_data[9] =
1014 ((((tsens_base1_data) + tsens9_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001015 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001016 calib_tsens_point1_data[10] =
1017 ((((tsens_base1_data) + tsens10_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001018 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001019 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001020
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001021 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001022 pr_debug("two point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001023 calib_tsens_point2_data[0] =
1024 (((tsens_base2_data + tsens0_point2) << 2) |
1025 TSENS_BIT_APPEND);
1026 calib_tsens_point2_data[1] =
1027 (((tsens_base2_data + tsens1_point2) << 2) |
1028 TSENS_BIT_APPEND);
1029 calib_tsens_point2_data[2] =
1030 (((tsens_base2_data + tsens2_point2) << 2) |
1031 TSENS_BIT_APPEND);
1032 calib_tsens_point2_data[3] =
1033 (((tsens_base2_data + tsens3_point2) << 2) |
1034 TSENS_BIT_APPEND);
1035 calib_tsens_point2_data[4] =
1036 (((tsens_base2_data + tsens4_point2) << 2) |
1037 TSENS_BIT_APPEND);
1038 calib_tsens_point2_data[5] =
1039 (((tsens_base2_data + tsens5_point2) << 2) |
1040 TSENS_BIT_APPEND);
1041 calib_tsens_point2_data[6] =
1042 (((tsens_base2_data + tsens6_point2) << 2) |
1043 TSENS_BIT_APPEND);
1044 calib_tsens_point2_data[7] =
1045 (((tsens_base2_data + tsens7_point2) << 2) |
1046 TSENS_BIT_APPEND);
1047 calib_tsens_point2_data[8] =
1048 (((tsens_base2_data + tsens8_point2) << 2) |
1049 TSENS_BIT_APPEND);
1050 calib_tsens_point2_data[9] =
1051 (((tsens_base2_data + tsens9_point2) << 2) |
1052 TSENS_BIT_APPEND);
1053 calib_tsens_point2_data[10] =
1054 (((tsens_base2_data + tsens10_point2) << 2) |
1055 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001056 }
1057
1058compute_intercept_slope:
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001059 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1060 int32_t num = 0, den = 0;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001061 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
1062 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001063 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001064 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
1065 temp_120_degc - temp_30_degc (x2 - x1) */
1066 num = tmdev->sensor[i].calib_data_point2 -
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001067 tmdev->sensor[i].calib_data_point1;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001068 num *= tmdev->tsens_factor;
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001069 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001070 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001071 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001072 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
1073 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
1074 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001075 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
1076 tmdev->prev_reading_avail = false;
1077 }
1078
1079 return 0;
1080}
1081
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001082static int tsens_calib_sensors(void)
1083{
1084 int rc = 0;
1085
1086 if (!tmdev)
1087 return -ENODEV;
1088
1089 if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8974)
1090 rc = tsens_calib_8974_sensors();
1091 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
1092 rc = tsens_calib_8x26_sensors();
1093 else
1094 rc = -ENODEV;
1095
1096 return rc;
1097}
1098
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001099static int get_device_tree_data(struct platform_device *pdev)
1100{
1101 const struct device_node *of_node = pdev->dev.of_node;
1102 struct resource *res_mem = NULL;
1103 u32 *tsens_slope_data;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001104 u32 rc = 0, i, tsens_num_sensors, calib_type;
1105 const char *tsens_calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001106
1107 rc = of_property_read_u32(of_node,
1108 "qcom,sensors", &tsens_num_sensors);
1109 if (rc) {
1110 dev_err(&pdev->dev, "missing sensor number\n");
1111 return -ENODEV;
1112 }
1113
1114 tsens_slope_data = devm_kzalloc(&pdev->dev,
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001115 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001116 if (!tsens_slope_data) {
1117 dev_err(&pdev->dev, "can not allocate slope data\n");
1118 return -ENOMEM;
1119 }
1120
1121 rc = of_property_read_u32_array(of_node,
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001122 "qcom,slope", tsens_slope_data, tsens_num_sensors);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001123 if (rc) {
1124 dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
1125 return rc;
1126 };
1127
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001128 tsens_calib_mode = of_get_property(of_node,
1129 "qcom,calib-mode", NULL);
1130 if (!strncmp(tsens_calib_mode, "fuse_map1", 9))
1131 calib_type = TSENS_CALIB_FUSE_MAP_8974;
1132 else if (!strncmp(tsens_calib_mode, "fuse_map2", 9))
1133 calib_type = TSENS_CALIB_FUSE_MAP_8X26;
1134 else if (!strncmp(tsens_calib_mode, "fuse_map3", 9))
1135 calib_type = TSENS_CALIB_FUSE_MAP_8X10;
1136 else {
1137 pr_err("%s: Invalid calibration property\n", __func__);
1138 return -EINVAL;
1139 }
1140
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001141 tmdev = devm_kzalloc(&pdev->dev,
1142 sizeof(struct tsens_tm_device) +
1143 tsens_num_sensors *
1144 sizeof(struct tsens_tm_device_sensor),
1145 GFP_KERNEL);
1146 if (tmdev == NULL) {
1147 pr_err("%s: kzalloc() failed.\n", __func__);
1148 return -ENOMEM;
1149 }
1150
1151 for (i = 0; i < tsens_num_sensors; i++)
1152 tmdev->sensor[i].slope_mul_tsens_factor = tsens_slope_data[i];
1153 tmdev->tsens_factor = TSENS_SLOPE_FACTOR;
1154 tmdev->tsens_num_sensor = tsens_num_sensors;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001155 tmdev->calibration_less_mode = of_property_read_bool(of_node,
1156 "qcom,calibration-less-mode");
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001157 tmdev->calib_mode = calib_type;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001158
1159 tmdev->tsens_irq = platform_get_irq(pdev, 0);
1160 if (tmdev->tsens_irq < 0) {
1161 pr_err("Invalid get irq\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001162 rc = tmdev->tsens_irq;
1163 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001164 }
1165
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001166 /* TSENS register region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001167 tmdev->res_tsens_mem = platform_get_resource_byname(pdev,
1168 IORESOURCE_MEM, "tsens_physical");
1169 if (!tmdev->res_tsens_mem) {
1170 pr_err("Could not get tsens physical address resource\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001171 rc = -EINVAL;
1172 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001173 }
1174
1175 tmdev->tsens_len = tmdev->res_tsens_mem->end -
1176 tmdev->res_tsens_mem->start + 1;
1177
1178 res_mem = request_mem_region(tmdev->res_tsens_mem->start,
1179 tmdev->tsens_len, tmdev->res_tsens_mem->name);
1180 if (!res_mem) {
1181 pr_err("Request tsens physical memory region failed\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001182 rc = -EINVAL;
1183 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001184 }
1185
1186 tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
1187 if (!tmdev->tsens_addr) {
1188 pr_err("Failed to IO map TSENS registers.\n");
1189 rc = -EINVAL;
1190 goto fail_unmap_tsens_region;
1191 }
1192
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001193 /* TSENS calibration region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001194 tmdev->res_calib_mem = platform_get_resource_byname(pdev,
1195 IORESOURCE_MEM, "tsens_eeprom_physical");
1196 if (!tmdev->res_calib_mem) {
1197 pr_err("Could not get qfprom physical address resource\n");
1198 rc = -EINVAL;
1199 goto fail_unmap_tsens;
1200 }
1201
1202 tmdev->calib_len = tmdev->res_calib_mem->end -
1203 tmdev->res_calib_mem->start + 1;
1204
1205 res_mem = request_mem_region(tmdev->res_calib_mem->start,
1206 tmdev->calib_len, tmdev->res_calib_mem->name);
1207 if (!res_mem) {
1208 pr_err("Request calibration memory region failed\n");
1209 rc = -EINVAL;
1210 goto fail_unmap_tsens;
1211 }
1212
1213 tmdev->tsens_calib_addr = ioremap(res_mem->start,
1214 tmdev->calib_len);
1215 if (!tmdev->tsens_calib_addr) {
1216 pr_err("Failed to IO map EEPROM registers.\n");
1217 rc = -EINVAL;
1218 goto fail_unmap_calib_region;
1219 }
1220
1221 return 0;
1222
1223fail_unmap_calib_region:
1224 if (tmdev->res_calib_mem)
1225 release_mem_region(tmdev->res_calib_mem->start,
1226 tmdev->calib_len);
1227fail_unmap_tsens:
1228 if (tmdev->tsens_addr)
1229 iounmap(tmdev->tsens_addr);
1230fail_unmap_tsens_region:
1231 if (tmdev->res_tsens_mem)
1232 release_mem_region(tmdev->res_tsens_mem->start,
1233 tmdev->tsens_len);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001234fail_tmdev:
1235 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001236 return rc;
1237}
1238
1239static int __devinit tsens_tm_probe(struct platform_device *pdev)
1240{
1241 int rc;
1242
1243 if (tmdev) {
1244 pr_err("TSENS device already in use\n");
1245 return -EBUSY;
1246 }
1247
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001248 if (pdev->dev.of_node) {
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001249 rc = get_device_tree_data(pdev);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001250 if (rc) {
1251 pr_err("Error reading TSENS DT\n");
1252 return rc;
1253 }
1254 } else
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001255 return -ENODEV;
1256
1257 tmdev->pdev = pdev;
1258 rc = tsens_calib_sensors();
Michael Bohanb89167e2012-10-04 16:24:23 -07001259 if (rc < 0) {
1260 pr_err("Calibration failed\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001261 goto fail;
Michael Bohanb89167e2012-10-04 16:24:23 -07001262 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001263
1264 tsens_hw_init();
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001265
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001266 tmdev->prev_reading_avail = true;
1267
1268 platform_set_drvdata(pdev, tmdev);
1269
1270 return 0;
1271fail:
1272 if (tmdev->tsens_calib_addr)
1273 iounmap(tmdev->tsens_calib_addr);
1274 if (tmdev->res_calib_mem)
1275 release_mem_region(tmdev->res_calib_mem->start,
1276 tmdev->calib_len);
1277 if (tmdev->tsens_addr)
1278 iounmap(tmdev->tsens_addr);
1279 if (tmdev->res_tsens_mem)
1280 release_mem_region(tmdev->res_tsens_mem->start,
1281 tmdev->tsens_len);
Michael Bohanb89167e2012-10-04 16:24:23 -07001282 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001283
1284 return rc;
1285}
1286
1287static int __devinit _tsens_register_thermal(void)
1288{
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001289 struct platform_device *pdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001290 int rc, i;
1291
1292 if (!tmdev) {
1293 pr_err("%s: TSENS early init not done\n", __func__);
1294 return -ENODEV;
1295 }
1296
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001297 pdev = tmdev->pdev;
1298
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001299 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1300 char name[18];
1301 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
1302 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
1303 tmdev->sensor[i].sensor_num = i;
1304 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
1305 TSENS_TRIP_NUM, &tmdev->sensor[i],
1306 &tsens_thermal_zone_ops, 0, 0, 0, 0);
1307 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
1308 pr_err("%s: thermal_zone_device_register() failed.\n",
1309 __func__);
1310 rc = -ENODEV;
1311 goto fail;
1312 }
1313 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001314
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001315 rc = request_irq(tmdev->tsens_irq, tsens_isr,
1316 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
1317 if (rc < 0) {
1318 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
1319 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1320 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1321 goto fail;
Siddartha Mohanadossb9be9812013-02-13 11:03:32 -08001322 } else {
1323 enable_irq_wake(tmdev->tsens_irq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001324 }
1325 platform_set_drvdata(pdev, tmdev);
1326
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -07001327 INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
1328
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001329 return 0;
1330fail:
1331 if (tmdev->tsens_calib_addr)
1332 iounmap(tmdev->tsens_calib_addr);
1333 if (tmdev->res_calib_mem)
1334 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001335 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001336 if (tmdev->tsens_addr)
1337 iounmap(tmdev->tsens_addr);
1338 if (tmdev->res_tsens_mem)
1339 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001340 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001341 return rc;
1342}
1343
1344static int __devexit tsens_tm_remove(struct platform_device *pdev)
1345{
1346 struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
1347 int i;
1348
1349 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1350 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1351 if (tmdev->tsens_calib_addr)
1352 iounmap(tmdev->tsens_calib_addr);
1353 if (tmdev->res_calib_mem)
1354 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001355 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001356 if (tmdev->tsens_addr)
1357 iounmap(tmdev->tsens_addr);
1358 if (tmdev->res_tsens_mem)
1359 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001360 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001361 free_irq(tmdev->tsens_irq, tmdev);
1362 platform_set_drvdata(pdev, NULL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001363
1364 return 0;
1365}
1366
1367static struct of_device_id tsens_match[] = {
1368 { .compatible = "qcom,msm-tsens",
1369 },
1370 {}
1371};
1372
1373static struct platform_driver tsens_tm_driver = {
1374 .probe = tsens_tm_probe,
1375 .remove = tsens_tm_remove,
1376 .driver = {
1377 .name = "msm-tsens",
1378 .owner = THIS_MODULE,
1379 .of_match_table = tsens_match,
1380 },
1381};
1382
1383static int __init tsens_tm_init_driver(void)
1384{
1385 return platform_driver_register(&tsens_tm_driver);
1386}
1387arch_initcall(tsens_tm_init_driver);
1388
1389static int __init tsens_thermal_register(void)
1390{
1391 return _tsens_register_thermal();
1392}
1393module_init(tsens_thermal_register);
1394
1395static void __exit _tsens_tm_remove(void)
1396{
1397 platform_driver_unregister(&tsens_tm_driver);
1398}
1399module_exit(_tsens_tm_remove);
1400
1401MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
1402MODULE_LICENSE("GPL v2");