blob: 991cf2e11ba586af7644819b6d45c5dd38776a79 [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 Mohanadoss21c96ed2013-03-26 10:35:42 -070077#define TSENS_EEPROM_8X10_1(n) ((n) + 0x1a4)
78#define TSENS_EEPROM_8X10_1_OFFSET 8
79
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070080/* TSENS calibration Mask data */
81#define TSENS_BASE1_MASK 0xff
82#define TSENS0_POINT1_MASK 0x3f00
83#define TSENS1_POINT1_MASK 0xfc000
84#define TSENS2_POINT1_MASK 0x3f00000
85#define TSENS3_POINT1_MASK 0xfc000000
86#define TSENS4_POINT1_MASK 0x3f
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070087#define TSENS5_POINT1_MASK 0xfc0
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070088#define TSENS6_POINT1_MASK 0x3f000
89#define TSENS7_POINT1_MASK 0xfc0000
90#define TSENS8_POINT1_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070091#define TSENS8_POINT1_MASK_BACKUP 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070092#define TSENS9_POINT1_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070093#define TSENS9_POINT1_MASK_BACKUP 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -080094#define TSENS10_POINT1_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070095#define TSENS10_POINT1_MASK_BACKUP 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070096#define TSENS_CAL_SEL_0_1 0xc0000000
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070097#define TSENS_CAL_SEL_2 0x40000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070098#define TSENS_CAL_SEL_SHIFT 30
99#define TSENS_CAL_SEL_SHIFT_2 28
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700100#define TSENS_ONE_POINT_CALIB 0x1
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700101#define TSENS_ONE_POINT_CALIB_OPTION_2 0x2
102#define TSENS_TWO_POINT_CALIB 0x3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700103
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700104#define TSENS0_POINT1_SHIFT 8
105#define TSENS1_POINT1_SHIFT 14
106#define TSENS2_POINT1_SHIFT 20
107#define TSENS3_POINT1_SHIFT 26
108#define TSENS5_POINT1_SHIFT 6
109#define TSENS6_POINT1_SHIFT 12
110#define TSENS7_POINT1_SHIFT 18
111#define TSENS8_POINT1_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700112#define TSENS9_POINT1_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700113#define TSENS10_POINT1_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700114#define TSENS10_POINT1_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700115
116#define TSENS_POINT2_BASE_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700117#define TSENS_POINT2_BASE_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700118#define TSENS0_POINT2_SHIFT 20
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700119#define TSENS0_POINT2_BACKUP_SHIFT 26
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700120#define TSENS1_POINT2_SHIFT 26
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700121#define TSENS2_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700122#define TSENS3_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700123#define TSENS3_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700124#define TSENS4_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700125#define TSENS4_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700126#define TSENS5_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700127#define TSENS5_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700128#define TSENS6_POINT2_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700129#define TSENS7_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700130#define TSENS8_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700131#define TSENS8_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700132#define TSENS9_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700133#define TSENS9_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700134#define TSENS10_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700135#define TSENS10_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700136
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700137#define TSENS_BASE2_MASK 0xff000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700138#define TSENS_BASE2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700139#define TSENS0_POINT2_MASK 0x3f00000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700140#define TSENS0_POINT2_BACKUP_MASK 0xfc000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700141#define TSENS1_POINT2_MASK 0xfc000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700142#define TSENS1_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700143#define TSENS2_POINT2_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700144#define TSENS2_POINT2_BACKUP_MASK 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800145#define TSENS3_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700146#define TSENS3_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700147#define TSENS4_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700148#define TSENS4_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700149#define TSENS5_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700150#define TSENS5_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700151#define TSENS6_POINT2_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700152#define TSENS6_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700153#define TSENS7_POINT2_MASK 0x3f
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800154#define TSENS7_POINT2_BACKUP_MASK 0xfc0
155#define TSENS8_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700156#define TSENS8_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700157#define TSENS9_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700158#define TSENS9_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700159#define TSENS10_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700160#define TSENS10_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700161
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800162#define TSENS_8X26_BASE0_MASK 0x1fe000
163#define TSENS0_8X26_POINT1_MASK 0x7f00000
164#define TSENS1_8X26_POINT1_MASK 0x3f
165#define TSENS2_8X26_POINT1_MASK 0xfc0
166#define TSENS3_8X26_POINT1_MASK 0x3f000
167#define TSENS4_8X26_POINT1_MASK 0xfc0000
168#define TSENS5_8X26_POINT1_MASK 0x3f000000
169#define TSENS6_8X26_POINT1_MASK 0x3f00000
170#define TSENS_8X26_TSENS_CAL_SEL 0xe0000000
171#define TSENS_8X26_BASE1_MASK 0xff
172#define TSENS0_8X26_POINT2_MASK 0x3f00
173#define TSENS1_8X26_POINT2_MASK 0xfc00
174#define TSENS2_8X26_POINT2_MASK 0x3f00000
175#define TSENS3_8X26_POINT2_MASK 0xfc000000
176#define TSENS4_8X26_POINT2_MASK 0xfc000000
177#define TSENS5_8X26_POINT2_MASK 0x3f00000
178#define TSENS6_8X26_POINT2_MASK 0x7e0000
179
180#define TSENS_8X26_CAL_SEL_SHIFT 29
181#define TSENS_8X26_BASE0_SHIFT 13
182#define TSENS0_8X26_POINT1_SHIFT 21
183#define TSENS2_8X26_POINT1_SHIFT 6
184#define TSENS3_8X26_POINT1_SHIFT 12
185#define TSENS4_8X26_POINT1_SHIFT 18
186#define TSENS5_8X26_POINT1_SHIFT 24
187#define TSENS6_8X26_POINT1_SHIFT 20
188
189#define TSENS0_8X26_POINT2_SHIFT 8
190#define TSENS1_8X26_POINT2_SHIFT 14
191#define TSENS2_8X26_POINT2_SHIFT 20
192#define TSENS3_8X26_POINT2_SHIFT 26
193#define TSENS4_8X26_POINT2_SHIFT 20
194#define TSENS5_8X26_POINT2_SHIFT 26
195#define TSENS6_8X26_POINT2_SHIFT 17
196
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700197#define TSENS_8X10_CAL_SEL_SHIFT 28
198#define TSENS_8X10_BASE1_SHIFT 8
199#define TSENS0_8X10_POINT1_SHIFT 16
200#define TSENS0_8X10_POINT2_SHIFT 22
201#define TSENS1_8X10_POINT2_SHIFT 6
202#define TSENS_8X10_BASE0_MASK 0xf
203#define TSENS_8X10_BASE1_MASK 0xf0
204#define TSENS0_8X10_POINT1_MASK 0x3f0000
205#define TSENS0_8X10_POINT2_MASK 0xfc00000
206#define TSENS_8X10_TSENS_CAL_SEL 0x70000000
207#define TSENS1_8X10_POINT1_MASK 0x3f
208#define TSENS1_8X10_POINT2_MASK 0xfc0
209
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700210#define TSENS_BIT_APPEND 0x3
211#define TSENS_CAL_DEGC_POINT1 30
212#define TSENS_CAL_DEGC_POINT2 120
213#define TSENS_SLOPE_FACTOR 1000
214
215/* TSENS register data */
216#define TSENS_TRDY_RDY_MIN_TIME 2000
217#define TSENS_TRDY_RDY_MAX_TIME 2100
218#define TSENS_THRESHOLD_MAX_CODE 0x3ff
219#define TSENS_THRESHOLD_MIN_CODE 0x0
220
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700221#define TSENS_GLOBAL_INIT_DATA 0x302f16c
222#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700223#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700224#define TSENS_SN_REMOTE_CFG_DATA 0x11c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700225
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700226#define TSENS_QFPROM_BACKUP_SEL 0x3
227#define TSENS_QFPROM_BACKUP_REDUN_SEL 0xe0000000
228#define TSENS_QFPROM_BACKUP_REDUN_SHIFT 29
229
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800230enum tsens_calib_fuse_map_type {
231 TSENS_CALIB_FUSE_MAP_8974 = 0,
232 TSENS_CALIB_FUSE_MAP_8X26,
233 TSENS_CALIB_FUSE_MAP_8X10,
234 TSENS_CALIB_FUSE_MAP_NUM,
235};
236
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700237/* Trips: warm and cool */
238enum tsens_trip_type {
239 TSENS_TRIP_WARM = 0,
240 TSENS_TRIP_COOL,
241 TSENS_TRIP_NUM,
242};
243
244struct tsens_tm_device_sensor {
245 struct thermal_zone_device *tz_dev;
246 enum thermal_device_mode mode;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700247 /* Physical HW sensor number */
248 unsigned int sensor_hw_num;
249 /* Software index. This is keep track of the HW/SW
250 * sensor_ID mapping */
251 unsigned int sensor_sw_id;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700252 struct work_struct work;
253 int offset;
254 int calib_data_point1;
255 int calib_data_point2;
256 uint32_t slope_mul_tsens_factor;
257};
258
259struct tsens_tm_device {
260 struct platform_device *pdev;
261 bool prev_reading_avail;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -0700262 bool calibration_less_mode;
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700263 bool tsens_local_init;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700264 int tsens_factor;
265 uint32_t tsens_num_sensor;
266 int tsens_irq;
267 void *tsens_addr;
268 void *tsens_calib_addr;
269 int tsens_len;
270 int calib_len;
271 struct resource *res_tsens_mem;
272 struct resource *res_calib_mem;
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700273 struct work_struct tsens_work;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800274 uint32_t calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700275 struct tsens_tm_device_sensor sensor[0];
276};
277
278struct tsens_tm_device *tmdev;
279
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700280int tsens_get_sw_id_mapping(int sensor_hw_num, int *sensor_sw_idx)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700281{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700282 int i = 0;
283 bool id_found = false;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700284
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700285 while (i < tmdev->tsens_num_sensor && !id_found) {
286 if (sensor_hw_num == tmdev->sensor[i].sensor_hw_num) {
Siddartha Mohanadossee00f422013-04-17 11:33:01 -0700287 *sensor_sw_idx = tmdev->sensor[i].sensor_sw_id;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700288 id_found = true;
289 }
290 i++;
291 }
292
293 if (!id_found)
294 return -EINVAL;
295
296 return 0;
297}
298EXPORT_SYMBOL(tsens_get_sw_id_mapping);
299
300int tsens_get_hw_id_mapping(int sensor_sw_id, int *sensor_hw_num)
301{
302 int i = 0;
303 bool id_found = false;
304
305 while (i < tmdev->tsens_num_sensor && !id_found) {
306 if (sensor_sw_id == tmdev->sensor[i].sensor_sw_id) {
Siddartha Mohanadossee00f422013-04-17 11:33:01 -0700307 *sensor_hw_num = tmdev->sensor[i].sensor_hw_num;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700308 id_found = true;
309 }
310 i++;
311 }
312
313 if (!id_found)
314 return -EINVAL;
315
316 return 0;
317}
318EXPORT_SYMBOL(tsens_get_hw_id_mapping);
319
320static int tsens_tz_code_to_degc(int adc_code, int sensor_sw_id)
321{
322 int degc, num, den, idx;
323
324 idx = sensor_sw_id;
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700325 num = ((adc_code * tmdev->tsens_factor) -
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700326 tmdev->sensor[idx].offset);
327 den = (int) tmdev->sensor[idx].slope_mul_tsens_factor;
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700328
Siddartha Mohanadoss8cc1fbc2013-04-05 15:10:52 -0700329 if (num > 0)
330 degc = ((num + (den/2))/den);
331 else if (num < 0)
332 degc = ((num - (den/2))/den);
333 else
334 degc = num/den;
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -0700335
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700336 pr_debug("raw_code:0x%x, sensor_num:%d, degc:%d\n",
337 adc_code, idx, degc);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700338 return degc;
339}
340
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700341static int tsens_tz_degc_to_code(int degc, int idx)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700342{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700343 int code = ((degc * tmdev->sensor[idx].slope_mul_tsens_factor)
344 + tmdev->sensor[idx].offset)/tmdev->tsens_factor;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700345
346 if (code > TSENS_THRESHOLD_MAX_CODE)
347 code = TSENS_THRESHOLD_MAX_CODE;
348 else if (code < TSENS_THRESHOLD_MIN_CODE)
349 code = TSENS_THRESHOLD_MIN_CODE;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700350 pr_debug("raw_code:0x%x, sensor_num:%d, degc:%d\n",
351 code, idx, degc);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700352 return code;
353}
354
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700355static void msm_tsens_get_temp(int sensor_hw_num, unsigned long *temp)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700356{
357 unsigned int code, sensor_addr;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700358 int sensor_sw_id = -EINVAL, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700359
360 if (!tmdev->prev_reading_avail) {
361 while (!(readl_relaxed(TSENS_TRDY_ADDR(tmdev->tsens_addr))
362 & TSENS_TRDY_MASK))
363 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
364 TSENS_TRDY_RDY_MAX_TIME);
365 tmdev->prev_reading_avail = true;
366 }
367
368 sensor_addr =
369 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
370 code = readl_relaxed(sensor_addr +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700371 (sensor_hw_num << TSENS_STATUS_ADDR_OFFSET));
372 /* Obtain SW index to map the corresponding thermal zone's
373 * offset and slope for code to degc conversion. */
374 rc = tsens_get_sw_id_mapping(sensor_hw_num, &sensor_sw_id);
375 if (rc < 0) {
376 pr_err("tsens mapping index not found\n");
377 return;
378 }
379
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700380 *temp = tsens_tz_code_to_degc((code & TSENS_SN_STATUS_TEMP_MASK),
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700381 sensor_sw_id);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700382}
383
384static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
385 unsigned long *temp)
386{
387 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
388
389 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
390 return -EINVAL;
391
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700392 msm_tsens_get_temp(tm_sensor->sensor_hw_num, temp);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700393
394 return 0;
395}
396
397int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
398{
399 if (!tmdev)
400 return -ENODEV;
401
402 msm_tsens_get_temp(device->sensor_num, temp);
403
404 return 0;
405}
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700406EXPORT_SYMBOL(tsens_get_temp);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700407
Siddartha Mohanadossb66effc2013-04-04 19:48:17 -0700408int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors)
409{
410 if (!tmdev)
411 return -ENODEV;
412
413 *tsens_num_sensors = tmdev->tsens_num_sensor;
414
415 return 0;
416}
417EXPORT_SYMBOL(tsens_get_max_sensor_num);
418
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700419static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
420 enum thermal_device_mode *mode)
421{
422 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
423
424 if (!tm_sensor || !mode)
425 return -EINVAL;
426
427 *mode = tm_sensor->mode;
428
429 return 0;
430}
431
432static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
433 int trip, enum thermal_trip_type *type)
434{
435 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
436
437 if (!tm_sensor || trip < 0 || !type)
438 return -EINVAL;
439
440 switch (trip) {
441 case TSENS_TRIP_WARM:
442 *type = THERMAL_TRIP_CONFIGURABLE_HI;
443 break;
444 case TSENS_TRIP_COOL:
445 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
446 break;
447 default:
448 return -EINVAL;
449 }
450
451 return 0;
452}
453
454static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
455 int trip, enum thermal_trip_activation_mode mode)
456{
457 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
458 unsigned int reg_cntl, code, hi_code, lo_code, mask;
459
460 if (!tm_sensor || trip < 0)
461 return -EINVAL;
462
463 lo_code = TSENS_THRESHOLD_MIN_CODE;
464 hi_code = TSENS_THRESHOLD_MAX_CODE;
465
466 reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700467 (tmdev->tsens_addr) +
468 (tm_sensor->sensor_hw_num *
469 TSENS_SN_ADDR_OFFSET)));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700470 switch (trip) {
471 case TSENS_TRIP_WARM:
472 code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
473 >> TSENS_UPPER_THRESHOLD_SHIFT;
474 mask = TSENS_UPPER_STATUS_CLR;
475
476 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
477 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
478 break;
479 case TSENS_TRIP_COOL:
480 code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
481 mask = TSENS_LOWER_STATUS_CLR;
482
483 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
484 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
485 >> TSENS_UPPER_THRESHOLD_SHIFT;
486 break;
487 default:
488 return -EINVAL;
489 }
490
491 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
492 writel_relaxed(reg_cntl | mask,
493 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700494 (tmdev->tsens_addr) +
495 (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET)));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700496 else {
497 if (code < lo_code || code > hi_code) {
498 pr_err("%s with invalid code %x\n", __func__, code);
499 return -EINVAL;
500 }
501 writel_relaxed(reg_cntl & ~mask,
502 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr) +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700503 (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET)));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700504 }
505 mb();
506 return 0;
507}
508
509static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
510 int trip, unsigned long *temp)
511{
512 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
513 unsigned int reg;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700514 int sensor_sw_id = -EINVAL, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700515
516 if (!tm_sensor || trip < 0 || !temp)
517 return -EINVAL;
518
519 reg = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
520 (tmdev->tsens_addr) +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700521 (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700522 switch (trip) {
523 case TSENS_TRIP_WARM:
524 reg = (reg & TSENS_UPPER_THRESHOLD_MASK) >>
525 TSENS_UPPER_THRESHOLD_SHIFT;
526 break;
527 case TSENS_TRIP_COOL:
528 reg = (reg & TSENS_LOWER_THRESHOLD_MASK);
529 break;
530 default:
531 return -EINVAL;
532 }
533
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700534 rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id);
535 if (rc < 0) {
536 pr_err("tsens mapping index not found\n");
537 return rc;
538 }
539 *temp = tsens_tz_code_to_degc(reg, sensor_sw_id);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700540
541 return 0;
542}
543
544static int tsens_tz_notify(struct thermal_zone_device *thermal,
545 int count, enum thermal_trip_type type)
546{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700547 /* Critical temperature threshold are enabled and will
548 * shutdown the device once critical thresholds are crossed. */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700549 pr_debug("%s debug\n", __func__);
550 return 1;
551}
552
553static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
554 int trip, long temp)
555{
556 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
557 unsigned int reg_cntl;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700558 int code, hi_code, lo_code, code_err_chk, sensor_sw_id = 0, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700559
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700560 rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id);
561 if (rc < 0) {
562 pr_err("tsens mapping index not found\n");
563 return rc;
564 }
565 code_err_chk = code = tsens_tz_degc_to_code(temp, sensor_sw_id);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700566 if (!tm_sensor || trip < 0)
567 return -EINVAL;
568
569 lo_code = TSENS_THRESHOLD_MIN_CODE;
570 hi_code = TSENS_THRESHOLD_MAX_CODE;
571
572 reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700573 (tmdev->tsens_addr) + (tm_sensor->sensor_hw_num *
574 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700575 switch (trip) {
576 case TSENS_TRIP_WARM:
577 code <<= TSENS_UPPER_THRESHOLD_SHIFT;
578 reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
579 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
580 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
581 break;
582 case TSENS_TRIP_COOL:
583 reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
584 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
585 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
586 >> TSENS_UPPER_THRESHOLD_SHIFT;
587 break;
588 default:
589 return -EINVAL;
590 }
591
592 if (code_err_chk < lo_code || code_err_chk > hi_code)
593 return -EINVAL;
594
595 writel_relaxed(reg_cntl | code, (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
596 (tmdev->tsens_addr) +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700597 (tm_sensor->sensor_hw_num *
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700598 TSENS_SN_ADDR_OFFSET)));
599 mb();
600 return 0;
601}
602
603static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
604 .get_temp = tsens_tz_get_temp,
605 .get_mode = tsens_tz_get_mode,
606 .get_trip_type = tsens_tz_get_trip_type,
607 .activate_trip_type = tsens_tz_activate_trip_type,
608 .get_trip_temp = tsens_tz_get_trip_temp,
609 .set_trip_temp = tsens_tz_set_trip_temp,
610 .notify = tsens_tz_notify,
611};
612
613static void notify_uspace_tsens_fn(struct work_struct *work)
614{
615 struct tsens_tm_device_sensor *tm = container_of(work,
616 struct tsens_tm_device_sensor, work);
617
618 sysfs_notify(&tm->tz_dev->device.kobj,
619 NULL, "type");
620}
621
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700622static void tsens_scheduler_fn(struct work_struct *work)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700623{
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700624 struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
625 tsens_work);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700626 unsigned int i, status, threshold;
627 unsigned int sensor_status_addr, sensor_status_ctrl_addr;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700628 int sensor_sw_id = -EINVAL, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700629
630 sensor_status_addr =
631 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
632 sensor_status_ctrl_addr =
633 (unsigned int)TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
634 (tmdev->tsens_addr);
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700635 for (i = 0; i < tm->tsens_num_sensor; i++) {
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700636 bool upper_thr = false, lower_thr = false;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700637 uint32_t addr_offset;
638
639 addr_offset = tm->sensor[i].sensor_hw_num *
640 TSENS_SN_ADDR_OFFSET;
641 status = readl_relaxed(sensor_status_addr + addr_offset);
642 threshold = readl_relaxed(sensor_status_ctrl_addr +
643 addr_offset);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700644 if (status & TSENS_SN_STATUS_UPPER_STATUS) {
645 writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700646 TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
647 tmdev->tsens_addr + addr_offset));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700648 upper_thr = true;
649 }
650 if (status & TSENS_SN_STATUS_LOWER_STATUS) {
651 writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700652 TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
653 tmdev->tsens_addr + addr_offset));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700654 lower_thr = true;
655 }
656 if (upper_thr || lower_thr) {
657 /* Notify user space */
658 schedule_work(&tm->sensor[i].work);
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700659 rc = tsens_get_sw_id_mapping(
660 tm->sensor[i].sensor_hw_num,
661 &sensor_sw_id);
662 if (rc < 0)
663 pr_err("tsens mapping index not found\n");
664 pr_debug("sensor:%d trigger temp (%d degC)\n",
665 tm->sensor[i].sensor_hw_num,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700666 tsens_tz_code_to_degc((status &
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700667 TSENS_SN_STATUS_TEMP_MASK),
668 sensor_sw_id));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700669 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700670 }
671 mb();
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700672}
673
674static irqreturn_t tsens_isr(int irq, void *data)
675{
676 schedule_work(&tmdev->tsens_work);
677
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700678 return IRQ_HANDLED;
679}
680
681static void tsens_hw_init(void)
682{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700683 unsigned int reg_cntl = 0, sensor_en = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700684 unsigned int i;
685
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700686 if (tmdev->tsens_local_init) {
687 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
688 writel_relaxed(reg_cntl | TSENS_SW_RST,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700689 TSENS_CTRL_ADDR(tmdev->tsens_addr));
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700690 reg_cntl |= (TSENS_62_5_MS_MEAS_PERIOD <<
691 TSENS_MEAS_PERIOD_SHIFT);
692 for (i = 0; i < tmdev->tsens_num_sensor; i++)
693 sensor_en |= (1 << tmdev->sensor[i].sensor_hw_num);
694 sensor_en <<= TSENS_SENSOR0_SHIFT;
695 reg_cntl |= (sensor_en | TSENS_EN);
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700696 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
697 writel_relaxed(TSENS_GLOBAL_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700698 TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700699 writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700700 TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700701 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
702 writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700703 TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700704 + (tmdev->sensor[i].sensor_hw_num *
705 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700706 writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700707 TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700708 + (tmdev->sensor[i].sensor_hw_num *
709 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700710 }
711 pr_debug("Local TSENS control initialization\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700712 }
713 writel_relaxed(TSENS_INTERRUPT_EN,
714 TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
715}
716
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700717static int tsens_calib_8x10_sensors(void)
718{
719 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
720 int tsens0_point2 = 0, tsens1_point2 = 0;
721 int tsens_base1_data = 0, tsens_calibration_mode = 0;
722 uint32_t calib_data[2];
723 uint32_t calib_tsens_point1_data[2], calib_tsens_point2_data[2];
724
725 if (tmdev->calibration_less_mode)
726 goto calibration_less_mode;
727
728 calib_data[0] = readl_relaxed(
729 TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr));
730 calib_data[1] = readl_relaxed(
731 (TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr) +
732 TSENS_EEPROM_8X10_1_OFFSET));
733
734 tsens_calibration_mode = (calib_data[0] & TSENS_8X10_TSENS_CAL_SEL)
735 >> TSENS_8X10_CAL_SEL_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700736 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700737
738 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
739 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
740 tsens_base0_data = (calib_data[0] & TSENS_8X10_BASE0_MASK);
741 tsens0_point1 = (calib_data[0] & TSENS0_8X10_POINT1_MASK) >>
742 TSENS0_8X10_POINT1_SHIFT;
743 tsens1_point1 = calib_data[1] & TSENS1_8X10_POINT1_MASK;
744 } else
745 goto calibration_less_mode;
746
747 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
748 tsens_base1_data = (calib_data[0] & TSENS_8X10_BASE1_MASK) >>
749 TSENS_8X10_BASE1_SHIFT;
750 tsens0_point2 = (calib_data[0] & TSENS0_8X10_POINT2_MASK) >>
751 TSENS0_8X10_POINT2_SHIFT;
752 tsens1_point2 = (calib_data[1] & TSENS1_8X10_POINT2_MASK) >>
753 TSENS1_8X10_POINT2_SHIFT;
754 }
755
756 if (tsens_calibration_mode == 0) {
757calibration_less_mode:
758 pr_debug("TSENS is calibrationless mode\n");
759 for (i = 0; i < tmdev->tsens_num_sensor; i++)
760 calib_tsens_point2_data[i] = 780;
761 calib_tsens_point1_data[0] = 595;
762 calib_tsens_point1_data[1] = 629;
763 goto compute_intercept_slope;
764 }
765
766 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
767 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
768 calib_tsens_point1_data[0] =
769 ((((tsens_base0_data) + tsens0_point1) << 2) |
770 TSENS_BIT_APPEND);
771 calib_tsens_point1_data[1] =
772 ((((tsens_base0_data) + tsens1_point1) << 2) |
773 TSENS_BIT_APPEND);
774 }
775
776 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
777 pr_debug("two point calibration calculation\n");
778 calib_tsens_point2_data[0] =
779 (((tsens_base1_data + tsens0_point2) << 2) |
780 TSENS_BIT_APPEND);
781 calib_tsens_point2_data[1] =
782 (((tsens_base1_data + tsens1_point2) << 2) |
783 TSENS_BIT_APPEND);
784 }
785
786compute_intercept_slope:
787 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
788 int32_t num = 0, den = 0;
789 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
790 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700791 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
792 i, tmdev->sensor[i].calib_data_point1,
793 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700794 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
795 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
796 temp_120_degc - temp_30_degc (x2 - x1) */
797 num = tmdev->sensor[i].calib_data_point2 -
798 tmdev->sensor[i].calib_data_point1;
799 num *= tmdev->tsens_factor;
800 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
801 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
802 }
803 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
804 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
805 tmdev->sensor[i].slope_mul_tsens_factor);
806 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
807 tmdev->prev_reading_avail = false;
808 }
809
810 return 0;
811}
812
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800813static int tsens_calib_8x26_sensors(void)
814{
815 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
816 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
817 int tsens5_point1 = 0, tsens6_point1 = 0, tsens6_point2 = 0;
818 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
819 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
820 int tsens_base1_data = 0, tsens_calibration_mode = 0;
821 uint32_t calib_data[6];
822 uint32_t calib_tsens_point1_data[7], calib_tsens_point2_data[7];
823
824 if (tmdev->calibration_less_mode)
825 goto calibration_less_mode;
826
827 for (i = 0; i < TSENS_8X26_MAIN_CALIB_ADDR_RANGE; i++)
828 calib_data[i] = readl_relaxed(
829 (TSENS_EEPROM_8X26_1(tmdev->tsens_calib_addr))
830 + (i * TSENS_SN_ADDR_OFFSET));
831 calib_data[4] = readl_relaxed(
832 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)));
833 calib_data[5] = readl_relaxed(
834 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
835
Siddartha Mohanadoss2114b2d2013-03-07 17:43:00 -0800836 tsens_calibration_mode = (calib_data[5] & TSENS_8X26_TSENS_CAL_SEL)
837 >> TSENS_8X26_CAL_SEL_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700838 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800839
840 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
841 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800842 tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
843 >> TSENS_8X26_BASE0_SHIFT;
844 tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
845 TSENS0_8X26_POINT1_SHIFT;
846 tsens1_point1 = calib_data[1] & TSENS1_8X26_POINT1_MASK;
847 tsens2_point1 = (calib_data[1] & TSENS2_8X26_POINT1_MASK) >>
848 TSENS2_8X26_POINT1_SHIFT;
849 tsens3_point1 = (calib_data[1] & TSENS3_8X26_POINT1_MASK) >>
850 TSENS3_8X26_POINT1_SHIFT;
851 tsens4_point1 = (calib_data[1] & TSENS4_8X26_POINT1_MASK) >>
852 TSENS4_8X26_POINT1_SHIFT;
853 tsens5_point1 = (calib_data[1] & TSENS5_8X26_POINT1_MASK) >>
854 TSENS5_8X26_POINT1_SHIFT;
855 tsens6_point1 = (calib_data[2] & TSENS6_8X26_POINT1_MASK) >>
856 TSENS6_8X26_POINT1_SHIFT;
857 } else
858 goto calibration_less_mode;
859
860 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800861 tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
862 tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
863 TSENS0_8X26_POINT2_SHIFT;
864 tsens1_point2 = (calib_data[3] & TSENS1_8X26_POINT2_MASK) >>
865 TSENS1_8X26_POINT2_SHIFT;
866 tsens2_point2 = (calib_data[3] & TSENS2_8X26_POINT2_MASK) >>
867 TSENS2_8X26_POINT2_SHIFT;
868 tsens3_point2 = (calib_data[3] & TSENS3_8X26_POINT2_MASK) >>
869 TSENS3_8X26_POINT2_SHIFT;
870 tsens4_point2 = (calib_data[4] & TSENS4_8X26_POINT2_MASK) >>
871 TSENS4_8X26_POINT2_SHIFT;
872 tsens5_point2 = (calib_data[4] & TSENS5_8X26_POINT2_MASK) >>
873 TSENS5_8X26_POINT2_SHIFT;
874 tsens6_point2 = (calib_data[5] & TSENS6_8X26_POINT2_MASK) >>
875 TSENS6_8X26_POINT2_SHIFT;
876 }
877
878 if (tsens_calibration_mode == 0) {
879calibration_less_mode:
880 pr_debug("TSENS is calibrationless mode\n");
881 for (i = 0; i < tmdev->tsens_num_sensor; i++)
882 calib_tsens_point2_data[i] = 780;
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700883 calib_tsens_point1_data[0] = 595;
884 calib_tsens_point1_data[1] = 625;
885 calib_tsens_point1_data[2] = 553;
886 calib_tsens_point1_data[3] = 578;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800887 calib_tsens_point1_data[4] = 505;
888 calib_tsens_point1_data[5] = 509;
889 calib_tsens_point1_data[6] = 507;
890 goto compute_intercept_slope;
891 }
892
893 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
894 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800895 calib_tsens_point1_data[0] =
896 ((((tsens_base0_data) + tsens0_point1) << 2) |
897 TSENS_BIT_APPEND);
898 calib_tsens_point1_data[1] =
899 ((((tsens_base0_data) + tsens1_point1) << 2) |
900 TSENS_BIT_APPEND);
901 calib_tsens_point1_data[2] =
902 ((((tsens_base0_data) + tsens2_point1) << 2) |
903 TSENS_BIT_APPEND);
904 calib_tsens_point1_data[3] =
905 ((((tsens_base0_data) + tsens3_point1) << 2) |
906 TSENS_BIT_APPEND);
907 calib_tsens_point1_data[4] =
908 ((((tsens_base0_data) + tsens4_point1) << 2) |
909 TSENS_BIT_APPEND);
910 calib_tsens_point1_data[5] =
911 ((((tsens_base0_data) + tsens5_point1) << 2) |
912 TSENS_BIT_APPEND);
913 calib_tsens_point1_data[6] =
914 ((((tsens_base0_data) + tsens6_point1) << 2) |
915 TSENS_BIT_APPEND);
916 }
917
918 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
919 pr_debug("two point calibration calculation\n");
920 calib_tsens_point2_data[0] =
921 (((tsens_base1_data + tsens0_point2) << 2) |
922 TSENS_BIT_APPEND);
923 calib_tsens_point2_data[1] =
924 (((tsens_base1_data + tsens1_point2) << 2) |
925 TSENS_BIT_APPEND);
926 calib_tsens_point2_data[2] =
927 (((tsens_base1_data + tsens2_point2) << 2) |
928 TSENS_BIT_APPEND);
929 calib_tsens_point2_data[3] =
930 (((tsens_base1_data + tsens3_point2) << 2) |
931 TSENS_BIT_APPEND);
932 calib_tsens_point2_data[4] =
933 (((tsens_base1_data + tsens4_point2) << 2) |
934 TSENS_BIT_APPEND);
935 calib_tsens_point2_data[5] =
936 (((tsens_base1_data + tsens5_point2) << 2) |
937 TSENS_BIT_APPEND);
938 calib_tsens_point2_data[6] =
939 (((tsens_base1_data + tsens6_point2) << 2) |
940 TSENS_BIT_APPEND);
941 }
942
943compute_intercept_slope:
944 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
945 int32_t num = 0, den = 0;
946 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
947 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700948 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
949 i, tmdev->sensor[i].calib_data_point1,
950 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800951 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
952 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
953 temp_120_degc - temp_30_degc (x2 - x1) */
954 num = tmdev->sensor[i].calib_data_point2 -
955 tmdev->sensor[i].calib_data_point1;
956 num *= tmdev->tsens_factor;
957 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
958 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
959 }
960 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
961 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
962 tmdev->sensor[i].slope_mul_tsens_factor);
963 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
964 tmdev->prev_reading_avail = false;
965 }
966
967 return 0;
968}
969
970static int tsens_calib_8974_sensors(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700971{
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700972 int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
973 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
974 int tsens5_point1 = 0, tsens6_point1 = 0, tsens7_point1 = 0;
975 int tsens8_point1 = 0, tsens9_point1 = 0, tsens10_point1 = 0;
976 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
977 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
978 int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
979 int tsens9_point2 = 0, tsens10_point2 = 0;
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700980 int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700981 uint32_t calib_data[6], calib_redun_sel, calib_data_backup[4];
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700982 uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11];
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700983
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -0700984 if (tmdev->calibration_less_mode)
985 goto calibration_less_mode;
986
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700987 calib_redun_sel = readl_relaxed(
988 TSENS_EEPROM_REDUNDANCY_SEL(tmdev->tsens_calib_addr));
989 calib_redun_sel = calib_redun_sel & TSENS_QFPROM_BACKUP_REDUN_SEL;
990 calib_redun_sel >>= TSENS_QFPROM_BACKUP_REDUN_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700991 pr_debug("calib_redun_sel:%x\n", calib_redun_sel);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700992
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700993 for (i = 0; i < TSENS_MAIN_CALIB_ADDR_RANGE; i++) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700994 calib_data[i] = readl_relaxed(
995 (TSENS_EEPROM(tmdev->tsens_calib_addr))
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700996 + (i * TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700997 pr_debug("calib raw data row%d:0x%x\n", i, calib_data[i]);
998 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700999
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001000 if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) {
1001 tsens_calibration_mode = (calib_data[4] & TSENS_CAL_SEL_0_1)
1002 >> TSENS_CAL_SEL_SHIFT;
1003 temp = (calib_data[5] & TSENS_CAL_SEL_2)
1004 >> TSENS_CAL_SEL_SHIFT_2;
1005 tsens_calibration_mode |= temp;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001006 pr_debug("backup calib mode:%x\n", calib_redun_sel);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001007
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001008 for (i = 0; i < TSENS_BACKUP_CALIB_ADDR_RANGE; i++)
1009 calib_data_backup[i] = readl_relaxed(
1010 (TSENS_EEPROM_BACKUP_REGION(
1011 tmdev->tsens_calib_addr))
1012 + (i * TSENS_SN_ADDR_OFFSET));
1013
1014 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB)
1015 || (tsens_calibration_mode ==
1016 TSENS_TWO_POINT_CALIB) ||
1017 (tsens_calibration_mode ==
1018 TSENS_ONE_POINT_CALIB_OPTION_2)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001019 tsens_base1_data = (calib_data_backup[0] &
1020 TSENS_BASE1_MASK);
1021 tsens0_point1 = (calib_data_backup[0] &
1022 TSENS0_POINT1_MASK) >>
1023 TSENS0_POINT1_SHIFT;
1024 tsens1_point1 = (calib_data_backup[0] &
1025 TSENS1_POINT1_MASK) >> TSENS1_POINT1_SHIFT;
1026 tsens2_point1 = (calib_data_backup[0] &
1027 TSENS2_POINT1_MASK) >> TSENS2_POINT1_SHIFT;
1028 tsens3_point1 = (calib_data_backup[0] &
1029 TSENS3_POINT1_MASK) >> TSENS3_POINT1_SHIFT;
1030 tsens4_point1 = (calib_data_backup[1] &
1031 TSENS4_POINT1_MASK);
1032 tsens5_point1 = (calib_data_backup[1] &
1033 TSENS5_POINT1_MASK) >> TSENS5_POINT1_SHIFT;
1034 tsens6_point1 = (calib_data_backup[1] &
1035 TSENS6_POINT1_MASK) >> TSENS6_POINT1_SHIFT;
1036 tsens7_point1 = (calib_data_backup[1] &
1037 TSENS7_POINT1_MASK) >> TSENS7_POINT1_SHIFT;
1038 tsens8_point1 = (calib_data_backup[2] &
1039 TSENS8_POINT1_MASK_BACKUP) >>
1040 TSENS8_POINT1_SHIFT;
1041 tsens9_point1 = (calib_data_backup[2] &
1042 TSENS9_POINT1_MASK_BACKUP) >>
1043 TSENS9_POINT1_BACKUP_SHIFT;
1044 tsens10_point1 = (calib_data_backup[2] &
1045 TSENS10_POINT1_MASK_BACKUP) >>
1046 TSENS10_POINT1_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001047 } else
1048 goto calibration_less_mode;
1049
1050 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001051 tsens_base2_data = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001052 TSENS_BASE2_BACKUP_MASK) >>
1053 TSENS_POINT2_BASE_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001054 tsens0_point2 = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001055 TSENS0_POINT2_BACKUP_MASK) >>
1056 TSENS0_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001057 tsens1_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001058 TSENS1_POINT2_BACKUP_MASK);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001059 tsens2_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001060 TSENS2_POINT2_BACKUP_MASK) >>
1061 TSENS2_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001062 tsens3_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001063 TSENS3_POINT2_BACKUP_MASK) >>
1064 TSENS3_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001065 tsens4_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001066 TSENS4_POINT2_BACKUP_MASK) >>
1067 TSENS4_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001068 tsens5_point2 = (calib_data[4] &
1069 TSENS5_POINT2_BACKUP_MASK) >>
1070 TSENS5_POINT2_BACKUP_SHIFT;
1071 tsens6_point2 = (calib_data[5] &
1072 TSENS6_POINT2_BACKUP_MASK);
1073 tsens7_point2 = (calib_data[5] &
1074 TSENS7_POINT2_BACKUP_MASK) >>
1075 TSENS7_POINT2_BACKUP_SHIFT;
1076 tsens8_point2 = (calib_data[5] &
1077 TSENS8_POINT2_BACKUP_MASK) >>
1078 TSENS8_POINT2_BACKUP_SHIFT;
1079 tsens9_point2 = (calib_data[5] &
1080 TSENS9_POINT2_BACKUP_MASK) >>
1081 TSENS9_POINT2_BACKUP_SHIFT;
1082 tsens10_point2 = (calib_data[5] &
1083 TSENS10_POINT2_BACKUP_MASK)
1084 >> TSENS10_POINT2_BACKUP_SHIFT;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001085 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001086 } else {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001087 tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
1088 >> TSENS_CAL_SEL_SHIFT;
1089 temp = (calib_data[3] & TSENS_CAL_SEL_2)
1090 >> TSENS_CAL_SEL_SHIFT_2;
1091 tsens_calibration_mode |= temp;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001092 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001093 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) ||
1094 (tsens_calibration_mode ==
1095 TSENS_ONE_POINT_CALIB_OPTION_2) ||
1096 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001097 tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
1098 tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
1099 TSENS0_POINT1_SHIFT;
1100 tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
1101 TSENS1_POINT1_SHIFT;
1102 tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
1103 TSENS2_POINT1_SHIFT;
1104 tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
1105 TSENS3_POINT1_SHIFT;
1106 tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
1107 tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
1108 TSENS5_POINT1_SHIFT;
1109 tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
1110 TSENS6_POINT1_SHIFT;
1111 tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
1112 TSENS7_POINT1_SHIFT;
1113 tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
1114 TSENS8_POINT1_SHIFT;
1115 tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
1116 tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK)
1117 >> TSENS10_POINT1_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001118 } else
1119 goto calibration_less_mode;
1120
1121 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001122 tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
1123 TSENS_POINT2_BASE_SHIFT;
1124 tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
1125 TSENS0_POINT2_SHIFT;
1126 tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
1127 TSENS1_POINT2_SHIFT;
1128 tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
1129 tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
1130 TSENS3_POINT2_SHIFT;
1131 tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
1132 TSENS4_POINT2_SHIFT;
1133 tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
1134 TSENS5_POINT2_SHIFT;
1135 tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
1136 TSENS6_POINT2_SHIFT;
1137 tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
1138 tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
1139 TSENS8_POINT2_SHIFT;
1140 tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
1141 TSENS9_POINT2_SHIFT;
1142 tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK)
1143 >> TSENS10_POINT2_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001144 }
1145
1146 if (tsens_calibration_mode == 0) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001147calibration_less_mode:
1148 pr_debug("TSENS is calibrationless mode\n");
1149 for (i = 0; i < tmdev->tsens_num_sensor; i++)
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001150 calib_tsens_point2_data[i] = 780;
1151 calib_tsens_point1_data[0] = 502;
1152 calib_tsens_point1_data[1] = 509;
1153 calib_tsens_point1_data[2] = 503;
1154 calib_tsens_point1_data[3] = 509;
1155 calib_tsens_point1_data[4] = 505;
1156 calib_tsens_point1_data[5] = 509;
1157 calib_tsens_point1_data[6] = 507;
1158 calib_tsens_point1_data[7] = 510;
1159 calib_tsens_point1_data[8] = 508;
1160 calib_tsens_point1_data[9] = 509;
1161 calib_tsens_point1_data[10] = 508;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001162 goto compute_intercept_slope;
1163 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001164 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001165
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001166 if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001167 calib_tsens_point1_data[0] =
1168 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1169 + tsens0_point1;
1170 calib_tsens_point1_data[1] =
1171 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1172 + tsens1_point1;
1173 calib_tsens_point1_data[2] =
1174 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1175 + tsens2_point1;
1176 calib_tsens_point1_data[3] =
1177 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1178 + tsens3_point1;
1179 calib_tsens_point1_data[4] =
1180 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1181 + tsens4_point1;
1182 calib_tsens_point1_data[5] =
1183 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1184 + tsens5_point1;
1185 calib_tsens_point1_data[6] =
1186 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1187 + tsens6_point1;
1188 calib_tsens_point1_data[7] =
1189 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1190 + tsens7_point1;
1191 calib_tsens_point1_data[8] =
1192 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1193 + tsens8_point1;
1194 calib_tsens_point1_data[9] =
1195 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1196 + tsens9_point1;
1197 calib_tsens_point1_data[10] =
1198 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1199 + tsens10_point1;
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001200 }
1201
Siddartha Mohanadoss4d9815a2012-09-09 17:16:05 -07001202 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
1203 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001204 pr_debug("one point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001205 calib_tsens_point1_data[0] =
1206 ((((tsens_base1_data) + tsens0_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001207 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001208 calib_tsens_point1_data[1] =
1209 ((((tsens_base1_data) + tsens1_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001210 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001211 calib_tsens_point1_data[2] =
1212 ((((tsens_base1_data) + tsens2_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001213 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001214 calib_tsens_point1_data[3] =
1215 ((((tsens_base1_data) + tsens3_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001216 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001217 calib_tsens_point1_data[4] =
1218 ((((tsens_base1_data) + tsens4_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001219 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001220 calib_tsens_point1_data[5] =
1221 ((((tsens_base1_data) + tsens5_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001222 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001223 calib_tsens_point1_data[6] =
1224 ((((tsens_base1_data) + tsens6_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001225 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001226 calib_tsens_point1_data[7] =
1227 ((((tsens_base1_data) + tsens7_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001228 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001229 calib_tsens_point1_data[8] =
1230 ((((tsens_base1_data) + tsens8_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001231 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001232 calib_tsens_point1_data[9] =
1233 ((((tsens_base1_data) + tsens9_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001234 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001235 calib_tsens_point1_data[10] =
1236 ((((tsens_base1_data) + tsens10_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001237 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001238 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001239
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001240 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001241 pr_debug("two point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001242 calib_tsens_point2_data[0] =
1243 (((tsens_base2_data + tsens0_point2) << 2) |
1244 TSENS_BIT_APPEND);
1245 calib_tsens_point2_data[1] =
1246 (((tsens_base2_data + tsens1_point2) << 2) |
1247 TSENS_BIT_APPEND);
1248 calib_tsens_point2_data[2] =
1249 (((tsens_base2_data + tsens2_point2) << 2) |
1250 TSENS_BIT_APPEND);
1251 calib_tsens_point2_data[3] =
1252 (((tsens_base2_data + tsens3_point2) << 2) |
1253 TSENS_BIT_APPEND);
1254 calib_tsens_point2_data[4] =
1255 (((tsens_base2_data + tsens4_point2) << 2) |
1256 TSENS_BIT_APPEND);
1257 calib_tsens_point2_data[5] =
1258 (((tsens_base2_data + tsens5_point2) << 2) |
1259 TSENS_BIT_APPEND);
1260 calib_tsens_point2_data[6] =
1261 (((tsens_base2_data + tsens6_point2) << 2) |
1262 TSENS_BIT_APPEND);
1263 calib_tsens_point2_data[7] =
1264 (((tsens_base2_data + tsens7_point2) << 2) |
1265 TSENS_BIT_APPEND);
1266 calib_tsens_point2_data[8] =
1267 (((tsens_base2_data + tsens8_point2) << 2) |
1268 TSENS_BIT_APPEND);
1269 calib_tsens_point2_data[9] =
1270 (((tsens_base2_data + tsens9_point2) << 2) |
1271 TSENS_BIT_APPEND);
1272 calib_tsens_point2_data[10] =
1273 (((tsens_base2_data + tsens10_point2) << 2) |
1274 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001275 }
1276
1277compute_intercept_slope:
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001278 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1279 int32_t num = 0, den = 0;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001280 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
1281 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001282 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
1283 i, tmdev->sensor[i].calib_data_point1,
1284 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001285 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001286 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
1287 temp_120_degc - temp_30_degc (x2 - x1) */
1288 num = tmdev->sensor[i].calib_data_point2 -
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001289 tmdev->sensor[i].calib_data_point1;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001290 num *= tmdev->tsens_factor;
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001291 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001292 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001293 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001294 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
1295 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
1296 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001297 pr_debug("offset:%d\n", tmdev->sensor[i].offset);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001298 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
1299 tmdev->prev_reading_avail = false;
1300 }
1301
1302 return 0;
1303}
1304
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001305static int tsens_calib_sensors(void)
1306{
1307 int rc = 0;
1308
1309 if (!tmdev)
1310 return -ENODEV;
1311
1312 if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8974)
1313 rc = tsens_calib_8974_sensors();
1314 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
1315 rc = tsens_calib_8x26_sensors();
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -07001316 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X10)
1317 rc = tsens_calib_8x10_sensors();
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001318 else
1319 rc = -ENODEV;
1320
1321 return rc;
1322}
1323
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001324static int get_device_tree_data(struct platform_device *pdev)
1325{
1326 const struct device_node *of_node = pdev->dev.of_node;
1327 struct resource *res_mem = NULL;
1328 u32 *tsens_slope_data;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001329 u32 *sensor_id;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001330 u32 rc = 0, i, tsens_num_sensors, calib_type;
1331 const char *tsens_calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001332
1333 rc = of_property_read_u32(of_node,
1334 "qcom,sensors", &tsens_num_sensors);
1335 if (rc) {
1336 dev_err(&pdev->dev, "missing sensor number\n");
1337 return -ENODEV;
1338 }
1339
1340 tsens_slope_data = devm_kzalloc(&pdev->dev,
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001341 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001342 if (!tsens_slope_data) {
1343 dev_err(&pdev->dev, "can not allocate slope data\n");
1344 return -ENOMEM;
1345 }
1346
1347 rc = of_property_read_u32_array(of_node,
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001348 "qcom,slope", tsens_slope_data, tsens_num_sensors);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001349 if (rc) {
1350 dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
1351 return rc;
1352 };
1353
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001354 tsens_calib_mode = of_get_property(of_node,
1355 "qcom,calib-mode", NULL);
1356 if (!strncmp(tsens_calib_mode, "fuse_map1", 9))
1357 calib_type = TSENS_CALIB_FUSE_MAP_8974;
1358 else if (!strncmp(tsens_calib_mode, "fuse_map2", 9))
1359 calib_type = TSENS_CALIB_FUSE_MAP_8X26;
1360 else if (!strncmp(tsens_calib_mode, "fuse_map3", 9))
1361 calib_type = TSENS_CALIB_FUSE_MAP_8X10;
1362 else {
1363 pr_err("%s: Invalid calibration property\n", __func__);
1364 return -EINVAL;
1365 }
1366
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001367 tmdev = devm_kzalloc(&pdev->dev,
1368 sizeof(struct tsens_tm_device) +
1369 tsens_num_sensors *
1370 sizeof(struct tsens_tm_device_sensor),
1371 GFP_KERNEL);
1372 if (tmdev == NULL) {
1373 pr_err("%s: kzalloc() failed.\n", __func__);
1374 return -ENOMEM;
1375 }
1376
1377 for (i = 0; i < tsens_num_sensors; i++)
1378 tmdev->sensor[i].slope_mul_tsens_factor = tsens_slope_data[i];
1379 tmdev->tsens_factor = TSENS_SLOPE_FACTOR;
1380 tmdev->tsens_num_sensor = tsens_num_sensors;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001381 tmdev->calibration_less_mode = of_property_read_bool(of_node,
1382 "qcom,calibration-less-mode");
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001383 tmdev->calib_mode = calib_type;
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -07001384 tmdev->tsens_local_init = of_property_read_bool(of_node,
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -07001385 "qcom,tsens-local-init");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001386
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001387 sensor_id = devm_kzalloc(&pdev->dev,
1388 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
1389 if (!sensor_id) {
1390 dev_err(&pdev->dev, "can not allocate sensor id\n");
1391 return -ENOMEM;
1392 }
1393
1394 rc = of_property_read_u32_array(of_node,
1395 "qcom,sensor-id", sensor_id, tsens_num_sensors);
1396 if (rc) {
1397 pr_debug("Default sensor id mapping\n");
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001398 for (i = 0; i < tsens_num_sensors; i++) {
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001399 tmdev->sensor[i].sensor_hw_num = i;
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001400 tmdev->sensor[i].sensor_sw_id = i;
1401 }
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001402 } else {
1403 pr_debug("Use specified sensor id mapping\n");
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001404 for (i = 0; i < tsens_num_sensors; i++) {
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001405 tmdev->sensor[i].sensor_hw_num = sensor_id[i];
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001406 tmdev->sensor[i].sensor_sw_id = i;
1407 }
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001408 }
1409
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001410 tmdev->tsens_irq = platform_get_irq(pdev, 0);
1411 if (tmdev->tsens_irq < 0) {
1412 pr_err("Invalid get irq\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001413 rc = tmdev->tsens_irq;
1414 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001415 }
1416
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001417 /* TSENS register region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001418 tmdev->res_tsens_mem = platform_get_resource_byname(pdev,
1419 IORESOURCE_MEM, "tsens_physical");
1420 if (!tmdev->res_tsens_mem) {
1421 pr_err("Could not get tsens physical address resource\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001422 rc = -EINVAL;
1423 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001424 }
1425
1426 tmdev->tsens_len = tmdev->res_tsens_mem->end -
1427 tmdev->res_tsens_mem->start + 1;
1428
1429 res_mem = request_mem_region(tmdev->res_tsens_mem->start,
1430 tmdev->tsens_len, tmdev->res_tsens_mem->name);
1431 if (!res_mem) {
1432 pr_err("Request tsens physical memory region failed\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001433 rc = -EINVAL;
1434 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001435 }
1436
1437 tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
1438 if (!tmdev->tsens_addr) {
1439 pr_err("Failed to IO map TSENS registers.\n");
1440 rc = -EINVAL;
1441 goto fail_unmap_tsens_region;
1442 }
1443
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001444 /* TSENS calibration region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001445 tmdev->res_calib_mem = platform_get_resource_byname(pdev,
1446 IORESOURCE_MEM, "tsens_eeprom_physical");
1447 if (!tmdev->res_calib_mem) {
1448 pr_err("Could not get qfprom physical address resource\n");
1449 rc = -EINVAL;
1450 goto fail_unmap_tsens;
1451 }
1452
1453 tmdev->calib_len = tmdev->res_calib_mem->end -
1454 tmdev->res_calib_mem->start + 1;
1455
1456 res_mem = request_mem_region(tmdev->res_calib_mem->start,
1457 tmdev->calib_len, tmdev->res_calib_mem->name);
1458 if (!res_mem) {
1459 pr_err("Request calibration memory region failed\n");
1460 rc = -EINVAL;
1461 goto fail_unmap_tsens;
1462 }
1463
1464 tmdev->tsens_calib_addr = ioremap(res_mem->start,
1465 tmdev->calib_len);
1466 if (!tmdev->tsens_calib_addr) {
1467 pr_err("Failed to IO map EEPROM registers.\n");
1468 rc = -EINVAL;
1469 goto fail_unmap_calib_region;
1470 }
1471
1472 return 0;
1473
1474fail_unmap_calib_region:
1475 if (tmdev->res_calib_mem)
1476 release_mem_region(tmdev->res_calib_mem->start,
1477 tmdev->calib_len);
1478fail_unmap_tsens:
1479 if (tmdev->tsens_addr)
1480 iounmap(tmdev->tsens_addr);
1481fail_unmap_tsens_region:
1482 if (tmdev->res_tsens_mem)
1483 release_mem_region(tmdev->res_tsens_mem->start,
1484 tmdev->tsens_len);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001485fail_tmdev:
1486 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001487 return rc;
1488}
1489
1490static int __devinit tsens_tm_probe(struct platform_device *pdev)
1491{
1492 int rc;
1493
1494 if (tmdev) {
1495 pr_err("TSENS device already in use\n");
1496 return -EBUSY;
1497 }
1498
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001499 if (pdev->dev.of_node) {
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001500 rc = get_device_tree_data(pdev);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001501 if (rc) {
1502 pr_err("Error reading TSENS DT\n");
1503 return rc;
1504 }
1505 } else
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001506 return -ENODEV;
1507
1508 tmdev->pdev = pdev;
1509 rc = tsens_calib_sensors();
Michael Bohanb89167e2012-10-04 16:24:23 -07001510 if (rc < 0) {
1511 pr_err("Calibration failed\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001512 goto fail;
Michael Bohanb89167e2012-10-04 16:24:23 -07001513 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001514
1515 tsens_hw_init();
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001516
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001517 tmdev->prev_reading_avail = true;
1518
1519 platform_set_drvdata(pdev, tmdev);
1520
1521 return 0;
1522fail:
1523 if (tmdev->tsens_calib_addr)
1524 iounmap(tmdev->tsens_calib_addr);
1525 if (tmdev->res_calib_mem)
1526 release_mem_region(tmdev->res_calib_mem->start,
1527 tmdev->calib_len);
1528 if (tmdev->tsens_addr)
1529 iounmap(tmdev->tsens_addr);
1530 if (tmdev->res_tsens_mem)
1531 release_mem_region(tmdev->res_tsens_mem->start,
1532 tmdev->tsens_len);
Michael Bohanb89167e2012-10-04 16:24:23 -07001533 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001534
1535 return rc;
1536}
1537
1538static int __devinit _tsens_register_thermal(void)
1539{
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001540 struct platform_device *pdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001541 int rc, i;
1542
1543 if (!tmdev) {
1544 pr_err("%s: TSENS early init not done\n", __func__);
1545 return -ENODEV;
1546 }
1547
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001548 pdev = tmdev->pdev;
1549
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001550 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1551 char name[18];
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001552 snprintf(name, sizeof(name), "tsens_tz_sensor%d",
1553 tmdev->sensor[i].sensor_hw_num);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001554 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001555 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
1556 TSENS_TRIP_NUM, &tmdev->sensor[i],
1557 &tsens_thermal_zone_ops, 0, 0, 0, 0);
1558 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
1559 pr_err("%s: thermal_zone_device_register() failed.\n",
1560 __func__);
1561 rc = -ENODEV;
1562 goto fail;
1563 }
1564 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001565
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001566 rc = request_irq(tmdev->tsens_irq, tsens_isr,
1567 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
1568 if (rc < 0) {
1569 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
1570 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1571 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1572 goto fail;
Siddartha Mohanadossb9be9812013-02-13 11:03:32 -08001573 } else {
1574 enable_irq_wake(tmdev->tsens_irq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001575 }
1576 platform_set_drvdata(pdev, tmdev);
1577
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -07001578 INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
1579
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001580 return 0;
1581fail:
1582 if (tmdev->tsens_calib_addr)
1583 iounmap(tmdev->tsens_calib_addr);
1584 if (tmdev->res_calib_mem)
1585 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001586 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001587 if (tmdev->tsens_addr)
1588 iounmap(tmdev->tsens_addr);
1589 if (tmdev->res_tsens_mem)
1590 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001591 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001592 return rc;
1593}
1594
1595static int __devexit tsens_tm_remove(struct platform_device *pdev)
1596{
1597 struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
1598 int i;
1599
1600 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1601 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1602 if (tmdev->tsens_calib_addr)
1603 iounmap(tmdev->tsens_calib_addr);
1604 if (tmdev->res_calib_mem)
1605 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001606 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001607 if (tmdev->tsens_addr)
1608 iounmap(tmdev->tsens_addr);
1609 if (tmdev->res_tsens_mem)
1610 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001611 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001612 free_irq(tmdev->tsens_irq, tmdev);
1613 platform_set_drvdata(pdev, NULL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001614
1615 return 0;
1616}
1617
1618static struct of_device_id tsens_match[] = {
1619 { .compatible = "qcom,msm-tsens",
1620 },
1621 {}
1622};
1623
1624static struct platform_driver tsens_tm_driver = {
1625 .probe = tsens_tm_probe,
1626 .remove = tsens_tm_remove,
1627 .driver = {
1628 .name = "msm-tsens",
1629 .owner = THIS_MODULE,
1630 .of_match_table = tsens_match,
1631 },
1632};
1633
Siddartha Mohanadoss4cef5f42013-04-11 13:59:41 -07001634int __init tsens_tm_init_driver(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001635{
1636 return platform_driver_register(&tsens_tm_driver);
1637}
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001638
1639static int __init tsens_thermal_register(void)
1640{
1641 return _tsens_register_thermal();
1642}
1643module_init(tsens_thermal_register);
1644
1645static void __exit _tsens_tm_remove(void)
1646{
1647 platform_driver_unregister(&tsens_tm_driver);
1648}
1649module_exit(_tsens_tm_remove);
1650
1651MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
1652MODULE_LICENSE("GPL v2");