blob: 69331632f189c986bb6c6b164370cdddd26c4351 [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
167#define TSENS0_8X26_POINT1_MASK 0x7f00000
168#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
177#define TSENS1_8X26_POINT2_MASK 0xfc00
178#define TSENS2_8X26_POINT2_MASK 0x3f00000
179#define TSENS3_8X26_POINT2_MASK 0xfc000000
180#define TSENS4_8X26_POINT2_MASK 0xfc000000
181#define TSENS5_8X26_POINT2_MASK 0x3f00000
182#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 Mohanadoss630def02013-06-27 14:53:38 -0700567 if (!tm_sensor || trip < 0 || !temp)
568 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) {
667 /* Notify user space */
Matt Wagantall83026d62013-05-22 18:07:04 -0700668 queue_work(tm->tsens_wq, &tm->sensor[i].work);
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700669 rc = tsens_get_sw_id_mapping(
670 tm->sensor[i].sensor_hw_num,
671 &sensor_sw_id);
672 if (rc < 0)
673 pr_err("tsens mapping index not found\n");
674 pr_debug("sensor:%d trigger temp (%d degC)\n",
675 tm->sensor[i].sensor_hw_num,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700676 tsens_tz_code_to_degc((status &
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700677 TSENS_SN_STATUS_TEMP_MASK),
678 sensor_sw_id));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700679 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700680 }
681 mb();
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700682}
683
684static irqreturn_t tsens_isr(int irq, void *data)
685{
Matt Wagantall83026d62013-05-22 18:07:04 -0700686 queue_work(tmdev->tsens_wq, &tmdev->tsens_work);
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700687
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700688 return IRQ_HANDLED;
689}
690
691static void tsens_hw_init(void)
692{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700693 unsigned int reg_cntl = 0, sensor_en = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700694 unsigned int i;
695
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700696 if (tmdev->tsens_local_init) {
697 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
698 writel_relaxed(reg_cntl | TSENS_SW_RST,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700699 TSENS_CTRL_ADDR(tmdev->tsens_addr));
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700700 reg_cntl |= (TSENS_62_5_MS_MEAS_PERIOD <<
701 TSENS_MEAS_PERIOD_SHIFT);
702 for (i = 0; i < tmdev->tsens_num_sensor; i++)
703 sensor_en |= (1 << tmdev->sensor[i].sensor_hw_num);
704 sensor_en <<= TSENS_SENSOR0_SHIFT;
705 reg_cntl |= (sensor_en | TSENS_EN);
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700706 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
707 writel_relaxed(TSENS_GLOBAL_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700708 TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700709 writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700710 TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700711 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
712 writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700713 TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700714 + (tmdev->sensor[i].sensor_hw_num *
715 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700716 writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700717 TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700718 + (tmdev->sensor[i].sensor_hw_num *
719 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700720 }
721 pr_debug("Local TSENS control initialization\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700722 }
723 writel_relaxed(TSENS_INTERRUPT_EN,
724 TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
725}
726
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700727static int tsens_calib_8x10_sensors(void)
728{
729 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
730 int tsens0_point2 = 0, tsens1_point2 = 0;
731 int tsens_base1_data = 0, tsens_calibration_mode = 0;
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -0700732 uint32_t calib_data[2], calib_redun_sel;
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700733 uint32_t calib_tsens_point1_data[2], calib_tsens_point2_data[2];
734
735 if (tmdev->calibration_less_mode)
736 goto calibration_less_mode;
737
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -0700738 calib_redun_sel = readl_relaxed(
739 TSENS_EEPROM_8X10_2(tmdev->tsens_calib_addr));
740 calib_redun_sel = calib_redun_sel & TSENS_8X10_REDUN_SEL_MASK;
741 calib_redun_sel >>= TSENS_8X10_REDUN_SEL_SHIFT;
742 pr_debug("calib_redun_sel:%x\n", calib_redun_sel);
743
744 if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) {
745 calib_data[0] = readl_relaxed(
746 TSENS_EEPROM_8X10_SPARE_1(tmdev->tsens_calib_addr));
747 calib_data[1] = readl_relaxed(
748 TSENS_EEPROM_8X10_SPARE_2(tmdev->tsens_calib_addr));
749 } else {
750 calib_data[0] = readl_relaxed(
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700751 TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr));
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -0700752 calib_data[1] = readl_relaxed(
753 (TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr) +
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700754 TSENS_EEPROM_8X10_1_OFFSET));
Siddartha Mohanadossd44962f2013-07-09 12:13:33 -0700755 }
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700756
757 tsens_calibration_mode = (calib_data[0] & TSENS_8X10_TSENS_CAL_SEL)
758 >> TSENS_8X10_CAL_SEL_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700759 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700760
761 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
762 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
763 tsens_base0_data = (calib_data[0] & TSENS_8X10_BASE0_MASK);
764 tsens0_point1 = (calib_data[0] & TSENS0_8X10_POINT1_MASK) >>
765 TSENS0_8X10_POINT1_SHIFT;
766 tsens1_point1 = calib_data[1] & TSENS1_8X10_POINT1_MASK;
767 } else
768 goto calibration_less_mode;
769
770 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
771 tsens_base1_data = (calib_data[0] & TSENS_8X10_BASE1_MASK) >>
772 TSENS_8X10_BASE1_SHIFT;
773 tsens0_point2 = (calib_data[0] & TSENS0_8X10_POINT2_MASK) >>
774 TSENS0_8X10_POINT2_SHIFT;
775 tsens1_point2 = (calib_data[1] & TSENS1_8X10_POINT2_MASK) >>
776 TSENS1_8X10_POINT2_SHIFT;
777 }
778
779 if (tsens_calibration_mode == 0) {
780calibration_less_mode:
781 pr_debug("TSENS is calibrationless mode\n");
782 for (i = 0; i < tmdev->tsens_num_sensor; i++)
783 calib_tsens_point2_data[i] = 780;
784 calib_tsens_point1_data[0] = 595;
785 calib_tsens_point1_data[1] = 629;
786 goto compute_intercept_slope;
787 }
788
789 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
790 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
791 calib_tsens_point1_data[0] =
792 ((((tsens_base0_data) + tsens0_point1) << 2) |
793 TSENS_BIT_APPEND);
794 calib_tsens_point1_data[1] =
795 ((((tsens_base0_data) + tsens1_point1) << 2) |
796 TSENS_BIT_APPEND);
797 }
798
799 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
800 pr_debug("two point calibration calculation\n");
801 calib_tsens_point2_data[0] =
802 (((tsens_base1_data + tsens0_point2) << 2) |
803 TSENS_BIT_APPEND);
804 calib_tsens_point2_data[1] =
805 (((tsens_base1_data + tsens1_point2) << 2) |
806 TSENS_BIT_APPEND);
807 }
808
809compute_intercept_slope:
810 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
811 int32_t num = 0, den = 0;
812 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
813 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700814 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
815 i, tmdev->sensor[i].calib_data_point1,
816 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700817 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
818 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
819 temp_120_degc - temp_30_degc (x2 - x1) */
820 num = tmdev->sensor[i].calib_data_point2 -
821 tmdev->sensor[i].calib_data_point1;
822 num *= tmdev->tsens_factor;
823 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
824 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
825 }
826 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
827 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
828 tmdev->sensor[i].slope_mul_tsens_factor);
829 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
830 tmdev->prev_reading_avail = false;
831 }
832
833 return 0;
834}
835
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800836static int tsens_calib_8x26_sensors(void)
837{
838 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
839 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
840 int tsens5_point1 = 0, tsens6_point1 = 0, tsens6_point2 = 0;
841 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
842 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
843 int tsens_base1_data = 0, tsens_calibration_mode = 0;
844 uint32_t calib_data[6];
845 uint32_t calib_tsens_point1_data[7], calib_tsens_point2_data[7];
846
847 if (tmdev->calibration_less_mode)
848 goto calibration_less_mode;
849
850 for (i = 0; i < TSENS_8X26_MAIN_CALIB_ADDR_RANGE; i++)
851 calib_data[i] = readl_relaxed(
852 (TSENS_EEPROM_8X26_1(tmdev->tsens_calib_addr))
853 + (i * TSENS_SN_ADDR_OFFSET));
854 calib_data[4] = readl_relaxed(
855 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)));
856 calib_data[5] = readl_relaxed(
857 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
858
Siddartha Mohanadoss2114b2d2013-03-07 17:43:00 -0800859 tsens_calibration_mode = (calib_data[5] & TSENS_8X26_TSENS_CAL_SEL)
860 >> TSENS_8X26_CAL_SEL_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700861 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800862
863 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
864 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800865 tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
866 >> TSENS_8X26_BASE0_SHIFT;
867 tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
868 TSENS0_8X26_POINT1_SHIFT;
869 tsens1_point1 = calib_data[1] & TSENS1_8X26_POINT1_MASK;
870 tsens2_point1 = (calib_data[1] & TSENS2_8X26_POINT1_MASK) >>
871 TSENS2_8X26_POINT1_SHIFT;
872 tsens3_point1 = (calib_data[1] & TSENS3_8X26_POINT1_MASK) >>
873 TSENS3_8X26_POINT1_SHIFT;
874 tsens4_point1 = (calib_data[1] & TSENS4_8X26_POINT1_MASK) >>
875 TSENS4_8X26_POINT1_SHIFT;
876 tsens5_point1 = (calib_data[1] & TSENS5_8X26_POINT1_MASK) >>
877 TSENS5_8X26_POINT1_SHIFT;
878 tsens6_point1 = (calib_data[2] & TSENS6_8X26_POINT1_MASK) >>
879 TSENS6_8X26_POINT1_SHIFT;
880 } else
881 goto calibration_less_mode;
882
883 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800884 tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
885 tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
886 TSENS0_8X26_POINT2_SHIFT;
887 tsens1_point2 = (calib_data[3] & TSENS1_8X26_POINT2_MASK) >>
888 TSENS1_8X26_POINT2_SHIFT;
889 tsens2_point2 = (calib_data[3] & TSENS2_8X26_POINT2_MASK) >>
890 TSENS2_8X26_POINT2_SHIFT;
891 tsens3_point2 = (calib_data[3] & TSENS3_8X26_POINT2_MASK) >>
892 TSENS3_8X26_POINT2_SHIFT;
893 tsens4_point2 = (calib_data[4] & TSENS4_8X26_POINT2_MASK) >>
894 TSENS4_8X26_POINT2_SHIFT;
895 tsens5_point2 = (calib_data[4] & TSENS5_8X26_POINT2_MASK) >>
896 TSENS5_8X26_POINT2_SHIFT;
897 tsens6_point2 = (calib_data[5] & TSENS6_8X26_POINT2_MASK) >>
898 TSENS6_8X26_POINT2_SHIFT;
899 }
900
901 if (tsens_calibration_mode == 0) {
902calibration_less_mode:
903 pr_debug("TSENS is calibrationless mode\n");
904 for (i = 0; i < tmdev->tsens_num_sensor; i++)
905 calib_tsens_point2_data[i] = 780;
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700906 calib_tsens_point1_data[0] = 595;
907 calib_tsens_point1_data[1] = 625;
908 calib_tsens_point1_data[2] = 553;
909 calib_tsens_point1_data[3] = 578;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800910 calib_tsens_point1_data[4] = 505;
911 calib_tsens_point1_data[5] = 509;
912 calib_tsens_point1_data[6] = 507;
913 goto compute_intercept_slope;
914 }
915
916 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
917 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800918 calib_tsens_point1_data[0] =
919 ((((tsens_base0_data) + tsens0_point1) << 2) |
920 TSENS_BIT_APPEND);
921 calib_tsens_point1_data[1] =
922 ((((tsens_base0_data) + tsens1_point1) << 2) |
923 TSENS_BIT_APPEND);
924 calib_tsens_point1_data[2] =
925 ((((tsens_base0_data) + tsens2_point1) << 2) |
926 TSENS_BIT_APPEND);
927 calib_tsens_point1_data[3] =
928 ((((tsens_base0_data) + tsens3_point1) << 2) |
929 TSENS_BIT_APPEND);
930 calib_tsens_point1_data[4] =
931 ((((tsens_base0_data) + tsens4_point1) << 2) |
932 TSENS_BIT_APPEND);
933 calib_tsens_point1_data[5] =
934 ((((tsens_base0_data) + tsens5_point1) << 2) |
935 TSENS_BIT_APPEND);
936 calib_tsens_point1_data[6] =
937 ((((tsens_base0_data) + tsens6_point1) << 2) |
938 TSENS_BIT_APPEND);
939 }
940
941 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
942 pr_debug("two point calibration calculation\n");
943 calib_tsens_point2_data[0] =
944 (((tsens_base1_data + tsens0_point2) << 2) |
945 TSENS_BIT_APPEND);
946 calib_tsens_point2_data[1] =
947 (((tsens_base1_data + tsens1_point2) << 2) |
948 TSENS_BIT_APPEND);
949 calib_tsens_point2_data[2] =
950 (((tsens_base1_data + tsens2_point2) << 2) |
951 TSENS_BIT_APPEND);
952 calib_tsens_point2_data[3] =
953 (((tsens_base1_data + tsens3_point2) << 2) |
954 TSENS_BIT_APPEND);
955 calib_tsens_point2_data[4] =
956 (((tsens_base1_data + tsens4_point2) << 2) |
957 TSENS_BIT_APPEND);
958 calib_tsens_point2_data[5] =
959 (((tsens_base1_data + tsens5_point2) << 2) |
960 TSENS_BIT_APPEND);
961 calib_tsens_point2_data[6] =
962 (((tsens_base1_data + tsens6_point2) << 2) |
963 TSENS_BIT_APPEND);
964 }
965
966compute_intercept_slope:
967 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
968 int32_t num = 0, den = 0;
969 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
970 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700971 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
972 i, tmdev->sensor[i].calib_data_point1,
973 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800974 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
975 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
976 temp_120_degc - temp_30_degc (x2 - x1) */
977 num = tmdev->sensor[i].calib_data_point2 -
978 tmdev->sensor[i].calib_data_point1;
979 num *= tmdev->tsens_factor;
980 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
981 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
982 }
983 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
984 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
985 tmdev->sensor[i].slope_mul_tsens_factor);
986 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
987 tmdev->prev_reading_avail = false;
988 }
989
990 return 0;
991}
992
993static int tsens_calib_8974_sensors(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700994{
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700995 int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
996 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
997 int tsens5_point1 = 0, tsens6_point1 = 0, tsens7_point1 = 0;
998 int tsens8_point1 = 0, tsens9_point1 = 0, tsens10_point1 = 0;
999 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
1000 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
1001 int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
1002 int tsens9_point2 = 0, tsens10_point2 = 0;
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -07001003 int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001004 uint32_t calib_data[6], calib_redun_sel, calib_data_backup[4];
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001005 uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11];
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001006
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001007 if (tmdev->calibration_less_mode)
1008 goto calibration_less_mode;
1009
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001010 calib_redun_sel = readl_relaxed(
1011 TSENS_EEPROM_REDUNDANCY_SEL(tmdev->tsens_calib_addr));
1012 calib_redun_sel = calib_redun_sel & TSENS_QFPROM_BACKUP_REDUN_SEL;
1013 calib_redun_sel >>= TSENS_QFPROM_BACKUP_REDUN_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001014 pr_debug("calib_redun_sel:%x\n", calib_redun_sel);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001015
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001016 for (i = 0; i < TSENS_MAIN_CALIB_ADDR_RANGE; i++) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001017 calib_data[i] = readl_relaxed(
1018 (TSENS_EEPROM(tmdev->tsens_calib_addr))
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001019 + (i * TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001020 pr_debug("calib raw data row%d:0x%x\n", i, calib_data[i]);
1021 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001022
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001023 if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) {
1024 tsens_calibration_mode = (calib_data[4] & TSENS_CAL_SEL_0_1)
1025 >> TSENS_CAL_SEL_SHIFT;
1026 temp = (calib_data[5] & TSENS_CAL_SEL_2)
1027 >> TSENS_CAL_SEL_SHIFT_2;
1028 tsens_calibration_mode |= temp;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001029 pr_debug("backup calib mode:%x\n", calib_redun_sel);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001030
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001031 for (i = 0; i < TSENS_BACKUP_CALIB_ADDR_RANGE; i++)
1032 calib_data_backup[i] = readl_relaxed(
1033 (TSENS_EEPROM_BACKUP_REGION(
1034 tmdev->tsens_calib_addr))
1035 + (i * TSENS_SN_ADDR_OFFSET));
1036
1037 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB)
1038 || (tsens_calibration_mode ==
1039 TSENS_TWO_POINT_CALIB) ||
1040 (tsens_calibration_mode ==
1041 TSENS_ONE_POINT_CALIB_OPTION_2)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001042 tsens_base1_data = (calib_data_backup[0] &
1043 TSENS_BASE1_MASK);
1044 tsens0_point1 = (calib_data_backup[0] &
1045 TSENS0_POINT1_MASK) >>
1046 TSENS0_POINT1_SHIFT;
1047 tsens1_point1 = (calib_data_backup[0] &
1048 TSENS1_POINT1_MASK) >> TSENS1_POINT1_SHIFT;
1049 tsens2_point1 = (calib_data_backup[0] &
1050 TSENS2_POINT1_MASK) >> TSENS2_POINT1_SHIFT;
1051 tsens3_point1 = (calib_data_backup[0] &
1052 TSENS3_POINT1_MASK) >> TSENS3_POINT1_SHIFT;
1053 tsens4_point1 = (calib_data_backup[1] &
1054 TSENS4_POINT1_MASK);
1055 tsens5_point1 = (calib_data_backup[1] &
1056 TSENS5_POINT1_MASK) >> TSENS5_POINT1_SHIFT;
1057 tsens6_point1 = (calib_data_backup[1] &
1058 TSENS6_POINT1_MASK) >> TSENS6_POINT1_SHIFT;
1059 tsens7_point1 = (calib_data_backup[1] &
1060 TSENS7_POINT1_MASK) >> TSENS7_POINT1_SHIFT;
1061 tsens8_point1 = (calib_data_backup[2] &
1062 TSENS8_POINT1_MASK_BACKUP) >>
1063 TSENS8_POINT1_SHIFT;
1064 tsens9_point1 = (calib_data_backup[2] &
1065 TSENS9_POINT1_MASK_BACKUP) >>
1066 TSENS9_POINT1_BACKUP_SHIFT;
1067 tsens10_point1 = (calib_data_backup[2] &
1068 TSENS10_POINT1_MASK_BACKUP) >>
1069 TSENS10_POINT1_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001070 } else
1071 goto calibration_less_mode;
1072
1073 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001074 tsens_base2_data = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001075 TSENS_BASE2_BACKUP_MASK) >>
1076 TSENS_POINT2_BASE_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001077 tsens0_point2 = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001078 TSENS0_POINT2_BACKUP_MASK) >>
1079 TSENS0_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001080 tsens1_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001081 TSENS1_POINT2_BACKUP_MASK);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001082 tsens2_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001083 TSENS2_POINT2_BACKUP_MASK) >>
1084 TSENS2_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001085 tsens3_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001086 TSENS3_POINT2_BACKUP_MASK) >>
1087 TSENS3_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001088 tsens4_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001089 TSENS4_POINT2_BACKUP_MASK) >>
1090 TSENS4_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001091 tsens5_point2 = (calib_data[4] &
1092 TSENS5_POINT2_BACKUP_MASK) >>
1093 TSENS5_POINT2_BACKUP_SHIFT;
1094 tsens6_point2 = (calib_data[5] &
1095 TSENS6_POINT2_BACKUP_MASK);
1096 tsens7_point2 = (calib_data[5] &
1097 TSENS7_POINT2_BACKUP_MASK) >>
1098 TSENS7_POINT2_BACKUP_SHIFT;
1099 tsens8_point2 = (calib_data[5] &
1100 TSENS8_POINT2_BACKUP_MASK) >>
1101 TSENS8_POINT2_BACKUP_SHIFT;
1102 tsens9_point2 = (calib_data[5] &
1103 TSENS9_POINT2_BACKUP_MASK) >>
1104 TSENS9_POINT2_BACKUP_SHIFT;
1105 tsens10_point2 = (calib_data[5] &
1106 TSENS10_POINT2_BACKUP_MASK)
1107 >> TSENS10_POINT2_BACKUP_SHIFT;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001108 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001109 } else {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001110 tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
1111 >> TSENS_CAL_SEL_SHIFT;
1112 temp = (calib_data[3] & TSENS_CAL_SEL_2)
1113 >> TSENS_CAL_SEL_SHIFT_2;
1114 tsens_calibration_mode |= temp;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001115 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001116 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) ||
1117 (tsens_calibration_mode ==
1118 TSENS_ONE_POINT_CALIB_OPTION_2) ||
1119 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001120 tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
1121 tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
1122 TSENS0_POINT1_SHIFT;
1123 tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
1124 TSENS1_POINT1_SHIFT;
1125 tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
1126 TSENS2_POINT1_SHIFT;
1127 tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
1128 TSENS3_POINT1_SHIFT;
1129 tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
1130 tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
1131 TSENS5_POINT1_SHIFT;
1132 tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
1133 TSENS6_POINT1_SHIFT;
1134 tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
1135 TSENS7_POINT1_SHIFT;
1136 tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
1137 TSENS8_POINT1_SHIFT;
1138 tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
1139 tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK)
1140 >> TSENS10_POINT1_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001141 } else
1142 goto calibration_less_mode;
1143
1144 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001145 tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
1146 TSENS_POINT2_BASE_SHIFT;
1147 tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
1148 TSENS0_POINT2_SHIFT;
1149 tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
1150 TSENS1_POINT2_SHIFT;
1151 tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
1152 tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
1153 TSENS3_POINT2_SHIFT;
1154 tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
1155 TSENS4_POINT2_SHIFT;
1156 tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
1157 TSENS5_POINT2_SHIFT;
1158 tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
1159 TSENS6_POINT2_SHIFT;
1160 tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
1161 tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
1162 TSENS8_POINT2_SHIFT;
1163 tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
1164 TSENS9_POINT2_SHIFT;
1165 tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK)
1166 >> TSENS10_POINT2_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001167 }
1168
1169 if (tsens_calibration_mode == 0) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001170calibration_less_mode:
1171 pr_debug("TSENS is calibrationless mode\n");
1172 for (i = 0; i < tmdev->tsens_num_sensor; i++)
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001173 calib_tsens_point2_data[i] = 780;
1174 calib_tsens_point1_data[0] = 502;
1175 calib_tsens_point1_data[1] = 509;
1176 calib_tsens_point1_data[2] = 503;
1177 calib_tsens_point1_data[3] = 509;
1178 calib_tsens_point1_data[4] = 505;
1179 calib_tsens_point1_data[5] = 509;
1180 calib_tsens_point1_data[6] = 507;
1181 calib_tsens_point1_data[7] = 510;
1182 calib_tsens_point1_data[8] = 508;
1183 calib_tsens_point1_data[9] = 509;
1184 calib_tsens_point1_data[10] = 508;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001185 goto compute_intercept_slope;
1186 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001187 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001188
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001189 if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001190 calib_tsens_point1_data[0] =
1191 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1192 + tsens0_point1;
1193 calib_tsens_point1_data[1] =
1194 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1195 + tsens1_point1;
1196 calib_tsens_point1_data[2] =
1197 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1198 + tsens2_point1;
1199 calib_tsens_point1_data[3] =
1200 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1201 + tsens3_point1;
1202 calib_tsens_point1_data[4] =
1203 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1204 + tsens4_point1;
1205 calib_tsens_point1_data[5] =
1206 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1207 + tsens5_point1;
1208 calib_tsens_point1_data[6] =
1209 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1210 + tsens6_point1;
1211 calib_tsens_point1_data[7] =
1212 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1213 + tsens7_point1;
1214 calib_tsens_point1_data[8] =
1215 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1216 + tsens8_point1;
1217 calib_tsens_point1_data[9] =
1218 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1219 + tsens9_point1;
1220 calib_tsens_point1_data[10] =
1221 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1222 + tsens10_point1;
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001223 }
1224
Siddartha Mohanadoss4d9815a2012-09-09 17:16:05 -07001225 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
1226 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001227 pr_debug("one point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001228 calib_tsens_point1_data[0] =
1229 ((((tsens_base1_data) + tsens0_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001230 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001231 calib_tsens_point1_data[1] =
1232 ((((tsens_base1_data) + tsens1_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001233 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001234 calib_tsens_point1_data[2] =
1235 ((((tsens_base1_data) + tsens2_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001236 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001237 calib_tsens_point1_data[3] =
1238 ((((tsens_base1_data) + tsens3_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[4] =
1241 ((((tsens_base1_data) + tsens4_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[5] =
1244 ((((tsens_base1_data) + tsens5_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[6] =
1247 ((((tsens_base1_data) + tsens6_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[7] =
1250 ((((tsens_base1_data) + tsens7_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[8] =
1253 ((((tsens_base1_data) + tsens8_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[9] =
1256 ((((tsens_base1_data) + tsens9_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[10] =
1259 ((((tsens_base1_data) + tsens10_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001260 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001261 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001262
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001263 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001264 pr_debug("two point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001265 calib_tsens_point2_data[0] =
1266 (((tsens_base2_data + tsens0_point2) << 2) |
1267 TSENS_BIT_APPEND);
1268 calib_tsens_point2_data[1] =
1269 (((tsens_base2_data + tsens1_point2) << 2) |
1270 TSENS_BIT_APPEND);
1271 calib_tsens_point2_data[2] =
1272 (((tsens_base2_data + tsens2_point2) << 2) |
1273 TSENS_BIT_APPEND);
1274 calib_tsens_point2_data[3] =
1275 (((tsens_base2_data + tsens3_point2) << 2) |
1276 TSENS_BIT_APPEND);
1277 calib_tsens_point2_data[4] =
1278 (((tsens_base2_data + tsens4_point2) << 2) |
1279 TSENS_BIT_APPEND);
1280 calib_tsens_point2_data[5] =
1281 (((tsens_base2_data + tsens5_point2) << 2) |
1282 TSENS_BIT_APPEND);
1283 calib_tsens_point2_data[6] =
1284 (((tsens_base2_data + tsens6_point2) << 2) |
1285 TSENS_BIT_APPEND);
1286 calib_tsens_point2_data[7] =
1287 (((tsens_base2_data + tsens7_point2) << 2) |
1288 TSENS_BIT_APPEND);
1289 calib_tsens_point2_data[8] =
1290 (((tsens_base2_data + tsens8_point2) << 2) |
1291 TSENS_BIT_APPEND);
1292 calib_tsens_point2_data[9] =
1293 (((tsens_base2_data + tsens9_point2) << 2) |
1294 TSENS_BIT_APPEND);
1295 calib_tsens_point2_data[10] =
1296 (((tsens_base2_data + tsens10_point2) << 2) |
1297 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001298 }
1299
1300compute_intercept_slope:
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001301 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1302 int32_t num = 0, den = 0;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001303 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
1304 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001305 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
1306 i, tmdev->sensor[i].calib_data_point1,
1307 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001308 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001309 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
1310 temp_120_degc - temp_30_degc (x2 - x1) */
1311 num = tmdev->sensor[i].calib_data_point2 -
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001312 tmdev->sensor[i].calib_data_point1;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001313 num *= tmdev->tsens_factor;
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001314 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001315 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001316 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001317 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
1318 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
1319 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001320 pr_debug("offset:%d\n", tmdev->sensor[i].offset);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001321 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
1322 tmdev->prev_reading_avail = false;
1323 }
1324
1325 return 0;
1326}
1327
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001328static int tsens_calib_sensors(void)
1329{
1330 int rc = 0;
1331
1332 if (!tmdev)
1333 return -ENODEV;
1334
1335 if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8974)
1336 rc = tsens_calib_8974_sensors();
1337 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
1338 rc = tsens_calib_8x26_sensors();
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -07001339 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X10)
1340 rc = tsens_calib_8x10_sensors();
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001341 else
1342 rc = -ENODEV;
1343
1344 return rc;
1345}
1346
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001347static int get_device_tree_data(struct platform_device *pdev)
1348{
Siddartha Mohanadoss630def02013-06-27 14:53:38 -07001349 struct device_node *of_node = pdev->dev.of_node;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001350 struct resource *res_mem = NULL;
1351 u32 *tsens_slope_data;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001352 u32 *sensor_id;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001353 u32 rc = 0, i, tsens_num_sensors, calib_type;
1354 const char *tsens_calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001355
1356 rc = of_property_read_u32(of_node,
1357 "qcom,sensors", &tsens_num_sensors);
1358 if (rc) {
1359 dev_err(&pdev->dev, "missing sensor number\n");
1360 return -ENODEV;
1361 }
1362
1363 tsens_slope_data = devm_kzalloc(&pdev->dev,
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001364 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001365 if (!tsens_slope_data) {
1366 dev_err(&pdev->dev, "can not allocate slope data\n");
1367 return -ENOMEM;
1368 }
1369
1370 rc = of_property_read_u32_array(of_node,
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001371 "qcom,slope", tsens_slope_data, tsens_num_sensors);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001372 if (rc) {
1373 dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
1374 return rc;
1375 };
1376
Siddartha Mohanadoss630def02013-06-27 14:53:38 -07001377 rc = of_property_read_string(of_node,
1378 "qcom,calib-mode", &tsens_calib_mode);
1379 if (rc) {
1380 dev_err(&pdev->dev, "missing calib-mode\n");
1381 return -ENODEV;
1382 }
1383
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001384 if (!strncmp(tsens_calib_mode, "fuse_map1", 9))
1385 calib_type = TSENS_CALIB_FUSE_MAP_8974;
1386 else if (!strncmp(tsens_calib_mode, "fuse_map2", 9))
1387 calib_type = TSENS_CALIB_FUSE_MAP_8X26;
1388 else if (!strncmp(tsens_calib_mode, "fuse_map3", 9))
1389 calib_type = TSENS_CALIB_FUSE_MAP_8X10;
1390 else {
1391 pr_err("%s: Invalid calibration property\n", __func__);
1392 return -EINVAL;
1393 }
1394
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001395 tmdev = devm_kzalloc(&pdev->dev,
1396 sizeof(struct tsens_tm_device) +
1397 tsens_num_sensors *
1398 sizeof(struct tsens_tm_device_sensor),
1399 GFP_KERNEL);
1400 if (tmdev == NULL) {
1401 pr_err("%s: kzalloc() failed.\n", __func__);
1402 return -ENOMEM;
1403 }
1404
1405 for (i = 0; i < tsens_num_sensors; i++)
1406 tmdev->sensor[i].slope_mul_tsens_factor = tsens_slope_data[i];
1407 tmdev->tsens_factor = TSENS_SLOPE_FACTOR;
1408 tmdev->tsens_num_sensor = tsens_num_sensors;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001409 tmdev->calibration_less_mode = of_property_read_bool(of_node,
1410 "qcom,calibration-less-mode");
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001411 tmdev->calib_mode = calib_type;
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -07001412 tmdev->tsens_local_init = of_property_read_bool(of_node,
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -07001413 "qcom,tsens-local-init");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001414
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001415 sensor_id = devm_kzalloc(&pdev->dev,
1416 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
1417 if (!sensor_id) {
1418 dev_err(&pdev->dev, "can not allocate sensor id\n");
1419 return -ENOMEM;
1420 }
1421
1422 rc = of_property_read_u32_array(of_node,
1423 "qcom,sensor-id", sensor_id, tsens_num_sensors);
1424 if (rc) {
1425 pr_debug("Default sensor id mapping\n");
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001426 for (i = 0; i < tsens_num_sensors; i++) {
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001427 tmdev->sensor[i].sensor_hw_num = i;
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001428 tmdev->sensor[i].sensor_sw_id = i;
1429 }
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001430 } else {
1431 pr_debug("Use specified sensor id mapping\n");
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001432 for (i = 0; i < tsens_num_sensors; i++) {
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001433 tmdev->sensor[i].sensor_hw_num = sensor_id[i];
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001434 tmdev->sensor[i].sensor_sw_id = i;
1435 }
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001436 }
1437
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001438 tmdev->tsens_irq = platform_get_irq(pdev, 0);
1439 if (tmdev->tsens_irq < 0) {
1440 pr_err("Invalid get irq\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001441 rc = tmdev->tsens_irq;
1442 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001443 }
1444
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001445 /* TSENS register region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001446 tmdev->res_tsens_mem = platform_get_resource_byname(pdev,
1447 IORESOURCE_MEM, "tsens_physical");
1448 if (!tmdev->res_tsens_mem) {
1449 pr_err("Could not get tsens physical address resource\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001450 rc = -EINVAL;
1451 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001452 }
1453
1454 tmdev->tsens_len = tmdev->res_tsens_mem->end -
1455 tmdev->res_tsens_mem->start + 1;
1456
1457 res_mem = request_mem_region(tmdev->res_tsens_mem->start,
1458 tmdev->tsens_len, tmdev->res_tsens_mem->name);
1459 if (!res_mem) {
1460 pr_err("Request tsens physical memory region failed\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001461 rc = -EINVAL;
1462 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001463 }
1464
1465 tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
1466 if (!tmdev->tsens_addr) {
1467 pr_err("Failed to IO map TSENS registers.\n");
1468 rc = -EINVAL;
1469 goto fail_unmap_tsens_region;
1470 }
1471
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001472 /* TSENS calibration region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001473 tmdev->res_calib_mem = platform_get_resource_byname(pdev,
1474 IORESOURCE_MEM, "tsens_eeprom_physical");
1475 if (!tmdev->res_calib_mem) {
1476 pr_err("Could not get qfprom physical address resource\n");
1477 rc = -EINVAL;
1478 goto fail_unmap_tsens;
1479 }
1480
1481 tmdev->calib_len = tmdev->res_calib_mem->end -
1482 tmdev->res_calib_mem->start + 1;
1483
1484 res_mem = request_mem_region(tmdev->res_calib_mem->start,
1485 tmdev->calib_len, tmdev->res_calib_mem->name);
1486 if (!res_mem) {
1487 pr_err("Request calibration memory region failed\n");
1488 rc = -EINVAL;
1489 goto fail_unmap_tsens;
1490 }
1491
1492 tmdev->tsens_calib_addr = ioremap(res_mem->start,
1493 tmdev->calib_len);
1494 if (!tmdev->tsens_calib_addr) {
1495 pr_err("Failed to IO map EEPROM registers.\n");
1496 rc = -EINVAL;
1497 goto fail_unmap_calib_region;
1498 }
1499
1500 return 0;
1501
1502fail_unmap_calib_region:
1503 if (tmdev->res_calib_mem)
1504 release_mem_region(tmdev->res_calib_mem->start,
1505 tmdev->calib_len);
1506fail_unmap_tsens:
1507 if (tmdev->tsens_addr)
1508 iounmap(tmdev->tsens_addr);
1509fail_unmap_tsens_region:
1510 if (tmdev->res_tsens_mem)
1511 release_mem_region(tmdev->res_tsens_mem->start,
1512 tmdev->tsens_len);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001513fail_tmdev:
1514 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001515 return rc;
1516}
1517
1518static int __devinit tsens_tm_probe(struct platform_device *pdev)
1519{
1520 int rc;
1521
1522 if (tmdev) {
1523 pr_err("TSENS device already in use\n");
1524 return -EBUSY;
1525 }
1526
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001527 if (pdev->dev.of_node) {
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001528 rc = get_device_tree_data(pdev);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001529 if (rc) {
1530 pr_err("Error reading TSENS DT\n");
1531 return rc;
1532 }
1533 } else
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001534 return -ENODEV;
1535
1536 tmdev->pdev = pdev;
Matt Wagantall83026d62013-05-22 18:07:04 -07001537 tmdev->tsens_wq = alloc_workqueue("tsens_wq", WQ_HIGHPRI, 0);
1538 if (!tmdev->tsens_wq) {
1539 rc = -ENOMEM;
1540 goto fail;
1541 }
1542
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001543 rc = tsens_calib_sensors();
Michael Bohanb89167e2012-10-04 16:24:23 -07001544 if (rc < 0) {
1545 pr_err("Calibration failed\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001546 goto fail;
Michael Bohanb89167e2012-10-04 16:24:23 -07001547 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001548
1549 tsens_hw_init();
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001550
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001551 tmdev->prev_reading_avail = true;
1552
1553 platform_set_drvdata(pdev, tmdev);
1554
1555 return 0;
1556fail:
Matt Wagantall83026d62013-05-22 18:07:04 -07001557 if (tmdev->tsens_wq)
1558 destroy_workqueue(tmdev->tsens_wq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001559 if (tmdev->tsens_calib_addr)
1560 iounmap(tmdev->tsens_calib_addr);
1561 if (tmdev->res_calib_mem)
1562 release_mem_region(tmdev->res_calib_mem->start,
1563 tmdev->calib_len);
1564 if (tmdev->tsens_addr)
1565 iounmap(tmdev->tsens_addr);
1566 if (tmdev->res_tsens_mem)
1567 release_mem_region(tmdev->res_tsens_mem->start,
1568 tmdev->tsens_len);
Michael Bohanb89167e2012-10-04 16:24:23 -07001569 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001570
1571 return rc;
1572}
1573
1574static int __devinit _tsens_register_thermal(void)
1575{
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001576 struct platform_device *pdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001577 int rc, i;
1578
1579 if (!tmdev) {
1580 pr_err("%s: TSENS early init not done\n", __func__);
1581 return -ENODEV;
1582 }
1583
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001584 pdev = tmdev->pdev;
1585
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001586 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1587 char name[18];
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001588 snprintf(name, sizeof(name), "tsens_tz_sensor%d",
1589 tmdev->sensor[i].sensor_hw_num);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001590 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001591 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
1592 TSENS_TRIP_NUM, &tmdev->sensor[i],
1593 &tsens_thermal_zone_ops, 0, 0, 0, 0);
1594 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
1595 pr_err("%s: thermal_zone_device_register() failed.\n",
1596 __func__);
1597 rc = -ENODEV;
1598 goto fail;
1599 }
1600 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001601
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001602 rc = request_irq(tmdev->tsens_irq, tsens_isr,
1603 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
1604 if (rc < 0) {
1605 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
1606 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1607 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1608 goto fail;
Siddartha Mohanadossb9be9812013-02-13 11:03:32 -08001609 } else {
1610 enable_irq_wake(tmdev->tsens_irq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001611 }
1612 platform_set_drvdata(pdev, tmdev);
1613
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -07001614 INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
1615
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001616 return 0;
1617fail:
1618 if (tmdev->tsens_calib_addr)
1619 iounmap(tmdev->tsens_calib_addr);
1620 if (tmdev->res_calib_mem)
1621 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001622 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001623 if (tmdev->tsens_addr)
1624 iounmap(tmdev->tsens_addr);
1625 if (tmdev->res_tsens_mem)
1626 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001627 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001628 return rc;
1629}
1630
1631static int __devexit tsens_tm_remove(struct platform_device *pdev)
1632{
1633 struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
1634 int i;
1635
1636 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1637 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1638 if (tmdev->tsens_calib_addr)
1639 iounmap(tmdev->tsens_calib_addr);
1640 if (tmdev->res_calib_mem)
1641 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001642 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001643 if (tmdev->tsens_addr)
1644 iounmap(tmdev->tsens_addr);
1645 if (tmdev->res_tsens_mem)
1646 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001647 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001648 free_irq(tmdev->tsens_irq, tmdev);
Matt Wagantall83026d62013-05-22 18:07:04 -07001649 destroy_workqueue(tmdev->tsens_wq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001650 platform_set_drvdata(pdev, NULL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001651
1652 return 0;
1653}
1654
1655static struct of_device_id tsens_match[] = {
1656 { .compatible = "qcom,msm-tsens",
1657 },
1658 {}
1659};
1660
1661static struct platform_driver tsens_tm_driver = {
1662 .probe = tsens_tm_probe,
1663 .remove = tsens_tm_remove,
1664 .driver = {
1665 .name = "msm-tsens",
1666 .owner = THIS_MODULE,
1667 .of_match_table = tsens_match,
1668 },
1669};
1670
Siddartha Mohanadoss4cef5f42013-04-11 13:59:41 -07001671int __init tsens_tm_init_driver(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001672{
1673 return platform_driver_register(&tsens_tm_driver);
1674}
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001675
1676static int __init tsens_thermal_register(void)
1677{
1678 return _tsens_register_thermal();
1679}
1680module_init(tsens_thermal_register);
1681
1682static void __exit _tsens_tm_remove(void)
1683{
1684 platform_driver_unregister(&tsens_tm_driver);
1685}
1686module_exit(_tsens_tm_remove);
1687
1688MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
1689MODULE_LICENSE("GPL v2");