blob: 7d3664a7a749d436496504af5fcf7218dc803d6e [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
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -070057#define TSENS_62_5_MS_MEAS_PERIOD 1
Siddartha Mohanadossa0d74c62012-10-23 10:38:41 -070058#define TSENS_312_5_MS_MEAS_PERIOD 2
59#define TSENS_MEAS_PERIOD_SHIFT 18
60
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070061#define TSENS_SN_MIN_MAX_STATUS_CTRL(n) ((n) + 4)
62#define TSENS_GLOBAL_CONFIG(n) ((n) + 0x34)
63#define TSENS_S0_MAIN_CONFIG(n) ((n) + 0x38)
64#define TSENS_SN_REMOTE_CONFIG(n) ((n) + 0x3c)
65
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070066#define TSENS_EEPROM(n) ((n) + 0xd0)
Siddartha Mohanadoss49741992013-02-22 10:30:04 -080067#define TSENS_EEPROM_REDUNDANCY_SEL(n) ((n) + 0x444)
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070068#define TSENS_EEPROM_BACKUP_REGION(n) ((n) + 0x440)
69
70#define TSENS_MAIN_CALIB_ADDR_RANGE 6
71#define TSENS_BACKUP_CALIB_ADDR_RANGE 4
72
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -080073#define TSENS_EEPROM_8X26_1(n) ((n) + 0x1c0)
74#define TSENS_EEPROM_8X26_2(n) ((n) + 0x444)
75#define TSENS_8X26_MAIN_CALIB_ADDR_RANGE 4
76
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070077/* TSENS calibration Mask data */
78#define TSENS_BASE1_MASK 0xff
79#define TSENS0_POINT1_MASK 0x3f00
80#define TSENS1_POINT1_MASK 0xfc000
81#define TSENS2_POINT1_MASK 0x3f00000
82#define TSENS3_POINT1_MASK 0xfc000000
83#define TSENS4_POINT1_MASK 0x3f
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070084#define TSENS5_POINT1_MASK 0xfc0
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070085#define TSENS6_POINT1_MASK 0x3f000
86#define TSENS7_POINT1_MASK 0xfc0000
87#define TSENS8_POINT1_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070088#define TSENS8_POINT1_MASK_BACKUP 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070089#define TSENS9_POINT1_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070090#define TSENS9_POINT1_MASK_BACKUP 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -080091#define TSENS10_POINT1_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070092#define TSENS10_POINT1_MASK_BACKUP 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070093#define TSENS_CAL_SEL_0_1 0xc0000000
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070094#define TSENS_CAL_SEL_2 0x40000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070095#define TSENS_CAL_SEL_SHIFT 30
96#define TSENS_CAL_SEL_SHIFT_2 28
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070097#define TSENS_ONE_POINT_CALIB 0x1
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -070098#define TSENS_ONE_POINT_CALIB_OPTION_2 0x2
99#define TSENS_TWO_POINT_CALIB 0x3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700100
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700101#define TSENS0_POINT1_SHIFT 8
102#define TSENS1_POINT1_SHIFT 14
103#define TSENS2_POINT1_SHIFT 20
104#define TSENS3_POINT1_SHIFT 26
105#define TSENS5_POINT1_SHIFT 6
106#define TSENS6_POINT1_SHIFT 12
107#define TSENS7_POINT1_SHIFT 18
108#define TSENS8_POINT1_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700109#define TSENS9_POINT1_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700110#define TSENS10_POINT1_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700111#define TSENS10_POINT1_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700112
113#define TSENS_POINT2_BASE_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700114#define TSENS_POINT2_BASE_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700115#define TSENS0_POINT2_SHIFT 20
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700116#define TSENS0_POINT2_BACKUP_SHIFT 26
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700117#define TSENS1_POINT2_SHIFT 26
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700118#define TSENS2_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700119#define TSENS3_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700120#define TSENS3_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700121#define TSENS4_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700122#define TSENS4_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700123#define TSENS5_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700124#define TSENS5_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700125#define TSENS6_POINT2_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700126#define TSENS7_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700127#define TSENS8_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700128#define TSENS8_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700129#define TSENS9_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700130#define TSENS9_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700131#define TSENS10_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700132#define TSENS10_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700133
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700134#define TSENS_BASE2_MASK 0xff000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700135#define TSENS_BASE2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700136#define TSENS0_POINT2_MASK 0x3f00000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700137#define TSENS0_POINT2_BACKUP_MASK 0xfc000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700138#define TSENS1_POINT2_MASK 0xfc000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700139#define TSENS1_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700140#define TSENS2_POINT2_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700141#define TSENS2_POINT2_BACKUP_MASK 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800142#define TSENS3_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700143#define TSENS3_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700144#define TSENS4_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700145#define TSENS4_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700146#define TSENS5_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700147#define TSENS5_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700148#define TSENS6_POINT2_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700149#define TSENS6_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700150#define TSENS7_POINT2_MASK 0x3f
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800151#define TSENS7_POINT2_BACKUP_MASK 0xfc0
152#define TSENS8_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700153#define TSENS8_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700154#define TSENS9_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700155#define TSENS9_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700156#define TSENS10_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700157#define TSENS10_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700158
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800159#define TSENS_8X26_BASE0_MASK 0x1fe000
160#define TSENS0_8X26_POINT1_MASK 0x7f00000
161#define TSENS1_8X26_POINT1_MASK 0x3f
162#define TSENS2_8X26_POINT1_MASK 0xfc0
163#define TSENS3_8X26_POINT1_MASK 0x3f000
164#define TSENS4_8X26_POINT1_MASK 0xfc0000
165#define TSENS5_8X26_POINT1_MASK 0x3f000000
166#define TSENS6_8X26_POINT1_MASK 0x3f00000
167#define TSENS_8X26_TSENS_CAL_SEL 0xe0000000
168#define TSENS_8X26_BASE1_MASK 0xff
169#define TSENS0_8X26_POINT2_MASK 0x3f00
170#define TSENS1_8X26_POINT2_MASK 0xfc00
171#define TSENS2_8X26_POINT2_MASK 0x3f00000
172#define TSENS3_8X26_POINT2_MASK 0xfc000000
173#define TSENS4_8X26_POINT2_MASK 0xfc000000
174#define TSENS5_8X26_POINT2_MASK 0x3f00000
175#define TSENS6_8X26_POINT2_MASK 0x7e0000
176
177#define TSENS_8X26_CAL_SEL_SHIFT 29
178#define TSENS_8X26_BASE0_SHIFT 13
179#define TSENS0_8X26_POINT1_SHIFT 21
180#define TSENS2_8X26_POINT1_SHIFT 6
181#define TSENS3_8X26_POINT1_SHIFT 12
182#define TSENS4_8X26_POINT1_SHIFT 18
183#define TSENS5_8X26_POINT1_SHIFT 24
184#define TSENS6_8X26_POINT1_SHIFT 20
185
186#define TSENS0_8X26_POINT2_SHIFT 8
187#define TSENS1_8X26_POINT2_SHIFT 14
188#define TSENS2_8X26_POINT2_SHIFT 20
189#define TSENS3_8X26_POINT2_SHIFT 26
190#define TSENS4_8X26_POINT2_SHIFT 20
191#define TSENS5_8X26_POINT2_SHIFT 26
192#define TSENS6_8X26_POINT2_SHIFT 17
193
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700194#define TSENS_BIT_APPEND 0x3
195#define TSENS_CAL_DEGC_POINT1 30
196#define TSENS_CAL_DEGC_POINT2 120
197#define TSENS_SLOPE_FACTOR 1000
198
199/* TSENS register data */
200#define TSENS_TRDY_RDY_MIN_TIME 2000
201#define TSENS_TRDY_RDY_MAX_TIME 2100
202#define TSENS_THRESHOLD_MAX_CODE 0x3ff
203#define TSENS_THRESHOLD_MIN_CODE 0x0
204
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700205#define TSENS_GLOBAL_INIT_DATA 0x302f16c
206#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700207#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700208#define TSENS_SN_REMOTE_CFG_DATA 0x11c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700209
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700210#define TSENS_QFPROM_BACKUP_SEL 0x3
211#define TSENS_QFPROM_BACKUP_REDUN_SEL 0xe0000000
212#define TSENS_QFPROM_BACKUP_REDUN_SHIFT 29
213
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800214enum tsens_calib_fuse_map_type {
215 TSENS_CALIB_FUSE_MAP_8974 = 0,
216 TSENS_CALIB_FUSE_MAP_8X26,
217 TSENS_CALIB_FUSE_MAP_8X10,
218 TSENS_CALIB_FUSE_MAP_NUM,
219};
220
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700221/* Trips: warm and cool */
222enum tsens_trip_type {
223 TSENS_TRIP_WARM = 0,
224 TSENS_TRIP_COOL,
225 TSENS_TRIP_NUM,
226};
227
228struct tsens_tm_device_sensor {
229 struct thermal_zone_device *tz_dev;
230 enum thermal_device_mode mode;
231 unsigned int sensor_num;
232 struct work_struct work;
233 int offset;
234 int calib_data_point1;
235 int calib_data_point2;
236 uint32_t slope_mul_tsens_factor;
237};
238
239struct tsens_tm_device {
240 struct platform_device *pdev;
241 bool prev_reading_avail;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -0700242 bool calibration_less_mode;
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700243 bool tsens_local_init;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700244 int tsens_factor;
245 uint32_t tsens_num_sensor;
246 int tsens_irq;
247 void *tsens_addr;
248 void *tsens_calib_addr;
249 int tsens_len;
250 int calib_len;
251 struct resource *res_tsens_mem;
252 struct resource *res_calib_mem;
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700253 struct work_struct tsens_work;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800254 uint32_t calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700255 struct tsens_tm_device_sensor sensor[0];
256};
257
258struct tsens_tm_device *tmdev;
259
260static int tsens_tz_code_to_degc(int adc_code, int sensor_num)
261{
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700262 int degc, num, den;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700263
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700264 num = ((adc_code * tmdev->tsens_factor) -
265 tmdev->sensor[sensor_num].offset);
266 den = (int) tmdev->sensor[sensor_num].slope_mul_tsens_factor;
267 degc = num/den;
268
269 if ((degc >= 0) && (num % den != 0))
270 degc++;
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -0700271
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700272 return degc;
273}
274
275static int tsens_tz_degc_to_code(int degc, int sensor_num)
276{
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -0700277 int code = ((degc * tmdev->sensor[sensor_num].slope_mul_tsens_factor)
278 + tmdev->sensor[sensor_num].offset)/tmdev->tsens_factor;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700279
280 if (code > TSENS_THRESHOLD_MAX_CODE)
281 code = TSENS_THRESHOLD_MAX_CODE;
282 else if (code < TSENS_THRESHOLD_MIN_CODE)
283 code = TSENS_THRESHOLD_MIN_CODE;
284 return code;
285}
286
287static void msm_tsens_get_temp(int sensor_num, unsigned long *temp)
288{
289 unsigned int code, sensor_addr;
290
291 if (!tmdev->prev_reading_avail) {
292 while (!(readl_relaxed(TSENS_TRDY_ADDR(tmdev->tsens_addr))
293 & TSENS_TRDY_MASK))
294 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
295 TSENS_TRDY_RDY_MAX_TIME);
296 tmdev->prev_reading_avail = true;
297 }
298
299 sensor_addr =
300 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
301 code = readl_relaxed(sensor_addr +
302 (sensor_num << TSENS_STATUS_ADDR_OFFSET));
303 *temp = tsens_tz_code_to_degc((code & TSENS_SN_STATUS_TEMP_MASK),
304 sensor_num);
305}
306
307static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
308 unsigned long *temp)
309{
310 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
311
312 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
313 return -EINVAL;
314
315 msm_tsens_get_temp(tm_sensor->sensor_num, temp);
316
317 return 0;
318}
319
320int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
321{
322 if (!tmdev)
323 return -ENODEV;
324
325 msm_tsens_get_temp(device->sensor_num, temp);
326
327 return 0;
328}
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700329EXPORT_SYMBOL(tsens_get_temp);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700330
331static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
332 enum thermal_device_mode *mode)
333{
334 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
335
336 if (!tm_sensor || !mode)
337 return -EINVAL;
338
339 *mode = tm_sensor->mode;
340
341 return 0;
342}
343
344static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
345 int trip, enum thermal_trip_type *type)
346{
347 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
348
349 if (!tm_sensor || trip < 0 || !type)
350 return -EINVAL;
351
352 switch (trip) {
353 case TSENS_TRIP_WARM:
354 *type = THERMAL_TRIP_CONFIGURABLE_HI;
355 break;
356 case TSENS_TRIP_COOL:
357 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
358 break;
359 default:
360 return -EINVAL;
361 }
362
363 return 0;
364}
365
366static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
367 int trip, enum thermal_trip_activation_mode mode)
368{
369 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
370 unsigned int reg_cntl, code, hi_code, lo_code, mask;
371
372 if (!tm_sensor || trip < 0)
373 return -EINVAL;
374
375 lo_code = TSENS_THRESHOLD_MIN_CODE;
376 hi_code = TSENS_THRESHOLD_MAX_CODE;
377
378 reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
379 (tmdev->tsens_addr) +
380 (tm_sensor->sensor_num * 4)));
381 switch (trip) {
382 case TSENS_TRIP_WARM:
383 code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
384 >> TSENS_UPPER_THRESHOLD_SHIFT;
385 mask = TSENS_UPPER_STATUS_CLR;
386
387 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
388 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
389 break;
390 case TSENS_TRIP_COOL:
391 code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
392 mask = TSENS_LOWER_STATUS_CLR;
393
394 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
395 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
396 >> TSENS_UPPER_THRESHOLD_SHIFT;
397 break;
398 default:
399 return -EINVAL;
400 }
401
402 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
403 writel_relaxed(reg_cntl | mask,
404 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
405 (tmdev->tsens_addr) +
406 (tm_sensor->sensor_num * 4)));
407 else {
408 if (code < lo_code || code > hi_code) {
409 pr_err("%s with invalid code %x\n", __func__, code);
410 return -EINVAL;
411 }
412 writel_relaxed(reg_cntl & ~mask,
413 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr) +
414 (tm_sensor->sensor_num * 4)));
415 }
416 mb();
417 return 0;
418}
419
420static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
421 int trip, unsigned long *temp)
422{
423 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
424 unsigned int reg;
425
426 if (!tm_sensor || trip < 0 || !temp)
427 return -EINVAL;
428
429 reg = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
430 (tmdev->tsens_addr) +
431 (tm_sensor->sensor_num * TSENS_SN_ADDR_OFFSET));
432 switch (trip) {
433 case TSENS_TRIP_WARM:
434 reg = (reg & TSENS_UPPER_THRESHOLD_MASK) >>
435 TSENS_UPPER_THRESHOLD_SHIFT;
436 break;
437 case TSENS_TRIP_COOL:
438 reg = (reg & TSENS_LOWER_THRESHOLD_MASK);
439 break;
440 default:
441 return -EINVAL;
442 }
443
444 *temp = tsens_tz_code_to_degc(reg, tm_sensor->sensor_num);
445
446 return 0;
447}
448
449static int tsens_tz_notify(struct thermal_zone_device *thermal,
450 int count, enum thermal_trip_type type)
451{
452 /* TSENS driver does not shutdown the device.
453 All Thermal notification are sent to the
454 thermal daemon to take appropriate action */
455 pr_debug("%s debug\n", __func__);
456 return 1;
457}
458
459static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
460 int trip, long temp)
461{
462 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
463 unsigned int reg_cntl;
464 int code, hi_code, lo_code, code_err_chk;
465
466 code_err_chk = code = tsens_tz_degc_to_code(temp,
467 tm_sensor->sensor_num);
468 if (!tm_sensor || trip < 0)
469 return -EINVAL;
470
471 lo_code = TSENS_THRESHOLD_MIN_CODE;
472 hi_code = TSENS_THRESHOLD_MAX_CODE;
473
474 reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
475 (tmdev->tsens_addr) +
476 (tm_sensor->sensor_num * TSENS_SN_ADDR_OFFSET));
477 switch (trip) {
478 case TSENS_TRIP_WARM:
479 code <<= TSENS_UPPER_THRESHOLD_SHIFT;
480 reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
481 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
482 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
483 break;
484 case TSENS_TRIP_COOL:
485 reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
486 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
487 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
488 >> TSENS_UPPER_THRESHOLD_SHIFT;
489 break;
490 default:
491 return -EINVAL;
492 }
493
494 if (code_err_chk < lo_code || code_err_chk > hi_code)
495 return -EINVAL;
496
497 writel_relaxed(reg_cntl | code, (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
498 (tmdev->tsens_addr) +
499 (tm_sensor->sensor_num *
500 TSENS_SN_ADDR_OFFSET)));
501 mb();
502 return 0;
503}
504
505static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
506 .get_temp = tsens_tz_get_temp,
507 .get_mode = tsens_tz_get_mode,
508 .get_trip_type = tsens_tz_get_trip_type,
509 .activate_trip_type = tsens_tz_activate_trip_type,
510 .get_trip_temp = tsens_tz_get_trip_temp,
511 .set_trip_temp = tsens_tz_set_trip_temp,
512 .notify = tsens_tz_notify,
513};
514
515static void notify_uspace_tsens_fn(struct work_struct *work)
516{
517 struct tsens_tm_device_sensor *tm = container_of(work,
518 struct tsens_tm_device_sensor, work);
519
520 sysfs_notify(&tm->tz_dev->device.kobj,
521 NULL, "type");
522}
523
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700524static void tsens_scheduler_fn(struct work_struct *work)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700525{
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700526 struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
527 tsens_work);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700528 unsigned int i, status, threshold;
529 unsigned int sensor_status_addr, sensor_status_ctrl_addr;
530
531 sensor_status_addr =
532 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
533 sensor_status_ctrl_addr =
534 (unsigned int)TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
535 (tmdev->tsens_addr);
536 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
537 bool upper_thr = false, lower_thr = false;
538 status = readl_relaxed(sensor_status_addr);
539 threshold = readl_relaxed(sensor_status_ctrl_addr);
540 if (status & TSENS_SN_STATUS_UPPER_STATUS) {
541 writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
542 sensor_status_ctrl_addr);
543 upper_thr = true;
544 }
545 if (status & TSENS_SN_STATUS_LOWER_STATUS) {
546 writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
547 sensor_status_ctrl_addr);
548 lower_thr = true;
549 }
550 if (upper_thr || lower_thr) {
551 /* Notify user space */
552 schedule_work(&tm->sensor[i].work);
553 pr_debug("sensor:%d trigger temp (%d degC)\n", i,
554 tsens_tz_code_to_degc((status &
555 TSENS_SN_STATUS_TEMP_MASK), i));
556 }
557 sensor_status_addr += TSENS_SN_ADDR_OFFSET;
558 sensor_status_ctrl_addr += TSENS_SN_ADDR_OFFSET;
559 }
560 mb();
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700561}
562
563static irqreturn_t tsens_isr(int irq, void *data)
564{
565 schedule_work(&tmdev->tsens_work);
566
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700567 return IRQ_HANDLED;
568}
569
570static void tsens_hw_init(void)
571{
572 unsigned int reg_cntl = 0;
573 unsigned int i;
574
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700575 if (tmdev->tsens_local_init) {
576 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
577 writel_relaxed(reg_cntl | TSENS_SW_RST,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700578 TSENS_CTRL_ADDR(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700579 reg_cntl |= ((TSENS_62_5_MS_MEAS_PERIOD <<
580 TSENS_MEAS_PERIOD_SHIFT) |
Siddartha Mohanadossa0d74c62012-10-23 10:38:41 -0700581 (((1 << tmdev->tsens_num_sensor) - 1) << TSENS_SENSOR0_SHIFT) |
582 TSENS_EN);
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700583 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
584 writel_relaxed(TSENS_GLOBAL_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700585 TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700586 writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700587 TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700588 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
589 writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700590 TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
591 + (i * TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700592 writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700593 TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
594 + (i * TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700595 }
596 pr_debug("Local TSENS control initialization\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700597 }
598 writel_relaxed(TSENS_INTERRUPT_EN,
599 TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
600}
601
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800602static int tsens_calib_8x26_sensors(void)
603{
604 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
605 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
606 int tsens5_point1 = 0, tsens6_point1 = 0, tsens6_point2 = 0;
607 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
608 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
609 int tsens_base1_data = 0, tsens_calibration_mode = 0;
610 uint32_t calib_data[6];
611 uint32_t calib_tsens_point1_data[7], calib_tsens_point2_data[7];
612
613 if (tmdev->calibration_less_mode)
614 goto calibration_less_mode;
615
616 for (i = 0; i < TSENS_8X26_MAIN_CALIB_ADDR_RANGE; i++)
617 calib_data[i] = readl_relaxed(
618 (TSENS_EEPROM_8X26_1(tmdev->tsens_calib_addr))
619 + (i * TSENS_SN_ADDR_OFFSET));
620 calib_data[4] = readl_relaxed(
621 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)));
622 calib_data[5] = readl_relaxed(
623 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
624
Siddartha Mohanadoss2114b2d2013-03-07 17:43:00 -0800625 tsens_calibration_mode = (calib_data[5] & TSENS_8X26_TSENS_CAL_SEL)
626 >> TSENS_8X26_CAL_SEL_SHIFT;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800627
628 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
629 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
630 pr_debug("backup one point calibrationless mode\n");
631 tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
632 >> TSENS_8X26_BASE0_SHIFT;
633 tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
634 TSENS0_8X26_POINT1_SHIFT;
635 tsens1_point1 = calib_data[1] & TSENS1_8X26_POINT1_MASK;
636 tsens2_point1 = (calib_data[1] & TSENS2_8X26_POINT1_MASK) >>
637 TSENS2_8X26_POINT1_SHIFT;
638 tsens3_point1 = (calib_data[1] & TSENS3_8X26_POINT1_MASK) >>
639 TSENS3_8X26_POINT1_SHIFT;
640 tsens4_point1 = (calib_data[1] & TSENS4_8X26_POINT1_MASK) >>
641 TSENS4_8X26_POINT1_SHIFT;
642 tsens5_point1 = (calib_data[1] & TSENS5_8X26_POINT1_MASK) >>
643 TSENS5_8X26_POINT1_SHIFT;
644 tsens6_point1 = (calib_data[2] & TSENS6_8X26_POINT1_MASK) >>
645 TSENS6_8X26_POINT1_SHIFT;
646 } else
647 goto calibration_less_mode;
648
649 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
650 pr_debug("backup two point calibrationless mode\n");
651 tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
652 tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
653 TSENS0_8X26_POINT2_SHIFT;
654 tsens1_point2 = (calib_data[3] & TSENS1_8X26_POINT2_MASK) >>
655 TSENS1_8X26_POINT2_SHIFT;
656 tsens2_point2 = (calib_data[3] & TSENS2_8X26_POINT2_MASK) >>
657 TSENS2_8X26_POINT2_SHIFT;
658 tsens3_point2 = (calib_data[3] & TSENS3_8X26_POINT2_MASK) >>
659 TSENS3_8X26_POINT2_SHIFT;
660 tsens4_point2 = (calib_data[4] & TSENS4_8X26_POINT2_MASK) >>
661 TSENS4_8X26_POINT2_SHIFT;
662 tsens5_point2 = (calib_data[4] & TSENS5_8X26_POINT2_MASK) >>
663 TSENS5_8X26_POINT2_SHIFT;
664 tsens6_point2 = (calib_data[5] & TSENS6_8X26_POINT2_MASK) >>
665 TSENS6_8X26_POINT2_SHIFT;
666 }
667
668 if (tsens_calibration_mode == 0) {
669calibration_less_mode:
670 pr_debug("TSENS is calibrationless mode\n");
671 for (i = 0; i < tmdev->tsens_num_sensor; i++)
672 calib_tsens_point2_data[i] = 780;
673 calib_tsens_point1_data[0] = 502;
674 calib_tsens_point1_data[1] = 509;
675 calib_tsens_point1_data[2] = 503;
676 calib_tsens_point1_data[3] = 509;
677 calib_tsens_point1_data[4] = 505;
678 calib_tsens_point1_data[5] = 509;
679 calib_tsens_point1_data[6] = 507;
680 goto compute_intercept_slope;
681 }
682
683 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
684 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
685 pr_debug("one and two point calibration calculation\n");
686 calib_tsens_point1_data[0] =
687 ((((tsens_base0_data) + tsens0_point1) << 2) |
688 TSENS_BIT_APPEND);
689 calib_tsens_point1_data[1] =
690 ((((tsens_base0_data) + tsens1_point1) << 2) |
691 TSENS_BIT_APPEND);
692 calib_tsens_point1_data[2] =
693 ((((tsens_base0_data) + tsens2_point1) << 2) |
694 TSENS_BIT_APPEND);
695 calib_tsens_point1_data[3] =
696 ((((tsens_base0_data) + tsens3_point1) << 2) |
697 TSENS_BIT_APPEND);
698 calib_tsens_point1_data[4] =
699 ((((tsens_base0_data) + tsens4_point1) << 2) |
700 TSENS_BIT_APPEND);
701 calib_tsens_point1_data[5] =
702 ((((tsens_base0_data) + tsens5_point1) << 2) |
703 TSENS_BIT_APPEND);
704 calib_tsens_point1_data[6] =
705 ((((tsens_base0_data) + tsens6_point1) << 2) |
706 TSENS_BIT_APPEND);
707 }
708
709 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
710 pr_debug("two point calibration calculation\n");
711 calib_tsens_point2_data[0] =
712 (((tsens_base1_data + tsens0_point2) << 2) |
713 TSENS_BIT_APPEND);
714 calib_tsens_point2_data[1] =
715 (((tsens_base1_data + tsens1_point2) << 2) |
716 TSENS_BIT_APPEND);
717 calib_tsens_point2_data[2] =
718 (((tsens_base1_data + tsens2_point2) << 2) |
719 TSENS_BIT_APPEND);
720 calib_tsens_point2_data[3] =
721 (((tsens_base1_data + tsens3_point2) << 2) |
722 TSENS_BIT_APPEND);
723 calib_tsens_point2_data[4] =
724 (((tsens_base1_data + tsens4_point2) << 2) |
725 TSENS_BIT_APPEND);
726 calib_tsens_point2_data[5] =
727 (((tsens_base1_data + tsens5_point2) << 2) |
728 TSENS_BIT_APPEND);
729 calib_tsens_point2_data[6] =
730 (((tsens_base1_data + tsens6_point2) << 2) |
731 TSENS_BIT_APPEND);
732 }
733
734compute_intercept_slope:
735 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
736 int32_t num = 0, den = 0;
737 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
738 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
739 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
740 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
741 temp_120_degc - temp_30_degc (x2 - x1) */
742 num = tmdev->sensor[i].calib_data_point2 -
743 tmdev->sensor[i].calib_data_point1;
744 num *= tmdev->tsens_factor;
745 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
746 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
747 }
748 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
749 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
750 tmdev->sensor[i].slope_mul_tsens_factor);
751 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
752 tmdev->prev_reading_avail = false;
753 }
754
755 return 0;
756}
757
758static int tsens_calib_8974_sensors(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700759{
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700760 int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
761 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
762 int tsens5_point1 = 0, tsens6_point1 = 0, tsens7_point1 = 0;
763 int tsens8_point1 = 0, tsens9_point1 = 0, tsens10_point1 = 0;
764 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
765 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
766 int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
767 int tsens9_point2 = 0, tsens10_point2 = 0;
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700768 int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700769 uint32_t calib_data[6], calib_redun_sel, calib_data_backup[4];
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700770 uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11];
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700771
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -0700772 if (tmdev->calibration_less_mode)
773 goto calibration_less_mode;
774
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700775 calib_redun_sel = readl_relaxed(
776 TSENS_EEPROM_REDUNDANCY_SEL(tmdev->tsens_calib_addr));
777 calib_redun_sel = calib_redun_sel & TSENS_QFPROM_BACKUP_REDUN_SEL;
778 calib_redun_sel >>= TSENS_QFPROM_BACKUP_REDUN_SHIFT;
779
780 for (i = 0; i < TSENS_MAIN_CALIB_ADDR_RANGE; i++)
781 calib_data[i] = readl_relaxed(
782 (TSENS_EEPROM(tmdev->tsens_calib_addr))
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700783 + (i * TSENS_SN_ADDR_OFFSET));
784
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700785 if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) {
786 tsens_calibration_mode = (calib_data[4] & TSENS_CAL_SEL_0_1)
787 >> TSENS_CAL_SEL_SHIFT;
788 temp = (calib_data[5] & TSENS_CAL_SEL_2)
789 >> TSENS_CAL_SEL_SHIFT_2;
790 tsens_calibration_mode |= temp;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700791
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700792 for (i = 0; i < TSENS_BACKUP_CALIB_ADDR_RANGE; i++)
793 calib_data_backup[i] = readl_relaxed(
794 (TSENS_EEPROM_BACKUP_REGION(
795 tmdev->tsens_calib_addr))
796 + (i * TSENS_SN_ADDR_OFFSET));
797
798 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB)
799 || (tsens_calibration_mode ==
800 TSENS_TWO_POINT_CALIB) ||
801 (tsens_calibration_mode ==
802 TSENS_ONE_POINT_CALIB_OPTION_2)) {
803 pr_debug("backup one point calibrationless mode\n");
804 tsens_base1_data = (calib_data_backup[0] &
805 TSENS_BASE1_MASK);
806 tsens0_point1 = (calib_data_backup[0] &
807 TSENS0_POINT1_MASK) >>
808 TSENS0_POINT1_SHIFT;
809 tsens1_point1 = (calib_data_backup[0] &
810 TSENS1_POINT1_MASK) >> TSENS1_POINT1_SHIFT;
811 tsens2_point1 = (calib_data_backup[0] &
812 TSENS2_POINT1_MASK) >> TSENS2_POINT1_SHIFT;
813 tsens3_point1 = (calib_data_backup[0] &
814 TSENS3_POINT1_MASK) >> TSENS3_POINT1_SHIFT;
815 tsens4_point1 = (calib_data_backup[1] &
816 TSENS4_POINT1_MASK);
817 tsens5_point1 = (calib_data_backup[1] &
818 TSENS5_POINT1_MASK) >> TSENS5_POINT1_SHIFT;
819 tsens6_point1 = (calib_data_backup[1] &
820 TSENS6_POINT1_MASK) >> TSENS6_POINT1_SHIFT;
821 tsens7_point1 = (calib_data_backup[1] &
822 TSENS7_POINT1_MASK) >> TSENS7_POINT1_SHIFT;
823 tsens8_point1 = (calib_data_backup[2] &
824 TSENS8_POINT1_MASK_BACKUP) >>
825 TSENS8_POINT1_SHIFT;
826 tsens9_point1 = (calib_data_backup[2] &
827 TSENS9_POINT1_MASK_BACKUP) >>
828 TSENS9_POINT1_BACKUP_SHIFT;
829 tsens10_point1 = (calib_data_backup[2] &
830 TSENS10_POINT1_MASK_BACKUP) >>
831 TSENS10_POINT1_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700832 } else
833 goto calibration_less_mode;
834
835 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
836 pr_debug("backup two point calibrationless mode\n");
837 tsens_base2_data = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700838 TSENS_BASE2_BACKUP_MASK) >>
839 TSENS_POINT2_BASE_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700840 tsens0_point2 = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700841 TSENS0_POINT2_BACKUP_MASK) >>
842 TSENS0_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700843 tsens1_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700844 TSENS1_POINT2_BACKUP_MASK);
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700845 tsens2_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700846 TSENS2_POINT2_BACKUP_MASK) >>
847 TSENS2_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700848 tsens3_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700849 TSENS3_POINT2_BACKUP_MASK) >>
850 TSENS3_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700851 tsens4_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700852 TSENS4_POINT2_BACKUP_MASK) >>
853 TSENS4_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700854 tsens5_point2 = (calib_data[4] &
855 TSENS5_POINT2_BACKUP_MASK) >>
856 TSENS5_POINT2_BACKUP_SHIFT;
857 tsens6_point2 = (calib_data[5] &
858 TSENS6_POINT2_BACKUP_MASK);
859 tsens7_point2 = (calib_data[5] &
860 TSENS7_POINT2_BACKUP_MASK) >>
861 TSENS7_POINT2_BACKUP_SHIFT;
862 tsens8_point2 = (calib_data[5] &
863 TSENS8_POINT2_BACKUP_MASK) >>
864 TSENS8_POINT2_BACKUP_SHIFT;
865 tsens9_point2 = (calib_data[5] &
866 TSENS9_POINT2_BACKUP_MASK) >>
867 TSENS9_POINT2_BACKUP_SHIFT;
868 tsens10_point2 = (calib_data[5] &
869 TSENS10_POINT2_BACKUP_MASK)
870 >> TSENS10_POINT2_BACKUP_SHIFT;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700871 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700872 } else {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700873 tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
874 >> TSENS_CAL_SEL_SHIFT;
875 temp = (calib_data[3] & TSENS_CAL_SEL_2)
876 >> TSENS_CAL_SEL_SHIFT_2;
877 tsens_calibration_mode |= temp;
878 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) ||
879 (tsens_calibration_mode ==
880 TSENS_ONE_POINT_CALIB_OPTION_2) ||
881 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
882 pr_debug("TSENS is one point calibrationless mode\n");
883 tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
884 tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
885 TSENS0_POINT1_SHIFT;
886 tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
887 TSENS1_POINT1_SHIFT;
888 tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
889 TSENS2_POINT1_SHIFT;
890 tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
891 TSENS3_POINT1_SHIFT;
892 tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
893 tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
894 TSENS5_POINT1_SHIFT;
895 tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
896 TSENS6_POINT1_SHIFT;
897 tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
898 TSENS7_POINT1_SHIFT;
899 tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
900 TSENS8_POINT1_SHIFT;
901 tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
902 tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK)
903 >> TSENS10_POINT1_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700904 } else
905 goto calibration_less_mode;
906
907 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700908 pr_debug("TSENS is two point calibrationless mode\n");
909 tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
910 TSENS_POINT2_BASE_SHIFT;
911 tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
912 TSENS0_POINT2_SHIFT;
913 tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
914 TSENS1_POINT2_SHIFT;
915 tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
916 tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
917 TSENS3_POINT2_SHIFT;
918 tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
919 TSENS4_POINT2_SHIFT;
920 tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
921 TSENS5_POINT2_SHIFT;
922 tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
923 TSENS6_POINT2_SHIFT;
924 tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
925 tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
926 TSENS8_POINT2_SHIFT;
927 tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
928 TSENS9_POINT2_SHIFT;
929 tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK)
930 >> TSENS10_POINT2_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700931 }
932
933 if (tsens_calibration_mode == 0) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700934calibration_less_mode:
935 pr_debug("TSENS is calibrationless mode\n");
936 for (i = 0; i < tmdev->tsens_num_sensor; i++)
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700937 calib_tsens_point2_data[i] = 780;
938 calib_tsens_point1_data[0] = 502;
939 calib_tsens_point1_data[1] = 509;
940 calib_tsens_point1_data[2] = 503;
941 calib_tsens_point1_data[3] = 509;
942 calib_tsens_point1_data[4] = 505;
943 calib_tsens_point1_data[5] = 509;
944 calib_tsens_point1_data[6] = 507;
945 calib_tsens_point1_data[7] = 510;
946 calib_tsens_point1_data[8] = 508;
947 calib_tsens_point1_data[9] = 509;
948 calib_tsens_point1_data[10] = 508;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700949 goto compute_intercept_slope;
950 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700951 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700952
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700953 if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700954 pr_debug("old one point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700955 calib_tsens_point1_data[0] =
956 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
957 + tsens0_point1;
958 calib_tsens_point1_data[1] =
959 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
960 + tsens1_point1;
961 calib_tsens_point1_data[2] =
962 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
963 + tsens2_point1;
964 calib_tsens_point1_data[3] =
965 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
966 + tsens3_point1;
967 calib_tsens_point1_data[4] =
968 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
969 + tsens4_point1;
970 calib_tsens_point1_data[5] =
971 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
972 + tsens5_point1;
973 calib_tsens_point1_data[6] =
974 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
975 + tsens6_point1;
976 calib_tsens_point1_data[7] =
977 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
978 + tsens7_point1;
979 calib_tsens_point1_data[8] =
980 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
981 + tsens8_point1;
982 calib_tsens_point1_data[9] =
983 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
984 + tsens9_point1;
985 calib_tsens_point1_data[10] =
986 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
987 + tsens10_point1;
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700988 }
989
Siddartha Mohanadoss4d9815a2012-09-09 17:16:05 -0700990 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
991 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700992 pr_debug("one and two point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700993 calib_tsens_point1_data[0] =
994 ((((tsens_base1_data) + tsens0_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700995 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700996 calib_tsens_point1_data[1] =
997 ((((tsens_base1_data) + tsens1_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700998 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700999 calib_tsens_point1_data[2] =
1000 ((((tsens_base1_data) + tsens2_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001001 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001002 calib_tsens_point1_data[3] =
1003 ((((tsens_base1_data) + tsens3_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001004 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001005 calib_tsens_point1_data[4] =
1006 ((((tsens_base1_data) + tsens4_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001007 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001008 calib_tsens_point1_data[5] =
1009 ((((tsens_base1_data) + tsens5_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001010 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001011 calib_tsens_point1_data[6] =
1012 ((((tsens_base1_data) + tsens6_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001013 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001014 calib_tsens_point1_data[7] =
1015 ((((tsens_base1_data) + tsens7_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001016 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001017 calib_tsens_point1_data[8] =
1018 ((((tsens_base1_data) + tsens8_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001019 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001020 calib_tsens_point1_data[9] =
1021 ((((tsens_base1_data) + tsens9_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001022 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001023 calib_tsens_point1_data[10] =
1024 ((((tsens_base1_data) + tsens10_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001025 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001026 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001027
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001028 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001029 pr_debug("two point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001030 calib_tsens_point2_data[0] =
1031 (((tsens_base2_data + tsens0_point2) << 2) |
1032 TSENS_BIT_APPEND);
1033 calib_tsens_point2_data[1] =
1034 (((tsens_base2_data + tsens1_point2) << 2) |
1035 TSENS_BIT_APPEND);
1036 calib_tsens_point2_data[2] =
1037 (((tsens_base2_data + tsens2_point2) << 2) |
1038 TSENS_BIT_APPEND);
1039 calib_tsens_point2_data[3] =
1040 (((tsens_base2_data + tsens3_point2) << 2) |
1041 TSENS_BIT_APPEND);
1042 calib_tsens_point2_data[4] =
1043 (((tsens_base2_data + tsens4_point2) << 2) |
1044 TSENS_BIT_APPEND);
1045 calib_tsens_point2_data[5] =
1046 (((tsens_base2_data + tsens5_point2) << 2) |
1047 TSENS_BIT_APPEND);
1048 calib_tsens_point2_data[6] =
1049 (((tsens_base2_data + tsens6_point2) << 2) |
1050 TSENS_BIT_APPEND);
1051 calib_tsens_point2_data[7] =
1052 (((tsens_base2_data + tsens7_point2) << 2) |
1053 TSENS_BIT_APPEND);
1054 calib_tsens_point2_data[8] =
1055 (((tsens_base2_data + tsens8_point2) << 2) |
1056 TSENS_BIT_APPEND);
1057 calib_tsens_point2_data[9] =
1058 (((tsens_base2_data + tsens9_point2) << 2) |
1059 TSENS_BIT_APPEND);
1060 calib_tsens_point2_data[10] =
1061 (((tsens_base2_data + tsens10_point2) << 2) |
1062 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001063 }
1064
1065compute_intercept_slope:
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001066 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1067 int32_t num = 0, den = 0;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001068 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
1069 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001070 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001071 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
1072 temp_120_degc - temp_30_degc (x2 - x1) */
1073 num = tmdev->sensor[i].calib_data_point2 -
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001074 tmdev->sensor[i].calib_data_point1;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001075 num *= tmdev->tsens_factor;
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001076 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001077 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001078 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001079 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
1080 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
1081 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001082 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
1083 tmdev->prev_reading_avail = false;
1084 }
1085
1086 return 0;
1087}
1088
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001089static int tsens_calib_sensors(void)
1090{
1091 int rc = 0;
1092
1093 if (!tmdev)
1094 return -ENODEV;
1095
1096 if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8974)
1097 rc = tsens_calib_8974_sensors();
1098 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
1099 rc = tsens_calib_8x26_sensors();
1100 else
1101 rc = -ENODEV;
1102
1103 return rc;
1104}
1105
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001106static int get_device_tree_data(struct platform_device *pdev)
1107{
1108 const struct device_node *of_node = pdev->dev.of_node;
1109 struct resource *res_mem = NULL;
1110 u32 *tsens_slope_data;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001111 u32 rc = 0, i, tsens_num_sensors, calib_type;
1112 const char *tsens_calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001113
1114 rc = of_property_read_u32(of_node,
1115 "qcom,sensors", &tsens_num_sensors);
1116 if (rc) {
1117 dev_err(&pdev->dev, "missing sensor number\n");
1118 return -ENODEV;
1119 }
1120
1121 tsens_slope_data = devm_kzalloc(&pdev->dev,
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001122 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001123 if (!tsens_slope_data) {
1124 dev_err(&pdev->dev, "can not allocate slope data\n");
1125 return -ENOMEM;
1126 }
1127
1128 rc = of_property_read_u32_array(of_node,
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001129 "qcom,slope", tsens_slope_data, tsens_num_sensors);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001130 if (rc) {
1131 dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
1132 return rc;
1133 };
1134
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001135 tsens_calib_mode = of_get_property(of_node,
1136 "qcom,calib-mode", NULL);
1137 if (!strncmp(tsens_calib_mode, "fuse_map1", 9))
1138 calib_type = TSENS_CALIB_FUSE_MAP_8974;
1139 else if (!strncmp(tsens_calib_mode, "fuse_map2", 9))
1140 calib_type = TSENS_CALIB_FUSE_MAP_8X26;
1141 else if (!strncmp(tsens_calib_mode, "fuse_map3", 9))
1142 calib_type = TSENS_CALIB_FUSE_MAP_8X10;
1143 else {
1144 pr_err("%s: Invalid calibration property\n", __func__);
1145 return -EINVAL;
1146 }
1147
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001148 tmdev = devm_kzalloc(&pdev->dev,
1149 sizeof(struct tsens_tm_device) +
1150 tsens_num_sensors *
1151 sizeof(struct tsens_tm_device_sensor),
1152 GFP_KERNEL);
1153 if (tmdev == NULL) {
1154 pr_err("%s: kzalloc() failed.\n", __func__);
1155 return -ENOMEM;
1156 }
1157
1158 for (i = 0; i < tsens_num_sensors; i++)
1159 tmdev->sensor[i].slope_mul_tsens_factor = tsens_slope_data[i];
1160 tmdev->tsens_factor = TSENS_SLOPE_FACTOR;
1161 tmdev->tsens_num_sensor = tsens_num_sensors;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001162 tmdev->calibration_less_mode = of_property_read_bool(of_node,
1163 "qcom,calibration-less-mode");
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001164 tmdev->calib_mode = calib_type;
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -07001165 tmdev->tsens_local_init = of_property_read_bool(of_node,
1166 "qcom,tsens_local_init");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001167
1168 tmdev->tsens_irq = platform_get_irq(pdev, 0);
1169 if (tmdev->tsens_irq < 0) {
1170 pr_err("Invalid get irq\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001171 rc = tmdev->tsens_irq;
1172 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001173 }
1174
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001175 /* TSENS register region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001176 tmdev->res_tsens_mem = platform_get_resource_byname(pdev,
1177 IORESOURCE_MEM, "tsens_physical");
1178 if (!tmdev->res_tsens_mem) {
1179 pr_err("Could not get tsens physical address resource\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001180 rc = -EINVAL;
1181 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001182 }
1183
1184 tmdev->tsens_len = tmdev->res_tsens_mem->end -
1185 tmdev->res_tsens_mem->start + 1;
1186
1187 res_mem = request_mem_region(tmdev->res_tsens_mem->start,
1188 tmdev->tsens_len, tmdev->res_tsens_mem->name);
1189 if (!res_mem) {
1190 pr_err("Request tsens physical memory region failed\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001191 rc = -EINVAL;
1192 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001193 }
1194
1195 tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
1196 if (!tmdev->tsens_addr) {
1197 pr_err("Failed to IO map TSENS registers.\n");
1198 rc = -EINVAL;
1199 goto fail_unmap_tsens_region;
1200 }
1201
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001202 /* TSENS calibration region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001203 tmdev->res_calib_mem = platform_get_resource_byname(pdev,
1204 IORESOURCE_MEM, "tsens_eeprom_physical");
1205 if (!tmdev->res_calib_mem) {
1206 pr_err("Could not get qfprom physical address resource\n");
1207 rc = -EINVAL;
1208 goto fail_unmap_tsens;
1209 }
1210
1211 tmdev->calib_len = tmdev->res_calib_mem->end -
1212 tmdev->res_calib_mem->start + 1;
1213
1214 res_mem = request_mem_region(tmdev->res_calib_mem->start,
1215 tmdev->calib_len, tmdev->res_calib_mem->name);
1216 if (!res_mem) {
1217 pr_err("Request calibration memory region failed\n");
1218 rc = -EINVAL;
1219 goto fail_unmap_tsens;
1220 }
1221
1222 tmdev->tsens_calib_addr = ioremap(res_mem->start,
1223 tmdev->calib_len);
1224 if (!tmdev->tsens_calib_addr) {
1225 pr_err("Failed to IO map EEPROM registers.\n");
1226 rc = -EINVAL;
1227 goto fail_unmap_calib_region;
1228 }
1229
1230 return 0;
1231
1232fail_unmap_calib_region:
1233 if (tmdev->res_calib_mem)
1234 release_mem_region(tmdev->res_calib_mem->start,
1235 tmdev->calib_len);
1236fail_unmap_tsens:
1237 if (tmdev->tsens_addr)
1238 iounmap(tmdev->tsens_addr);
1239fail_unmap_tsens_region:
1240 if (tmdev->res_tsens_mem)
1241 release_mem_region(tmdev->res_tsens_mem->start,
1242 tmdev->tsens_len);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001243fail_tmdev:
1244 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001245 return rc;
1246}
1247
1248static int __devinit tsens_tm_probe(struct platform_device *pdev)
1249{
1250 int rc;
1251
1252 if (tmdev) {
1253 pr_err("TSENS device already in use\n");
1254 return -EBUSY;
1255 }
1256
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001257 if (pdev->dev.of_node) {
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001258 rc = get_device_tree_data(pdev);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001259 if (rc) {
1260 pr_err("Error reading TSENS DT\n");
1261 return rc;
1262 }
1263 } else
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001264 return -ENODEV;
1265
1266 tmdev->pdev = pdev;
1267 rc = tsens_calib_sensors();
Michael Bohanb89167e2012-10-04 16:24:23 -07001268 if (rc < 0) {
1269 pr_err("Calibration failed\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001270 goto fail;
Michael Bohanb89167e2012-10-04 16:24:23 -07001271 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001272
1273 tsens_hw_init();
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001274
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001275 tmdev->prev_reading_avail = true;
1276
1277 platform_set_drvdata(pdev, tmdev);
1278
1279 return 0;
1280fail:
1281 if (tmdev->tsens_calib_addr)
1282 iounmap(tmdev->tsens_calib_addr);
1283 if (tmdev->res_calib_mem)
1284 release_mem_region(tmdev->res_calib_mem->start,
1285 tmdev->calib_len);
1286 if (tmdev->tsens_addr)
1287 iounmap(tmdev->tsens_addr);
1288 if (tmdev->res_tsens_mem)
1289 release_mem_region(tmdev->res_tsens_mem->start,
1290 tmdev->tsens_len);
Michael Bohanb89167e2012-10-04 16:24:23 -07001291 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001292
1293 return rc;
1294}
1295
1296static int __devinit _tsens_register_thermal(void)
1297{
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001298 struct platform_device *pdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001299 int rc, i;
1300
1301 if (!tmdev) {
1302 pr_err("%s: TSENS early init not done\n", __func__);
1303 return -ENODEV;
1304 }
1305
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001306 pdev = tmdev->pdev;
1307
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001308 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1309 char name[18];
1310 snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
1311 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
1312 tmdev->sensor[i].sensor_num = i;
1313 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
1314 TSENS_TRIP_NUM, &tmdev->sensor[i],
1315 &tsens_thermal_zone_ops, 0, 0, 0, 0);
1316 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
1317 pr_err("%s: thermal_zone_device_register() failed.\n",
1318 __func__);
1319 rc = -ENODEV;
1320 goto fail;
1321 }
1322 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001323
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001324 rc = request_irq(tmdev->tsens_irq, tsens_isr,
1325 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
1326 if (rc < 0) {
1327 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
1328 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1329 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1330 goto fail;
Siddartha Mohanadossb9be9812013-02-13 11:03:32 -08001331 } else {
1332 enable_irq_wake(tmdev->tsens_irq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001333 }
1334 platform_set_drvdata(pdev, tmdev);
1335
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -07001336 INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
1337
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001338 return 0;
1339fail:
1340 if (tmdev->tsens_calib_addr)
1341 iounmap(tmdev->tsens_calib_addr);
1342 if (tmdev->res_calib_mem)
1343 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001344 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001345 if (tmdev->tsens_addr)
1346 iounmap(tmdev->tsens_addr);
1347 if (tmdev->res_tsens_mem)
1348 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001349 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001350 return rc;
1351}
1352
1353static int __devexit tsens_tm_remove(struct platform_device *pdev)
1354{
1355 struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
1356 int i;
1357
1358 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1359 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1360 if (tmdev->tsens_calib_addr)
1361 iounmap(tmdev->tsens_calib_addr);
1362 if (tmdev->res_calib_mem)
1363 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001364 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001365 if (tmdev->tsens_addr)
1366 iounmap(tmdev->tsens_addr);
1367 if (tmdev->res_tsens_mem)
1368 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001369 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001370 free_irq(tmdev->tsens_irq, tmdev);
1371 platform_set_drvdata(pdev, NULL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001372
1373 return 0;
1374}
1375
1376static struct of_device_id tsens_match[] = {
1377 { .compatible = "qcom,msm-tsens",
1378 },
1379 {}
1380};
1381
1382static struct platform_driver tsens_tm_driver = {
1383 .probe = tsens_tm_probe,
1384 .remove = tsens_tm_remove,
1385 .driver = {
1386 .name = "msm-tsens",
1387 .owner = THIS_MODULE,
1388 .of_match_table = tsens_match,
1389 },
1390};
1391
1392static int __init tsens_tm_init_driver(void)
1393{
1394 return platform_driver_register(&tsens_tm_driver);
1395}
1396arch_initcall(tsens_tm_init_driver);
1397
1398static int __init tsens_thermal_register(void)
1399{
1400 return _tsens_register_thermal();
1401}
1402module_init(tsens_thermal_register);
1403
1404static void __exit _tsens_tm_remove(void)
1405{
1406 platform_driver_unregister(&tsens_tm_driver);
1407}
1408module_exit(_tsens_tm_remove);
1409
1410MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
1411MODULE_LICENSE("GPL v2");