blob: 613af4ef1195504dd9452e36e7e849bbbf0d24a3 [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>
Matt Wagantall83026d62013-05-22 18:07:04 -070020#include <linux/workqueue.h>
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070021#include <linux/delay.h>
22#include <linux/kernel.h>
23#include <linux/io.h>
24#include <linux/slab.h>
25#include <linux/msm_tsens.h>
26#include <linux/err.h>
27#include <linux/of.h>
28
29#include <mach/msm_iomap.h>
30
31#define TSENS_DRIVER_NAME "msm-tsens"
32/* TSENS register info */
33#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n) ((n) + 0x1000)
34#define TSENS_INTERRUPT_EN BIT(0)
35
36#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n) ((n) + 0x1004)
37#define TSENS_UPPER_STATUS_CLR BIT(21)
38#define TSENS_LOWER_STATUS_CLR BIT(20)
39#define TSENS_UPPER_THRESHOLD_MASK 0xffc00
40#define TSENS_LOWER_THRESHOLD_MASK 0x3ff
41#define TSENS_UPPER_THRESHOLD_SHIFT 10
42
43#define TSENS_S0_STATUS_ADDR(n) ((n) + 0x1030)
44#define TSENS_SN_ADDR_OFFSET 0x4
45#define TSENS_SN_STATUS_TEMP_MASK 0x3ff
46#define TSENS_SN_STATUS_LOWER_STATUS BIT(11)
47#define TSENS_SN_STATUS_UPPER_STATUS BIT(12)
48#define TSENS_STATUS_ADDR_OFFSET 2
49
50#define TSENS_TRDY_ADDR(n) ((n) + 0x105c)
51#define TSENS_TRDY_MASK BIT(0)
52
53#define TSENS_CTRL_ADDR(n) (n)
Siddartha Mohanadossa0d74c62012-10-23 10:38:41 -070054#define TSENS_EN BIT(0)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070055#define TSENS_SW_RST BIT(1)
Siddartha Mohanadossa0d74c62012-10-23 10:38:41 -070056#define TSENS_ADC_CLK_SEL BIT(2)
57#define TSENS_SENSOR0_SHIFT 3
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -070058#define TSENS_62_5_MS_MEAS_PERIOD 1
Siddartha Mohanadossa0d74c62012-10-23 10:38:41 -070059#define TSENS_312_5_MS_MEAS_PERIOD 2
60#define TSENS_MEAS_PERIOD_SHIFT 18
61
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070062#define TSENS_SN_MIN_MAX_STATUS_CTRL(n) ((n) + 4)
63#define TSENS_GLOBAL_CONFIG(n) ((n) + 0x34)
64#define TSENS_S0_MAIN_CONFIG(n) ((n) + 0x38)
65#define TSENS_SN_REMOTE_CONFIG(n) ((n) + 0x3c)
66
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070067#define TSENS_EEPROM(n) ((n) + 0xd0)
Siddartha Mohanadoss49741992013-02-22 10:30:04 -080068#define TSENS_EEPROM_REDUNDANCY_SEL(n) ((n) + 0x444)
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070069#define TSENS_EEPROM_BACKUP_REGION(n) ((n) + 0x440)
70
71#define TSENS_MAIN_CALIB_ADDR_RANGE 6
72#define TSENS_BACKUP_CALIB_ADDR_RANGE 4
73
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -080074#define TSENS_EEPROM_8X26_1(n) ((n) + 0x1c0)
75#define TSENS_EEPROM_8X26_2(n) ((n) + 0x444)
76#define TSENS_8X26_MAIN_CALIB_ADDR_RANGE 4
77
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -070078#define TSENS_EEPROM_8X10_1(n) ((n) + 0x1a4)
79#define TSENS_EEPROM_8X10_1_OFFSET 8
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -070080#define TSENS_EEPROM_8X10_2(n) ((n) + 0x1a8)
81#define TSENS_EEPROM_8X10_SPARE_1(n) ((n) + 0xd8)
82#define TSENS_EEPROM_8X10_SPARE_2(n) ((n) + 0xdc)
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -070083
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070084/* TSENS calibration Mask data */
85#define TSENS_BASE1_MASK 0xff
86#define TSENS0_POINT1_MASK 0x3f00
87#define TSENS1_POINT1_MASK 0xfc000
88#define TSENS2_POINT1_MASK 0x3f00000
89#define TSENS3_POINT1_MASK 0xfc000000
90#define TSENS4_POINT1_MASK 0x3f
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070091#define TSENS5_POINT1_MASK 0xfc0
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070092#define TSENS6_POINT1_MASK 0x3f000
93#define TSENS7_POINT1_MASK 0xfc0000
94#define TSENS8_POINT1_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070095#define TSENS8_POINT1_MASK_BACKUP 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070096#define TSENS9_POINT1_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070097#define TSENS9_POINT1_MASK_BACKUP 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -080098#define TSENS10_POINT1_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070099#define TSENS10_POINT1_MASK_BACKUP 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700100#define TSENS_CAL_SEL_0_1 0xc0000000
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700101#define TSENS_CAL_SEL_2 0x40000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700102#define TSENS_CAL_SEL_SHIFT 30
103#define TSENS_CAL_SEL_SHIFT_2 28
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700104#define TSENS_ONE_POINT_CALIB 0x1
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700105#define TSENS_ONE_POINT_CALIB_OPTION_2 0x2
106#define TSENS_TWO_POINT_CALIB 0x3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700107
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700108#define TSENS0_POINT1_SHIFT 8
109#define TSENS1_POINT1_SHIFT 14
110#define TSENS2_POINT1_SHIFT 20
111#define TSENS3_POINT1_SHIFT 26
112#define TSENS5_POINT1_SHIFT 6
113#define TSENS6_POINT1_SHIFT 12
114#define TSENS7_POINT1_SHIFT 18
115#define TSENS8_POINT1_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700116#define TSENS9_POINT1_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700117#define TSENS10_POINT1_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700118#define TSENS10_POINT1_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700119
120#define TSENS_POINT2_BASE_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700121#define TSENS_POINT2_BASE_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700122#define TSENS0_POINT2_SHIFT 20
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700123#define TSENS0_POINT2_BACKUP_SHIFT 26
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700124#define TSENS1_POINT2_SHIFT 26
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700125#define TSENS2_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700126#define TSENS3_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700127#define TSENS3_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700128#define TSENS4_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700129#define TSENS4_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700130#define TSENS5_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700131#define TSENS5_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700132#define TSENS6_POINT2_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700133#define TSENS7_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700134#define TSENS8_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700135#define TSENS8_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700136#define TSENS9_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700137#define TSENS9_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700138#define TSENS10_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700139#define TSENS10_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700140
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700141#define TSENS_BASE2_MASK 0xff000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700142#define TSENS_BASE2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700143#define TSENS0_POINT2_MASK 0x3f00000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700144#define TSENS0_POINT2_BACKUP_MASK 0xfc000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700145#define TSENS1_POINT2_MASK 0xfc000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700146#define TSENS1_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700147#define TSENS2_POINT2_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700148#define TSENS2_POINT2_BACKUP_MASK 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800149#define TSENS3_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700150#define TSENS3_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700151#define TSENS4_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700152#define TSENS4_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700153#define TSENS5_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700154#define TSENS5_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700155#define TSENS6_POINT2_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700156#define TSENS6_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700157#define TSENS7_POINT2_MASK 0x3f
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800158#define TSENS7_POINT2_BACKUP_MASK 0xfc0
159#define TSENS8_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700160#define TSENS8_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700161#define TSENS9_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700162#define TSENS9_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700163#define TSENS10_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700164#define TSENS10_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700165
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800166#define TSENS_8X26_BASE0_MASK 0x1fe000
Siddartha Mohanadoss49149832013-09-06 15:06:03 -0700167#define TSENS0_8X26_POINT1_MASK 0x7e00000
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800168#define TSENS1_8X26_POINT1_MASK 0x3f
169#define TSENS2_8X26_POINT1_MASK 0xfc0
170#define TSENS3_8X26_POINT1_MASK 0x3f000
171#define TSENS4_8X26_POINT1_MASK 0xfc0000
172#define TSENS5_8X26_POINT1_MASK 0x3f000000
173#define TSENS6_8X26_POINT1_MASK 0x3f00000
174#define TSENS_8X26_TSENS_CAL_SEL 0xe0000000
175#define TSENS_8X26_BASE1_MASK 0xff
176#define TSENS0_8X26_POINT2_MASK 0x3f00
Siddartha Mohanadoss49149832013-09-06 15:06:03 -0700177#define TSENS1_8X26_POINT2_MASK 0xfc000
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800178#define TSENS2_8X26_POINT2_MASK 0x3f00000
179#define TSENS3_8X26_POINT2_MASK 0xfc000000
Siddartha Mohanadoss49149832013-09-06 15:06:03 -0700180#define TSENS4_8X26_POINT2_MASK 0x3f00000
181#define TSENS5_8X26_POINT2_MASK 0xfc000000
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800182#define TSENS6_8X26_POINT2_MASK 0x7e0000
183
184#define TSENS_8X26_CAL_SEL_SHIFT 29
185#define TSENS_8X26_BASE0_SHIFT 13
186#define TSENS0_8X26_POINT1_SHIFT 21
187#define TSENS2_8X26_POINT1_SHIFT 6
188#define TSENS3_8X26_POINT1_SHIFT 12
189#define TSENS4_8X26_POINT1_SHIFT 18
190#define TSENS5_8X26_POINT1_SHIFT 24
191#define TSENS6_8X26_POINT1_SHIFT 20
192
193#define TSENS0_8X26_POINT2_SHIFT 8
194#define TSENS1_8X26_POINT2_SHIFT 14
195#define TSENS2_8X26_POINT2_SHIFT 20
196#define TSENS3_8X26_POINT2_SHIFT 26
197#define TSENS4_8X26_POINT2_SHIFT 20
198#define TSENS5_8X26_POINT2_SHIFT 26
199#define TSENS6_8X26_POINT2_SHIFT 17
200
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700201#define TSENS_8X10_CAL_SEL_SHIFT 28
202#define TSENS_8X10_BASE1_SHIFT 8
203#define TSENS0_8X10_POINT1_SHIFT 16
204#define TSENS0_8X10_POINT2_SHIFT 22
205#define TSENS1_8X10_POINT2_SHIFT 6
Siddartha Mohanadoss74c700c2013-05-07 20:33:42 -0700206#define TSENS_8X10_BASE0_MASK 0xff
207#define TSENS_8X10_BASE1_MASK 0xff00
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700208#define TSENS0_8X10_POINT1_MASK 0x3f0000
209#define TSENS0_8X10_POINT2_MASK 0xfc00000
210#define TSENS_8X10_TSENS_CAL_SEL 0x70000000
211#define TSENS1_8X10_POINT1_MASK 0x3f
212#define TSENS1_8X10_POINT2_MASK 0xfc0
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -0700213#define TSENS_8X10_REDUN_SEL_MASK 0x6000000
214#define TSENS_8X10_REDUN_SEL_SHIFT 25
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700215
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700216#define TSENS_BIT_APPEND 0x3
217#define TSENS_CAL_DEGC_POINT1 30
218#define TSENS_CAL_DEGC_POINT2 120
219#define TSENS_SLOPE_FACTOR 1000
220
221/* TSENS register data */
222#define TSENS_TRDY_RDY_MIN_TIME 2000
223#define TSENS_TRDY_RDY_MAX_TIME 2100
224#define TSENS_THRESHOLD_MAX_CODE 0x3ff
225#define TSENS_THRESHOLD_MIN_CODE 0x0
226
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700227#define TSENS_GLOBAL_INIT_DATA 0x302f16c
228#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700229#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700230#define TSENS_SN_REMOTE_CFG_DATA 0x11c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700231
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700232#define TSENS_QFPROM_BACKUP_SEL 0x3
233#define TSENS_QFPROM_BACKUP_REDUN_SEL 0xe0000000
234#define TSENS_QFPROM_BACKUP_REDUN_SHIFT 29
235
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800236enum tsens_calib_fuse_map_type {
237 TSENS_CALIB_FUSE_MAP_8974 = 0,
238 TSENS_CALIB_FUSE_MAP_8X26,
239 TSENS_CALIB_FUSE_MAP_8X10,
240 TSENS_CALIB_FUSE_MAP_NUM,
241};
242
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700243/* Trips: warm and cool */
244enum tsens_trip_type {
245 TSENS_TRIP_WARM = 0,
246 TSENS_TRIP_COOL,
247 TSENS_TRIP_NUM,
248};
249
250struct tsens_tm_device_sensor {
251 struct thermal_zone_device *tz_dev;
252 enum thermal_device_mode mode;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700253 /* Physical HW sensor number */
254 unsigned int sensor_hw_num;
255 /* Software index. This is keep track of the HW/SW
256 * sensor_ID mapping */
257 unsigned int sensor_sw_id;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700258 struct work_struct work;
259 int offset;
260 int calib_data_point1;
261 int calib_data_point2;
262 uint32_t slope_mul_tsens_factor;
263};
264
265struct tsens_tm_device {
266 struct platform_device *pdev;
Matt Wagantall83026d62013-05-22 18:07:04 -0700267 struct workqueue_struct *tsens_wq;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700268 bool prev_reading_avail;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -0700269 bool calibration_less_mode;
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700270 bool tsens_local_init;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700271 int tsens_factor;
272 uint32_t tsens_num_sensor;
273 int tsens_irq;
274 void *tsens_addr;
275 void *tsens_calib_addr;
276 int tsens_len;
277 int calib_len;
278 struct resource *res_tsens_mem;
279 struct resource *res_calib_mem;
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700280 struct work_struct tsens_work;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800281 uint32_t calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700282 struct tsens_tm_device_sensor sensor[0];
283};
284
285struct tsens_tm_device *tmdev;
286
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700287int tsens_get_sw_id_mapping(int sensor_hw_num, int *sensor_sw_idx)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700288{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700289 int i = 0;
290 bool id_found = false;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700291
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700292 while (i < tmdev->tsens_num_sensor && !id_found) {
293 if (sensor_hw_num == tmdev->sensor[i].sensor_hw_num) {
Siddartha Mohanadossee00f422013-04-17 11:33:01 -0700294 *sensor_sw_idx = tmdev->sensor[i].sensor_sw_id;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700295 id_found = true;
296 }
297 i++;
298 }
299
300 if (!id_found)
301 return -EINVAL;
302
303 return 0;
304}
305EXPORT_SYMBOL(tsens_get_sw_id_mapping);
306
307int tsens_get_hw_id_mapping(int sensor_sw_id, int *sensor_hw_num)
308{
309 int i = 0;
310 bool id_found = false;
311
312 while (i < tmdev->tsens_num_sensor && !id_found) {
313 if (sensor_sw_id == tmdev->sensor[i].sensor_sw_id) {
Siddartha Mohanadossee00f422013-04-17 11:33:01 -0700314 *sensor_hw_num = tmdev->sensor[i].sensor_hw_num;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700315 id_found = true;
316 }
317 i++;
318 }
319
320 if (!id_found)
321 return -EINVAL;
322
323 return 0;
324}
325EXPORT_SYMBOL(tsens_get_hw_id_mapping);
326
327static int tsens_tz_code_to_degc(int adc_code, int sensor_sw_id)
328{
329 int degc, num, den, idx;
330
331 idx = sensor_sw_id;
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700332 num = ((adc_code * tmdev->tsens_factor) -
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700333 tmdev->sensor[idx].offset);
334 den = (int) tmdev->sensor[idx].slope_mul_tsens_factor;
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700335
Siddartha Mohanadoss8cc1fbc2013-04-05 15:10:52 -0700336 if (num > 0)
337 degc = ((num + (den/2))/den);
338 else if (num < 0)
339 degc = ((num - (den/2))/den);
340 else
341 degc = num/den;
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -0700342
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700343 pr_debug("raw_code:0x%x, sensor_num:%d, degc:%d\n",
344 adc_code, idx, degc);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700345 return degc;
346}
347
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700348static int tsens_tz_degc_to_code(int degc, int idx)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700349{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700350 int code = ((degc * tmdev->sensor[idx].slope_mul_tsens_factor)
351 + tmdev->sensor[idx].offset)/tmdev->tsens_factor;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700352
353 if (code > TSENS_THRESHOLD_MAX_CODE)
354 code = TSENS_THRESHOLD_MAX_CODE;
355 else if (code < TSENS_THRESHOLD_MIN_CODE)
356 code = TSENS_THRESHOLD_MIN_CODE;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700357 pr_debug("raw_code:0x%x, sensor_num:%d, degc:%d\n",
358 code, idx, degc);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700359 return code;
360}
361
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700362static void msm_tsens_get_temp(int sensor_hw_num, unsigned long *temp)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700363{
364 unsigned int code, sensor_addr;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700365 int sensor_sw_id = -EINVAL, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700366
367 if (!tmdev->prev_reading_avail) {
368 while (!(readl_relaxed(TSENS_TRDY_ADDR(tmdev->tsens_addr))
369 & TSENS_TRDY_MASK))
370 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
371 TSENS_TRDY_RDY_MAX_TIME);
372 tmdev->prev_reading_avail = true;
373 }
374
375 sensor_addr =
376 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
377 code = readl_relaxed(sensor_addr +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700378 (sensor_hw_num << TSENS_STATUS_ADDR_OFFSET));
379 /* Obtain SW index to map the corresponding thermal zone's
380 * offset and slope for code to degc conversion. */
381 rc = tsens_get_sw_id_mapping(sensor_hw_num, &sensor_sw_id);
382 if (rc < 0) {
383 pr_err("tsens mapping index not found\n");
384 return;
385 }
386
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700387 *temp = tsens_tz_code_to_degc((code & TSENS_SN_STATUS_TEMP_MASK),
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700388 sensor_sw_id);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700389}
390
391static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
392 unsigned long *temp)
393{
394 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
395
396 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
397 return -EINVAL;
398
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700399 msm_tsens_get_temp(tm_sensor->sensor_hw_num, temp);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700400
401 return 0;
402}
403
404int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
405{
406 if (!tmdev)
407 return -ENODEV;
408
409 msm_tsens_get_temp(device->sensor_num, temp);
410
411 return 0;
412}
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700413EXPORT_SYMBOL(tsens_get_temp);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700414
Siddartha Mohanadossb66effc2013-04-04 19:48:17 -0700415int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors)
416{
417 if (!tmdev)
418 return -ENODEV;
419
420 *tsens_num_sensors = tmdev->tsens_num_sensor;
421
422 return 0;
423}
424EXPORT_SYMBOL(tsens_get_max_sensor_num);
425
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700426static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
427 enum thermal_device_mode *mode)
428{
429 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
430
431 if (!tm_sensor || !mode)
432 return -EINVAL;
433
434 *mode = tm_sensor->mode;
435
436 return 0;
437}
438
439static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
440 int trip, enum thermal_trip_type *type)
441{
442 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
443
444 if (!tm_sensor || trip < 0 || !type)
445 return -EINVAL;
446
447 switch (trip) {
448 case TSENS_TRIP_WARM:
449 *type = THERMAL_TRIP_CONFIGURABLE_HI;
450 break;
451 case TSENS_TRIP_COOL:
452 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
453 break;
454 default:
455 return -EINVAL;
456 }
457
458 return 0;
459}
460
461static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
462 int trip, enum thermal_trip_activation_mode mode)
463{
464 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
465 unsigned int reg_cntl, code, hi_code, lo_code, mask;
466
467 if (!tm_sensor || trip < 0)
468 return -EINVAL;
469
470 lo_code = TSENS_THRESHOLD_MIN_CODE;
471 hi_code = TSENS_THRESHOLD_MAX_CODE;
472
473 reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700474 (tmdev->tsens_addr) +
475 (tm_sensor->sensor_hw_num *
476 TSENS_SN_ADDR_OFFSET)));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700477 switch (trip) {
478 case TSENS_TRIP_WARM:
479 code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
480 >> TSENS_UPPER_THRESHOLD_SHIFT;
481 mask = TSENS_UPPER_STATUS_CLR;
482
483 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
484 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
485 break;
486 case TSENS_TRIP_COOL:
487 code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
488 mask = TSENS_LOWER_STATUS_CLR;
489
490 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
491 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
492 >> TSENS_UPPER_THRESHOLD_SHIFT;
493 break;
494 default:
495 return -EINVAL;
496 }
497
498 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
499 writel_relaxed(reg_cntl | mask,
500 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700501 (tmdev->tsens_addr) +
502 (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET)));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700503 else {
504 if (code < lo_code || code > hi_code) {
505 pr_err("%s with invalid code %x\n", __func__, code);
506 return -EINVAL;
507 }
508 writel_relaxed(reg_cntl & ~mask,
509 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr) +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700510 (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET)));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700511 }
512 mb();
513 return 0;
514}
515
516static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
517 int trip, unsigned long *temp)
518{
519 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
520 unsigned int reg;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700521 int sensor_sw_id = -EINVAL, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700522
523 if (!tm_sensor || trip < 0 || !temp)
524 return -EINVAL;
525
526 reg = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
527 (tmdev->tsens_addr) +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700528 (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700529 switch (trip) {
530 case TSENS_TRIP_WARM:
531 reg = (reg & TSENS_UPPER_THRESHOLD_MASK) >>
532 TSENS_UPPER_THRESHOLD_SHIFT;
533 break;
534 case TSENS_TRIP_COOL:
535 reg = (reg & TSENS_LOWER_THRESHOLD_MASK);
536 break;
537 default:
538 return -EINVAL;
539 }
540
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700541 rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id);
542 if (rc < 0) {
543 pr_err("tsens mapping index not found\n");
544 return rc;
545 }
546 *temp = tsens_tz_code_to_degc(reg, sensor_sw_id);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700547
548 return 0;
549}
550
551static int tsens_tz_notify(struct thermal_zone_device *thermal,
552 int count, enum thermal_trip_type type)
553{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700554 /* Critical temperature threshold are enabled and will
555 * shutdown the device once critical thresholds are crossed. */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700556 pr_debug("%s debug\n", __func__);
557 return 1;
558}
559
560static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
561 int trip, long temp)
562{
563 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
564 unsigned int reg_cntl;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700565 int code, hi_code, lo_code, code_err_chk, sensor_sw_id = 0, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700566
Siddartha Mohanadoss6b21cae2013-07-30 11:42:44 -0700567 if (!tm_sensor || trip < 0)
Siddartha Mohanadoss630def02013-06-27 14:53:38 -0700568 return -EINVAL;
569
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700570 rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id);
571 if (rc < 0) {
572 pr_err("tsens mapping index not found\n");
573 return rc;
574 }
575 code_err_chk = code = tsens_tz_degc_to_code(temp, sensor_sw_id);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700576 if (!tm_sensor || trip < 0)
577 return -EINVAL;
578
579 lo_code = TSENS_THRESHOLD_MIN_CODE;
580 hi_code = TSENS_THRESHOLD_MAX_CODE;
581
582 reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700583 (tmdev->tsens_addr) + (tm_sensor->sensor_hw_num *
584 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700585 switch (trip) {
586 case TSENS_TRIP_WARM:
587 code <<= TSENS_UPPER_THRESHOLD_SHIFT;
588 reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
589 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
590 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
591 break;
592 case TSENS_TRIP_COOL:
593 reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
594 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
595 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
596 >> TSENS_UPPER_THRESHOLD_SHIFT;
597 break;
598 default:
599 return -EINVAL;
600 }
601
602 if (code_err_chk < lo_code || code_err_chk > hi_code)
603 return -EINVAL;
604
605 writel_relaxed(reg_cntl | code, (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
606 (tmdev->tsens_addr) +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700607 (tm_sensor->sensor_hw_num *
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700608 TSENS_SN_ADDR_OFFSET)));
609 mb();
610 return 0;
611}
612
613static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
614 .get_temp = tsens_tz_get_temp,
615 .get_mode = tsens_tz_get_mode,
616 .get_trip_type = tsens_tz_get_trip_type,
617 .activate_trip_type = tsens_tz_activate_trip_type,
618 .get_trip_temp = tsens_tz_get_trip_temp,
619 .set_trip_temp = tsens_tz_set_trip_temp,
620 .notify = tsens_tz_notify,
621};
622
623static void notify_uspace_tsens_fn(struct work_struct *work)
624{
625 struct tsens_tm_device_sensor *tm = container_of(work,
626 struct tsens_tm_device_sensor, work);
627
628 sysfs_notify(&tm->tz_dev->device.kobj,
629 NULL, "type");
630}
631
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700632static void tsens_scheduler_fn(struct work_struct *work)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700633{
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700634 struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
635 tsens_work);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700636 unsigned int i, status, threshold;
637 unsigned int sensor_status_addr, sensor_status_ctrl_addr;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700638 int sensor_sw_id = -EINVAL, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700639
640 sensor_status_addr =
641 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
642 sensor_status_ctrl_addr =
643 (unsigned int)TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
644 (tmdev->tsens_addr);
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700645 for (i = 0; i < tm->tsens_num_sensor; i++) {
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700646 bool upper_thr = false, lower_thr = false;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700647 uint32_t addr_offset;
648
649 addr_offset = tm->sensor[i].sensor_hw_num *
650 TSENS_SN_ADDR_OFFSET;
651 status = readl_relaxed(sensor_status_addr + addr_offset);
652 threshold = readl_relaxed(sensor_status_ctrl_addr +
653 addr_offset);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700654 if (status & TSENS_SN_STATUS_UPPER_STATUS) {
655 writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700656 TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
657 tmdev->tsens_addr + addr_offset));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700658 upper_thr = true;
659 }
660 if (status & TSENS_SN_STATUS_LOWER_STATUS) {
661 writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700662 TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
663 tmdev->tsens_addr + addr_offset));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700664 lower_thr = true;
665 }
666 if (upper_thr || lower_thr) {
Praveen Chidambaram718bf642013-07-12 14:41:03 -0600667 unsigned long temp;
668 enum thermal_trip_type trip =
669 THERMAL_TRIP_CONFIGURABLE_LOW;
670
671 if (upper_thr)
672 trip = THERMAL_TRIP_CONFIGURABLE_HI;
673 tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp);
674 thermal_sensor_trip(tm->sensor[i].tz_dev, trip, temp);
675
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700676 /* Notify user space */
Matt Wagantall83026d62013-05-22 18:07:04 -0700677 queue_work(tm->tsens_wq, &tm->sensor[i].work);
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700678 rc = tsens_get_sw_id_mapping(
679 tm->sensor[i].sensor_hw_num,
680 &sensor_sw_id);
681 if (rc < 0)
682 pr_err("tsens mapping index not found\n");
683 pr_debug("sensor:%d trigger temp (%d degC)\n",
684 tm->sensor[i].sensor_hw_num,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700685 tsens_tz_code_to_degc((status &
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700686 TSENS_SN_STATUS_TEMP_MASK),
687 sensor_sw_id));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700688 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700689 }
690 mb();
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700691}
692
693static irqreturn_t tsens_isr(int irq, void *data)
694{
Matt Wagantall83026d62013-05-22 18:07:04 -0700695 queue_work(tmdev->tsens_wq, &tmdev->tsens_work);
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700696
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700697 return IRQ_HANDLED;
698}
699
700static void tsens_hw_init(void)
701{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700702 unsigned int reg_cntl = 0, sensor_en = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700703 unsigned int i;
704
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700705 if (tmdev->tsens_local_init) {
706 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
707 writel_relaxed(reg_cntl | TSENS_SW_RST,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700708 TSENS_CTRL_ADDR(tmdev->tsens_addr));
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700709 reg_cntl |= (TSENS_62_5_MS_MEAS_PERIOD <<
710 TSENS_MEAS_PERIOD_SHIFT);
711 for (i = 0; i < tmdev->tsens_num_sensor; i++)
712 sensor_en |= (1 << tmdev->sensor[i].sensor_hw_num);
713 sensor_en <<= TSENS_SENSOR0_SHIFT;
714 reg_cntl |= (sensor_en | TSENS_EN);
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700715 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
716 writel_relaxed(TSENS_GLOBAL_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700717 TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700718 writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700719 TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700720 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
721 writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700722 TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700723 + (tmdev->sensor[i].sensor_hw_num *
724 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700725 writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700726 TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700727 + (tmdev->sensor[i].sensor_hw_num *
728 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700729 }
730 pr_debug("Local TSENS control initialization\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700731 }
732 writel_relaxed(TSENS_INTERRUPT_EN,
733 TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
734}
735
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700736static int tsens_calib_8x10_sensors(void)
737{
738 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
739 int tsens0_point2 = 0, tsens1_point2 = 0;
740 int tsens_base1_data = 0, tsens_calibration_mode = 0;
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -0700741 uint32_t calib_data[2], calib_redun_sel;
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700742 uint32_t calib_tsens_point1_data[2], calib_tsens_point2_data[2];
743
744 if (tmdev->calibration_less_mode)
745 goto calibration_less_mode;
746
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -0700747 calib_redun_sel = readl_relaxed(
748 TSENS_EEPROM_8X10_2(tmdev->tsens_calib_addr));
749 calib_redun_sel = calib_redun_sel & TSENS_8X10_REDUN_SEL_MASK;
750 calib_redun_sel >>= TSENS_8X10_REDUN_SEL_SHIFT;
751 pr_debug("calib_redun_sel:%x\n", calib_redun_sel);
752
753 if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) {
754 calib_data[0] = readl_relaxed(
755 TSENS_EEPROM_8X10_SPARE_1(tmdev->tsens_calib_addr));
756 calib_data[1] = readl_relaxed(
757 TSENS_EEPROM_8X10_SPARE_2(tmdev->tsens_calib_addr));
758 } else {
759 calib_data[0] = readl_relaxed(
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700760 TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr));
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -0700761 calib_data[1] = readl_relaxed(
762 (TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr) +
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700763 TSENS_EEPROM_8X10_1_OFFSET));
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -0700764 }
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700765
766 tsens_calibration_mode = (calib_data[0] & TSENS_8X10_TSENS_CAL_SEL)
767 >> TSENS_8X10_CAL_SEL_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700768 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700769
770 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
771 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
772 tsens_base0_data = (calib_data[0] & TSENS_8X10_BASE0_MASK);
773 tsens0_point1 = (calib_data[0] & TSENS0_8X10_POINT1_MASK) >>
774 TSENS0_8X10_POINT1_SHIFT;
775 tsens1_point1 = calib_data[1] & TSENS1_8X10_POINT1_MASK;
776 } else
777 goto calibration_less_mode;
778
779 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
780 tsens_base1_data = (calib_data[0] & TSENS_8X10_BASE1_MASK) >>
781 TSENS_8X10_BASE1_SHIFT;
782 tsens0_point2 = (calib_data[0] & TSENS0_8X10_POINT2_MASK) >>
783 TSENS0_8X10_POINT2_SHIFT;
784 tsens1_point2 = (calib_data[1] & TSENS1_8X10_POINT2_MASK) >>
785 TSENS1_8X10_POINT2_SHIFT;
786 }
787
788 if (tsens_calibration_mode == 0) {
789calibration_less_mode:
790 pr_debug("TSENS is calibrationless mode\n");
791 for (i = 0; i < tmdev->tsens_num_sensor; i++)
792 calib_tsens_point2_data[i] = 780;
793 calib_tsens_point1_data[0] = 595;
794 calib_tsens_point1_data[1] = 629;
795 goto compute_intercept_slope;
796 }
797
798 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
799 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
800 calib_tsens_point1_data[0] =
801 ((((tsens_base0_data) + tsens0_point1) << 2) |
802 TSENS_BIT_APPEND);
803 calib_tsens_point1_data[1] =
804 ((((tsens_base0_data) + tsens1_point1) << 2) |
805 TSENS_BIT_APPEND);
806 }
807
808 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
809 pr_debug("two point calibration calculation\n");
810 calib_tsens_point2_data[0] =
811 (((tsens_base1_data + tsens0_point2) << 2) |
812 TSENS_BIT_APPEND);
813 calib_tsens_point2_data[1] =
814 (((tsens_base1_data + tsens1_point2) << 2) |
815 TSENS_BIT_APPEND);
816 }
817
818compute_intercept_slope:
819 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
820 int32_t num = 0, den = 0;
821 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
822 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700823 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
824 i, tmdev->sensor[i].calib_data_point1,
825 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700826 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
827 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
828 temp_120_degc - temp_30_degc (x2 - x1) */
829 num = tmdev->sensor[i].calib_data_point2 -
830 tmdev->sensor[i].calib_data_point1;
831 num *= tmdev->tsens_factor;
832 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
833 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
834 }
835 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
836 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
837 tmdev->sensor[i].slope_mul_tsens_factor);
838 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
839 tmdev->prev_reading_avail = false;
840 }
841
842 return 0;
843}
844
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800845static int tsens_calib_8x26_sensors(void)
846{
847 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
848 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
849 int tsens5_point1 = 0, tsens6_point1 = 0, tsens6_point2 = 0;
850 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
851 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
852 int tsens_base1_data = 0, tsens_calibration_mode = 0;
853 uint32_t calib_data[6];
854 uint32_t calib_tsens_point1_data[7], calib_tsens_point2_data[7];
855
856 if (tmdev->calibration_less_mode)
857 goto calibration_less_mode;
858
859 for (i = 0; i < TSENS_8X26_MAIN_CALIB_ADDR_RANGE; i++)
860 calib_data[i] = readl_relaxed(
861 (TSENS_EEPROM_8X26_1(tmdev->tsens_calib_addr))
862 + (i * TSENS_SN_ADDR_OFFSET));
863 calib_data[4] = readl_relaxed(
864 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)));
865 calib_data[5] = readl_relaxed(
866 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
867
Siddartha Mohanadoss2114b2d2013-03-07 17:43:00 -0800868 tsens_calibration_mode = (calib_data[5] & TSENS_8X26_TSENS_CAL_SEL)
869 >> TSENS_8X26_CAL_SEL_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700870 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800871
872 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
873 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800874 tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
875 >> TSENS_8X26_BASE0_SHIFT;
876 tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
877 TSENS0_8X26_POINT1_SHIFT;
878 tsens1_point1 = calib_data[1] & TSENS1_8X26_POINT1_MASK;
879 tsens2_point1 = (calib_data[1] & TSENS2_8X26_POINT1_MASK) >>
880 TSENS2_8X26_POINT1_SHIFT;
881 tsens3_point1 = (calib_data[1] & TSENS3_8X26_POINT1_MASK) >>
882 TSENS3_8X26_POINT1_SHIFT;
883 tsens4_point1 = (calib_data[1] & TSENS4_8X26_POINT1_MASK) >>
884 TSENS4_8X26_POINT1_SHIFT;
885 tsens5_point1 = (calib_data[1] & TSENS5_8X26_POINT1_MASK) >>
886 TSENS5_8X26_POINT1_SHIFT;
887 tsens6_point1 = (calib_data[2] & TSENS6_8X26_POINT1_MASK) >>
888 TSENS6_8X26_POINT1_SHIFT;
889 } else
890 goto calibration_less_mode;
891
892 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800893 tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
894 tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
895 TSENS0_8X26_POINT2_SHIFT;
896 tsens1_point2 = (calib_data[3] & TSENS1_8X26_POINT2_MASK) >>
897 TSENS1_8X26_POINT2_SHIFT;
898 tsens2_point2 = (calib_data[3] & TSENS2_8X26_POINT2_MASK) >>
899 TSENS2_8X26_POINT2_SHIFT;
900 tsens3_point2 = (calib_data[3] & TSENS3_8X26_POINT2_MASK) >>
901 TSENS3_8X26_POINT2_SHIFT;
902 tsens4_point2 = (calib_data[4] & TSENS4_8X26_POINT2_MASK) >>
903 TSENS4_8X26_POINT2_SHIFT;
904 tsens5_point2 = (calib_data[4] & TSENS5_8X26_POINT2_MASK) >>
905 TSENS5_8X26_POINT2_SHIFT;
906 tsens6_point2 = (calib_data[5] & TSENS6_8X26_POINT2_MASK) >>
907 TSENS6_8X26_POINT2_SHIFT;
908 }
909
910 if (tsens_calibration_mode == 0) {
911calibration_less_mode:
912 pr_debug("TSENS is calibrationless mode\n");
913 for (i = 0; i < tmdev->tsens_num_sensor; i++)
914 calib_tsens_point2_data[i] = 780;
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700915 calib_tsens_point1_data[0] = 595;
916 calib_tsens_point1_data[1] = 625;
917 calib_tsens_point1_data[2] = 553;
918 calib_tsens_point1_data[3] = 578;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800919 calib_tsens_point1_data[4] = 505;
920 calib_tsens_point1_data[5] = 509;
921 calib_tsens_point1_data[6] = 507;
922 goto compute_intercept_slope;
923 }
924
925 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
926 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800927 calib_tsens_point1_data[0] =
928 ((((tsens_base0_data) + tsens0_point1) << 2) |
929 TSENS_BIT_APPEND);
930 calib_tsens_point1_data[1] =
931 ((((tsens_base0_data) + tsens1_point1) << 2) |
932 TSENS_BIT_APPEND);
933 calib_tsens_point1_data[2] =
934 ((((tsens_base0_data) + tsens2_point1) << 2) |
935 TSENS_BIT_APPEND);
936 calib_tsens_point1_data[3] =
937 ((((tsens_base0_data) + tsens3_point1) << 2) |
938 TSENS_BIT_APPEND);
939 calib_tsens_point1_data[4] =
940 ((((tsens_base0_data) + tsens4_point1) << 2) |
941 TSENS_BIT_APPEND);
942 calib_tsens_point1_data[5] =
943 ((((tsens_base0_data) + tsens5_point1) << 2) |
944 TSENS_BIT_APPEND);
945 calib_tsens_point1_data[6] =
946 ((((tsens_base0_data) + tsens6_point1) << 2) |
947 TSENS_BIT_APPEND);
948 }
949
950 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
951 pr_debug("two point calibration calculation\n");
952 calib_tsens_point2_data[0] =
953 (((tsens_base1_data + tsens0_point2) << 2) |
954 TSENS_BIT_APPEND);
955 calib_tsens_point2_data[1] =
956 (((tsens_base1_data + tsens1_point2) << 2) |
957 TSENS_BIT_APPEND);
958 calib_tsens_point2_data[2] =
959 (((tsens_base1_data + tsens2_point2) << 2) |
960 TSENS_BIT_APPEND);
961 calib_tsens_point2_data[3] =
962 (((tsens_base1_data + tsens3_point2) << 2) |
963 TSENS_BIT_APPEND);
964 calib_tsens_point2_data[4] =
965 (((tsens_base1_data + tsens4_point2) << 2) |
966 TSENS_BIT_APPEND);
967 calib_tsens_point2_data[5] =
968 (((tsens_base1_data + tsens5_point2) << 2) |
969 TSENS_BIT_APPEND);
970 calib_tsens_point2_data[6] =
971 (((tsens_base1_data + tsens6_point2) << 2) |
972 TSENS_BIT_APPEND);
973 }
974
975compute_intercept_slope:
976 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
977 int32_t num = 0, den = 0;
978 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
979 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700980 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
981 i, tmdev->sensor[i].calib_data_point1,
982 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800983 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
984 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
985 temp_120_degc - temp_30_degc (x2 - x1) */
986 num = tmdev->sensor[i].calib_data_point2 -
987 tmdev->sensor[i].calib_data_point1;
988 num *= tmdev->tsens_factor;
989 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
990 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
991 }
992 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
993 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
994 tmdev->sensor[i].slope_mul_tsens_factor);
995 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
996 tmdev->prev_reading_avail = false;
997 }
998
999 return 0;
1000}
1001
1002static int tsens_calib_8974_sensors(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001003{
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001004 int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
1005 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
1006 int tsens5_point1 = 0, tsens6_point1 = 0, tsens7_point1 = 0;
1007 int tsens8_point1 = 0, tsens9_point1 = 0, tsens10_point1 = 0;
1008 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
1009 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
1010 int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
1011 int tsens9_point2 = 0, tsens10_point2 = 0;
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -07001012 int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001013 uint32_t calib_data[6], calib_redun_sel, calib_data_backup[4];
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001014 uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11];
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001015
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001016 if (tmdev->calibration_less_mode)
1017 goto calibration_less_mode;
1018
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001019 calib_redun_sel = readl_relaxed(
1020 TSENS_EEPROM_REDUNDANCY_SEL(tmdev->tsens_calib_addr));
1021 calib_redun_sel = calib_redun_sel & TSENS_QFPROM_BACKUP_REDUN_SEL;
1022 calib_redun_sel >>= TSENS_QFPROM_BACKUP_REDUN_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001023 pr_debug("calib_redun_sel:%x\n", calib_redun_sel);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001024
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001025 for (i = 0; i < TSENS_MAIN_CALIB_ADDR_RANGE; i++) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001026 calib_data[i] = readl_relaxed(
1027 (TSENS_EEPROM(tmdev->tsens_calib_addr))
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001028 + (i * TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001029 pr_debug("calib raw data row%d:0x%x\n", i, calib_data[i]);
1030 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001031
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001032 if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) {
1033 tsens_calibration_mode = (calib_data[4] & TSENS_CAL_SEL_0_1)
1034 >> TSENS_CAL_SEL_SHIFT;
1035 temp = (calib_data[5] & TSENS_CAL_SEL_2)
1036 >> TSENS_CAL_SEL_SHIFT_2;
1037 tsens_calibration_mode |= temp;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001038 pr_debug("backup calib mode:%x\n", calib_redun_sel);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001039
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001040 for (i = 0; i < TSENS_BACKUP_CALIB_ADDR_RANGE; i++)
1041 calib_data_backup[i] = readl_relaxed(
1042 (TSENS_EEPROM_BACKUP_REGION(
1043 tmdev->tsens_calib_addr))
1044 + (i * TSENS_SN_ADDR_OFFSET));
1045
1046 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB)
1047 || (tsens_calibration_mode ==
1048 TSENS_TWO_POINT_CALIB) ||
1049 (tsens_calibration_mode ==
1050 TSENS_ONE_POINT_CALIB_OPTION_2)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001051 tsens_base1_data = (calib_data_backup[0] &
1052 TSENS_BASE1_MASK);
1053 tsens0_point1 = (calib_data_backup[0] &
1054 TSENS0_POINT1_MASK) >>
1055 TSENS0_POINT1_SHIFT;
1056 tsens1_point1 = (calib_data_backup[0] &
1057 TSENS1_POINT1_MASK) >> TSENS1_POINT1_SHIFT;
1058 tsens2_point1 = (calib_data_backup[0] &
1059 TSENS2_POINT1_MASK) >> TSENS2_POINT1_SHIFT;
1060 tsens3_point1 = (calib_data_backup[0] &
1061 TSENS3_POINT1_MASK) >> TSENS3_POINT1_SHIFT;
1062 tsens4_point1 = (calib_data_backup[1] &
1063 TSENS4_POINT1_MASK);
1064 tsens5_point1 = (calib_data_backup[1] &
1065 TSENS5_POINT1_MASK) >> TSENS5_POINT1_SHIFT;
1066 tsens6_point1 = (calib_data_backup[1] &
1067 TSENS6_POINT1_MASK) >> TSENS6_POINT1_SHIFT;
1068 tsens7_point1 = (calib_data_backup[1] &
1069 TSENS7_POINT1_MASK) >> TSENS7_POINT1_SHIFT;
1070 tsens8_point1 = (calib_data_backup[2] &
1071 TSENS8_POINT1_MASK_BACKUP) >>
1072 TSENS8_POINT1_SHIFT;
1073 tsens9_point1 = (calib_data_backup[2] &
1074 TSENS9_POINT1_MASK_BACKUP) >>
1075 TSENS9_POINT1_BACKUP_SHIFT;
1076 tsens10_point1 = (calib_data_backup[2] &
1077 TSENS10_POINT1_MASK_BACKUP) >>
1078 TSENS10_POINT1_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001079 } else
1080 goto calibration_less_mode;
1081
1082 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001083 tsens_base2_data = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001084 TSENS_BASE2_BACKUP_MASK) >>
1085 TSENS_POINT2_BASE_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001086 tsens0_point2 = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001087 TSENS0_POINT2_BACKUP_MASK) >>
1088 TSENS0_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001089 tsens1_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001090 TSENS1_POINT2_BACKUP_MASK);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001091 tsens2_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001092 TSENS2_POINT2_BACKUP_MASK) >>
1093 TSENS2_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001094 tsens3_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001095 TSENS3_POINT2_BACKUP_MASK) >>
1096 TSENS3_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001097 tsens4_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001098 TSENS4_POINT2_BACKUP_MASK) >>
1099 TSENS4_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001100 tsens5_point2 = (calib_data[4] &
1101 TSENS5_POINT2_BACKUP_MASK) >>
1102 TSENS5_POINT2_BACKUP_SHIFT;
1103 tsens6_point2 = (calib_data[5] &
1104 TSENS6_POINT2_BACKUP_MASK);
1105 tsens7_point2 = (calib_data[5] &
1106 TSENS7_POINT2_BACKUP_MASK) >>
1107 TSENS7_POINT2_BACKUP_SHIFT;
1108 tsens8_point2 = (calib_data[5] &
1109 TSENS8_POINT2_BACKUP_MASK) >>
1110 TSENS8_POINT2_BACKUP_SHIFT;
1111 tsens9_point2 = (calib_data[5] &
1112 TSENS9_POINT2_BACKUP_MASK) >>
1113 TSENS9_POINT2_BACKUP_SHIFT;
1114 tsens10_point2 = (calib_data[5] &
1115 TSENS10_POINT2_BACKUP_MASK)
1116 >> TSENS10_POINT2_BACKUP_SHIFT;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001117 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001118 } else {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001119 tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
1120 >> TSENS_CAL_SEL_SHIFT;
1121 temp = (calib_data[3] & TSENS_CAL_SEL_2)
1122 >> TSENS_CAL_SEL_SHIFT_2;
1123 tsens_calibration_mode |= temp;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001124 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001125 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) ||
1126 (tsens_calibration_mode ==
1127 TSENS_ONE_POINT_CALIB_OPTION_2) ||
1128 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001129 tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
1130 tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
1131 TSENS0_POINT1_SHIFT;
1132 tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
1133 TSENS1_POINT1_SHIFT;
1134 tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
1135 TSENS2_POINT1_SHIFT;
1136 tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
1137 TSENS3_POINT1_SHIFT;
1138 tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
1139 tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
1140 TSENS5_POINT1_SHIFT;
1141 tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
1142 TSENS6_POINT1_SHIFT;
1143 tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
1144 TSENS7_POINT1_SHIFT;
1145 tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
1146 TSENS8_POINT1_SHIFT;
1147 tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
1148 tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK)
1149 >> TSENS10_POINT1_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001150 } else
1151 goto calibration_less_mode;
1152
1153 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001154 tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
1155 TSENS_POINT2_BASE_SHIFT;
1156 tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
1157 TSENS0_POINT2_SHIFT;
1158 tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
1159 TSENS1_POINT2_SHIFT;
1160 tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
1161 tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
1162 TSENS3_POINT2_SHIFT;
1163 tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
1164 TSENS4_POINT2_SHIFT;
1165 tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
1166 TSENS5_POINT2_SHIFT;
1167 tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
1168 TSENS6_POINT2_SHIFT;
1169 tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
1170 tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
1171 TSENS8_POINT2_SHIFT;
1172 tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
1173 TSENS9_POINT2_SHIFT;
1174 tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK)
1175 >> TSENS10_POINT2_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001176 }
1177
1178 if (tsens_calibration_mode == 0) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001179calibration_less_mode:
1180 pr_debug("TSENS is calibrationless mode\n");
1181 for (i = 0; i < tmdev->tsens_num_sensor; i++)
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001182 calib_tsens_point2_data[i] = 780;
1183 calib_tsens_point1_data[0] = 502;
1184 calib_tsens_point1_data[1] = 509;
1185 calib_tsens_point1_data[2] = 503;
1186 calib_tsens_point1_data[3] = 509;
1187 calib_tsens_point1_data[4] = 505;
1188 calib_tsens_point1_data[5] = 509;
1189 calib_tsens_point1_data[6] = 507;
1190 calib_tsens_point1_data[7] = 510;
1191 calib_tsens_point1_data[8] = 508;
1192 calib_tsens_point1_data[9] = 509;
1193 calib_tsens_point1_data[10] = 508;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001194 goto compute_intercept_slope;
1195 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001196 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001197
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001198 if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001199 calib_tsens_point1_data[0] =
1200 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1201 + tsens0_point1;
1202 calib_tsens_point1_data[1] =
1203 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1204 + tsens1_point1;
1205 calib_tsens_point1_data[2] =
1206 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1207 + tsens2_point1;
1208 calib_tsens_point1_data[3] =
1209 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1210 + tsens3_point1;
1211 calib_tsens_point1_data[4] =
1212 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1213 + tsens4_point1;
1214 calib_tsens_point1_data[5] =
1215 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1216 + tsens5_point1;
1217 calib_tsens_point1_data[6] =
1218 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1219 + tsens6_point1;
1220 calib_tsens_point1_data[7] =
1221 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1222 + tsens7_point1;
1223 calib_tsens_point1_data[8] =
1224 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1225 + tsens8_point1;
1226 calib_tsens_point1_data[9] =
1227 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1228 + tsens9_point1;
1229 calib_tsens_point1_data[10] =
1230 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1231 + tsens10_point1;
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001232 }
1233
Siddartha Mohanadoss4d9815a2012-09-09 17:16:05 -07001234 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
1235 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001236 pr_debug("one point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001237 calib_tsens_point1_data[0] =
1238 ((((tsens_base1_data) + tsens0_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001239 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001240 calib_tsens_point1_data[1] =
1241 ((((tsens_base1_data) + tsens1_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001242 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001243 calib_tsens_point1_data[2] =
1244 ((((tsens_base1_data) + tsens2_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001245 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001246 calib_tsens_point1_data[3] =
1247 ((((tsens_base1_data) + tsens3_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001248 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001249 calib_tsens_point1_data[4] =
1250 ((((tsens_base1_data) + tsens4_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001251 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001252 calib_tsens_point1_data[5] =
1253 ((((tsens_base1_data) + tsens5_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001254 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001255 calib_tsens_point1_data[6] =
1256 ((((tsens_base1_data) + tsens6_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001257 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001258 calib_tsens_point1_data[7] =
1259 ((((tsens_base1_data) + tsens7_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001260 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001261 calib_tsens_point1_data[8] =
1262 ((((tsens_base1_data) + tsens8_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001263 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001264 calib_tsens_point1_data[9] =
1265 ((((tsens_base1_data) + tsens9_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001266 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001267 calib_tsens_point1_data[10] =
1268 ((((tsens_base1_data) + tsens10_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001269 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001270 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001271
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001272 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001273 pr_debug("two point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001274 calib_tsens_point2_data[0] =
1275 (((tsens_base2_data + tsens0_point2) << 2) |
1276 TSENS_BIT_APPEND);
1277 calib_tsens_point2_data[1] =
1278 (((tsens_base2_data + tsens1_point2) << 2) |
1279 TSENS_BIT_APPEND);
1280 calib_tsens_point2_data[2] =
1281 (((tsens_base2_data + tsens2_point2) << 2) |
1282 TSENS_BIT_APPEND);
1283 calib_tsens_point2_data[3] =
1284 (((tsens_base2_data + tsens3_point2) << 2) |
1285 TSENS_BIT_APPEND);
1286 calib_tsens_point2_data[4] =
1287 (((tsens_base2_data + tsens4_point2) << 2) |
1288 TSENS_BIT_APPEND);
1289 calib_tsens_point2_data[5] =
1290 (((tsens_base2_data + tsens5_point2) << 2) |
1291 TSENS_BIT_APPEND);
1292 calib_tsens_point2_data[6] =
1293 (((tsens_base2_data + tsens6_point2) << 2) |
1294 TSENS_BIT_APPEND);
1295 calib_tsens_point2_data[7] =
1296 (((tsens_base2_data + tsens7_point2) << 2) |
1297 TSENS_BIT_APPEND);
1298 calib_tsens_point2_data[8] =
1299 (((tsens_base2_data + tsens8_point2) << 2) |
1300 TSENS_BIT_APPEND);
1301 calib_tsens_point2_data[9] =
1302 (((tsens_base2_data + tsens9_point2) << 2) |
1303 TSENS_BIT_APPEND);
1304 calib_tsens_point2_data[10] =
1305 (((tsens_base2_data + tsens10_point2) << 2) |
1306 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001307 }
1308
1309compute_intercept_slope:
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001310 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1311 int32_t num = 0, den = 0;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001312 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
1313 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001314 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
1315 i, tmdev->sensor[i].calib_data_point1,
1316 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001317 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001318 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
1319 temp_120_degc - temp_30_degc (x2 - x1) */
1320 num = tmdev->sensor[i].calib_data_point2 -
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001321 tmdev->sensor[i].calib_data_point1;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001322 num *= tmdev->tsens_factor;
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001323 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001324 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001325 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001326 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
1327 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
1328 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001329 pr_debug("offset:%d\n", tmdev->sensor[i].offset);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001330 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
1331 tmdev->prev_reading_avail = false;
1332 }
1333
1334 return 0;
1335}
1336
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001337static int tsens_calib_sensors(void)
1338{
1339 int rc = 0;
1340
1341 if (!tmdev)
1342 return -ENODEV;
1343
1344 if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8974)
1345 rc = tsens_calib_8974_sensors();
1346 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
1347 rc = tsens_calib_8x26_sensors();
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -07001348 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X10)
1349 rc = tsens_calib_8x10_sensors();
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001350 else
1351 rc = -ENODEV;
1352
1353 return rc;
1354}
1355
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001356static int get_device_tree_data(struct platform_device *pdev)
1357{
Siddartha Mohanadoss630def02013-06-27 14:53:38 -07001358 struct device_node *of_node = pdev->dev.of_node;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001359 struct resource *res_mem = NULL;
1360 u32 *tsens_slope_data;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001361 u32 *sensor_id;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001362 u32 rc = 0, i, tsens_num_sensors, calib_type;
1363 const char *tsens_calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001364
1365 rc = of_property_read_u32(of_node,
1366 "qcom,sensors", &tsens_num_sensors);
1367 if (rc) {
1368 dev_err(&pdev->dev, "missing sensor number\n");
1369 return -ENODEV;
1370 }
1371
1372 tsens_slope_data = devm_kzalloc(&pdev->dev,
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001373 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001374 if (!tsens_slope_data) {
1375 dev_err(&pdev->dev, "can not allocate slope data\n");
1376 return -ENOMEM;
1377 }
1378
1379 rc = of_property_read_u32_array(of_node,
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001380 "qcom,slope", tsens_slope_data, tsens_num_sensors);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001381 if (rc) {
1382 dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
1383 return rc;
1384 };
1385
Siddartha Mohanadoss630def02013-06-27 14:53:38 -07001386 rc = of_property_read_string(of_node,
1387 "qcom,calib-mode", &tsens_calib_mode);
1388 if (rc) {
1389 dev_err(&pdev->dev, "missing calib-mode\n");
1390 return -ENODEV;
1391 }
1392
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001393 if (!strncmp(tsens_calib_mode, "fuse_map1", 9))
1394 calib_type = TSENS_CALIB_FUSE_MAP_8974;
1395 else if (!strncmp(tsens_calib_mode, "fuse_map2", 9))
1396 calib_type = TSENS_CALIB_FUSE_MAP_8X26;
1397 else if (!strncmp(tsens_calib_mode, "fuse_map3", 9))
1398 calib_type = TSENS_CALIB_FUSE_MAP_8X10;
1399 else {
1400 pr_err("%s: Invalid calibration property\n", __func__);
1401 return -EINVAL;
1402 }
1403
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001404 tmdev = devm_kzalloc(&pdev->dev,
1405 sizeof(struct tsens_tm_device) +
1406 tsens_num_sensors *
1407 sizeof(struct tsens_tm_device_sensor),
1408 GFP_KERNEL);
1409 if (tmdev == NULL) {
1410 pr_err("%s: kzalloc() failed.\n", __func__);
1411 return -ENOMEM;
1412 }
1413
1414 for (i = 0; i < tsens_num_sensors; i++)
1415 tmdev->sensor[i].slope_mul_tsens_factor = tsens_slope_data[i];
1416 tmdev->tsens_factor = TSENS_SLOPE_FACTOR;
1417 tmdev->tsens_num_sensor = tsens_num_sensors;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001418 tmdev->calibration_less_mode = of_property_read_bool(of_node,
1419 "qcom,calibration-less-mode");
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001420 tmdev->calib_mode = calib_type;
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -07001421 tmdev->tsens_local_init = of_property_read_bool(of_node,
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -07001422 "qcom,tsens-local-init");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001423
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001424 sensor_id = devm_kzalloc(&pdev->dev,
1425 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
1426 if (!sensor_id) {
1427 dev_err(&pdev->dev, "can not allocate sensor id\n");
1428 return -ENOMEM;
1429 }
1430
1431 rc = of_property_read_u32_array(of_node,
1432 "qcom,sensor-id", sensor_id, tsens_num_sensors);
1433 if (rc) {
1434 pr_debug("Default sensor id mapping\n");
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001435 for (i = 0; i < tsens_num_sensors; i++) {
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001436 tmdev->sensor[i].sensor_hw_num = i;
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001437 tmdev->sensor[i].sensor_sw_id = i;
1438 }
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001439 } else {
1440 pr_debug("Use specified sensor id mapping\n");
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001441 for (i = 0; i < tsens_num_sensors; i++) {
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001442 tmdev->sensor[i].sensor_hw_num = sensor_id[i];
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001443 tmdev->sensor[i].sensor_sw_id = i;
1444 }
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001445 }
1446
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001447 tmdev->tsens_irq = platform_get_irq(pdev, 0);
1448 if (tmdev->tsens_irq < 0) {
1449 pr_err("Invalid get irq\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001450 rc = tmdev->tsens_irq;
1451 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001452 }
1453
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001454 /* TSENS register region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001455 tmdev->res_tsens_mem = platform_get_resource_byname(pdev,
1456 IORESOURCE_MEM, "tsens_physical");
1457 if (!tmdev->res_tsens_mem) {
1458 pr_err("Could not get tsens physical address resource\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001459 rc = -EINVAL;
1460 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001461 }
1462
1463 tmdev->tsens_len = tmdev->res_tsens_mem->end -
1464 tmdev->res_tsens_mem->start + 1;
1465
1466 res_mem = request_mem_region(tmdev->res_tsens_mem->start,
1467 tmdev->tsens_len, tmdev->res_tsens_mem->name);
1468 if (!res_mem) {
1469 pr_err("Request tsens physical memory region failed\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001470 rc = -EINVAL;
1471 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001472 }
1473
1474 tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
1475 if (!tmdev->tsens_addr) {
1476 pr_err("Failed to IO map TSENS registers.\n");
1477 rc = -EINVAL;
1478 goto fail_unmap_tsens_region;
1479 }
1480
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001481 /* TSENS calibration region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001482 tmdev->res_calib_mem = platform_get_resource_byname(pdev,
1483 IORESOURCE_MEM, "tsens_eeprom_physical");
1484 if (!tmdev->res_calib_mem) {
1485 pr_err("Could not get qfprom physical address resource\n");
1486 rc = -EINVAL;
1487 goto fail_unmap_tsens;
1488 }
1489
1490 tmdev->calib_len = tmdev->res_calib_mem->end -
1491 tmdev->res_calib_mem->start + 1;
1492
1493 res_mem = request_mem_region(tmdev->res_calib_mem->start,
1494 tmdev->calib_len, tmdev->res_calib_mem->name);
1495 if (!res_mem) {
1496 pr_err("Request calibration memory region failed\n");
1497 rc = -EINVAL;
1498 goto fail_unmap_tsens;
1499 }
1500
1501 tmdev->tsens_calib_addr = ioremap(res_mem->start,
1502 tmdev->calib_len);
1503 if (!tmdev->tsens_calib_addr) {
1504 pr_err("Failed to IO map EEPROM registers.\n");
1505 rc = -EINVAL;
1506 goto fail_unmap_calib_region;
1507 }
1508
1509 return 0;
1510
1511fail_unmap_calib_region:
1512 if (tmdev->res_calib_mem)
1513 release_mem_region(tmdev->res_calib_mem->start,
1514 tmdev->calib_len);
1515fail_unmap_tsens:
1516 if (tmdev->tsens_addr)
1517 iounmap(tmdev->tsens_addr);
1518fail_unmap_tsens_region:
1519 if (tmdev->res_tsens_mem)
1520 release_mem_region(tmdev->res_tsens_mem->start,
1521 tmdev->tsens_len);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001522fail_tmdev:
1523 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001524 return rc;
1525}
1526
1527static int __devinit tsens_tm_probe(struct platform_device *pdev)
1528{
1529 int rc;
1530
1531 if (tmdev) {
1532 pr_err("TSENS device already in use\n");
1533 return -EBUSY;
1534 }
1535
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001536 if (pdev->dev.of_node) {
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001537 rc = get_device_tree_data(pdev);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001538 if (rc) {
1539 pr_err("Error reading TSENS DT\n");
1540 return rc;
1541 }
1542 } else
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001543 return -ENODEV;
1544
1545 tmdev->pdev = pdev;
Matt Wagantall83026d62013-05-22 18:07:04 -07001546 tmdev->tsens_wq = alloc_workqueue("tsens_wq", WQ_HIGHPRI, 0);
1547 if (!tmdev->tsens_wq) {
1548 rc = -ENOMEM;
1549 goto fail;
1550 }
1551
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001552 rc = tsens_calib_sensors();
Michael Bohanb89167e2012-10-04 16:24:23 -07001553 if (rc < 0) {
1554 pr_err("Calibration failed\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001555 goto fail;
Michael Bohanb89167e2012-10-04 16:24:23 -07001556 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001557
1558 tsens_hw_init();
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001559
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001560 tmdev->prev_reading_avail = true;
1561
1562 platform_set_drvdata(pdev, tmdev);
1563
1564 return 0;
1565fail:
Matt Wagantall83026d62013-05-22 18:07:04 -07001566 if (tmdev->tsens_wq)
1567 destroy_workqueue(tmdev->tsens_wq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001568 if (tmdev->tsens_calib_addr)
1569 iounmap(tmdev->tsens_calib_addr);
1570 if (tmdev->res_calib_mem)
1571 release_mem_region(tmdev->res_calib_mem->start,
1572 tmdev->calib_len);
1573 if (tmdev->tsens_addr)
1574 iounmap(tmdev->tsens_addr);
1575 if (tmdev->res_tsens_mem)
1576 release_mem_region(tmdev->res_tsens_mem->start,
1577 tmdev->tsens_len);
Michael Bohanb89167e2012-10-04 16:24:23 -07001578 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001579
1580 return rc;
1581}
1582
1583static int __devinit _tsens_register_thermal(void)
1584{
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001585 struct platform_device *pdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001586 int rc, i;
1587
1588 if (!tmdev) {
1589 pr_err("%s: TSENS early init not done\n", __func__);
1590 return -ENODEV;
1591 }
1592
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001593 pdev = tmdev->pdev;
1594
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001595 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1596 char name[18];
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001597 snprintf(name, sizeof(name), "tsens_tz_sensor%d",
1598 tmdev->sensor[i].sensor_hw_num);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001599 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001600 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
1601 TSENS_TRIP_NUM, &tmdev->sensor[i],
1602 &tsens_thermal_zone_ops, 0, 0, 0, 0);
1603 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
1604 pr_err("%s: thermal_zone_device_register() failed.\n",
1605 __func__);
1606 rc = -ENODEV;
1607 goto fail;
1608 }
1609 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001610
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001611 rc = request_irq(tmdev->tsens_irq, tsens_isr,
1612 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
1613 if (rc < 0) {
1614 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
1615 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1616 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1617 goto fail;
Siddartha Mohanadossb9be9812013-02-13 11:03:32 -08001618 } else {
1619 enable_irq_wake(tmdev->tsens_irq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001620 }
1621 platform_set_drvdata(pdev, tmdev);
1622
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -07001623 INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
1624
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001625 return 0;
1626fail:
1627 if (tmdev->tsens_calib_addr)
1628 iounmap(tmdev->tsens_calib_addr);
1629 if (tmdev->res_calib_mem)
1630 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001631 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001632 if (tmdev->tsens_addr)
1633 iounmap(tmdev->tsens_addr);
1634 if (tmdev->res_tsens_mem)
1635 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001636 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001637 return rc;
1638}
1639
1640static int __devexit tsens_tm_remove(struct platform_device *pdev)
1641{
1642 struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
1643 int i;
1644
1645 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1646 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1647 if (tmdev->tsens_calib_addr)
1648 iounmap(tmdev->tsens_calib_addr);
1649 if (tmdev->res_calib_mem)
1650 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001651 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001652 if (tmdev->tsens_addr)
1653 iounmap(tmdev->tsens_addr);
1654 if (tmdev->res_tsens_mem)
1655 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001656 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001657 free_irq(tmdev->tsens_irq, tmdev);
Matt Wagantall83026d62013-05-22 18:07:04 -07001658 destroy_workqueue(tmdev->tsens_wq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001659 platform_set_drvdata(pdev, NULL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001660
1661 return 0;
1662}
1663
1664static struct of_device_id tsens_match[] = {
1665 { .compatible = "qcom,msm-tsens",
1666 },
1667 {}
1668};
1669
1670static struct platform_driver tsens_tm_driver = {
1671 .probe = tsens_tm_probe,
1672 .remove = tsens_tm_remove,
1673 .driver = {
1674 .name = "msm-tsens",
1675 .owner = THIS_MODULE,
1676 .of_match_table = tsens_match,
1677 },
1678};
1679
Siddartha Mohanadoss4cef5f42013-04-11 13:59:41 -07001680int __init tsens_tm_init_driver(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001681{
1682 return platform_driver_register(&tsens_tm_driver);
1683}
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001684
1685static int __init tsens_thermal_register(void)
1686{
1687 return _tsens_register_thermal();
1688}
1689module_init(tsens_thermal_register);
1690
1691static void __exit _tsens_tm_remove(void)
1692{
1693 platform_driver_unregister(&tsens_tm_driver);
1694}
1695module_exit(_tsens_tm_remove);
1696
1697MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
1698MODULE_LICENSE("GPL v2");