blob: 52608af749246f1b5ff32a780222693e753654a5 [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
80
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070081/* TSENS calibration Mask data */
82#define TSENS_BASE1_MASK 0xff
83#define TSENS0_POINT1_MASK 0x3f00
84#define TSENS1_POINT1_MASK 0xfc000
85#define TSENS2_POINT1_MASK 0x3f00000
86#define TSENS3_POINT1_MASK 0xfc000000
87#define TSENS4_POINT1_MASK 0x3f
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070088#define TSENS5_POINT1_MASK 0xfc0
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070089#define TSENS6_POINT1_MASK 0x3f000
90#define TSENS7_POINT1_MASK 0xfc0000
91#define TSENS8_POINT1_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070092#define TSENS8_POINT1_MASK_BACKUP 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070093#define TSENS9_POINT1_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070094#define TSENS9_POINT1_MASK_BACKUP 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -080095#define TSENS10_POINT1_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -070096#define TSENS10_POINT1_MASK_BACKUP 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070097#define TSENS_CAL_SEL_0_1 0xc0000000
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -070098#define TSENS_CAL_SEL_2 0x40000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -070099#define TSENS_CAL_SEL_SHIFT 30
100#define TSENS_CAL_SEL_SHIFT_2 28
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700101#define TSENS_ONE_POINT_CALIB 0x1
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -0700102#define TSENS_ONE_POINT_CALIB_OPTION_2 0x2
103#define TSENS_TWO_POINT_CALIB 0x3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700104
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700105#define TSENS0_POINT1_SHIFT 8
106#define TSENS1_POINT1_SHIFT 14
107#define TSENS2_POINT1_SHIFT 20
108#define TSENS3_POINT1_SHIFT 26
109#define TSENS5_POINT1_SHIFT 6
110#define TSENS6_POINT1_SHIFT 12
111#define TSENS7_POINT1_SHIFT 18
112#define TSENS8_POINT1_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700113#define TSENS9_POINT1_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700114#define TSENS10_POINT1_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700115#define TSENS10_POINT1_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700116
117#define TSENS_POINT2_BASE_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700118#define TSENS_POINT2_BASE_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700119#define TSENS0_POINT2_SHIFT 20
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700120#define TSENS0_POINT2_BACKUP_SHIFT 26
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700121#define TSENS1_POINT2_SHIFT 26
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700122#define TSENS2_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700123#define TSENS3_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700124#define TSENS3_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700125#define TSENS4_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700126#define TSENS4_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700127#define TSENS5_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700128#define TSENS5_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700129#define TSENS6_POINT2_SHIFT 24
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700130#define TSENS7_POINT2_BACKUP_SHIFT 6
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700131#define TSENS8_POINT2_SHIFT 6
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700132#define TSENS8_POINT2_BACKUP_SHIFT 12
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700133#define TSENS9_POINT2_SHIFT 12
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700134#define TSENS9_POINT2_BACKUP_SHIFT 18
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700135#define TSENS10_POINT2_SHIFT 18
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700136#define TSENS10_POINT2_BACKUP_SHIFT 24
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700137
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700138#define TSENS_BASE2_MASK 0xff000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700139#define TSENS_BASE2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700140#define TSENS0_POINT2_MASK 0x3f00000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700141#define TSENS0_POINT2_BACKUP_MASK 0xfc000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700142#define TSENS1_POINT2_MASK 0xfc000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700143#define TSENS1_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700144#define TSENS2_POINT2_MASK 0x3f
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700145#define TSENS2_POINT2_BACKUP_MASK 0xfc0
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800146#define TSENS3_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700147#define TSENS3_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700148#define TSENS4_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700149#define TSENS4_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700150#define TSENS5_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700151#define TSENS5_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700152#define TSENS6_POINT2_MASK 0x3f000000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700153#define TSENS6_POINT2_BACKUP_MASK 0x3f
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700154#define TSENS7_POINT2_MASK 0x3f
Siddartha Mohanadoss44653e82013-02-08 16:04:29 -0800155#define TSENS7_POINT2_BACKUP_MASK 0xfc0
156#define TSENS8_POINT2_MASK 0xfc0
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700157#define TSENS8_POINT2_BACKUP_MASK 0x3f000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700158#define TSENS9_POINT2_MASK 0x3f000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700159#define TSENS9_POINT2_BACKUP_MASK 0xfc0000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700160#define TSENS10_POINT2_MASK 0xfc0000
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700161#define TSENS10_POINT2_BACKUP_MASK 0x3f000000
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700162
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800163#define TSENS_8X26_BASE0_MASK 0x1fe000
164#define TSENS0_8X26_POINT1_MASK 0x7f00000
165#define TSENS1_8X26_POINT1_MASK 0x3f
166#define TSENS2_8X26_POINT1_MASK 0xfc0
167#define TSENS3_8X26_POINT1_MASK 0x3f000
168#define TSENS4_8X26_POINT1_MASK 0xfc0000
169#define TSENS5_8X26_POINT1_MASK 0x3f000000
170#define TSENS6_8X26_POINT1_MASK 0x3f00000
171#define TSENS_8X26_TSENS_CAL_SEL 0xe0000000
172#define TSENS_8X26_BASE1_MASK 0xff
173#define TSENS0_8X26_POINT2_MASK 0x3f00
174#define TSENS1_8X26_POINT2_MASK 0xfc00
175#define TSENS2_8X26_POINT2_MASK 0x3f00000
176#define TSENS3_8X26_POINT2_MASK 0xfc000000
177#define TSENS4_8X26_POINT2_MASK 0xfc000000
178#define TSENS5_8X26_POINT2_MASK 0x3f00000
179#define TSENS6_8X26_POINT2_MASK 0x7e0000
180
181#define TSENS_8X26_CAL_SEL_SHIFT 29
182#define TSENS_8X26_BASE0_SHIFT 13
183#define TSENS0_8X26_POINT1_SHIFT 21
184#define TSENS2_8X26_POINT1_SHIFT 6
185#define TSENS3_8X26_POINT1_SHIFT 12
186#define TSENS4_8X26_POINT1_SHIFT 18
187#define TSENS5_8X26_POINT1_SHIFT 24
188#define TSENS6_8X26_POINT1_SHIFT 20
189
190#define TSENS0_8X26_POINT2_SHIFT 8
191#define TSENS1_8X26_POINT2_SHIFT 14
192#define TSENS2_8X26_POINT2_SHIFT 20
193#define TSENS3_8X26_POINT2_SHIFT 26
194#define TSENS4_8X26_POINT2_SHIFT 20
195#define TSENS5_8X26_POINT2_SHIFT 26
196#define TSENS6_8X26_POINT2_SHIFT 17
197
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700198#define TSENS_8X10_CAL_SEL_SHIFT 28
199#define TSENS_8X10_BASE1_SHIFT 8
200#define TSENS0_8X10_POINT1_SHIFT 16
201#define TSENS0_8X10_POINT2_SHIFT 22
202#define TSENS1_8X10_POINT2_SHIFT 6
Siddartha Mohanadoss74c700c2013-05-07 20:33:42 -0700203#define TSENS_8X10_BASE0_MASK 0xff
204#define TSENS_8X10_BASE1_MASK 0xff00
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700205#define TSENS0_8X10_POINT1_MASK 0x3f0000
206#define TSENS0_8X10_POINT2_MASK 0xfc00000
207#define TSENS_8X10_TSENS_CAL_SEL 0x70000000
208#define TSENS1_8X10_POINT1_MASK 0x3f
209#define TSENS1_8X10_POINT2_MASK 0xfc0
210
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700211#define TSENS_BIT_APPEND 0x3
212#define TSENS_CAL_DEGC_POINT1 30
213#define TSENS_CAL_DEGC_POINT2 120
214#define TSENS_SLOPE_FACTOR 1000
215
216/* TSENS register data */
217#define TSENS_TRDY_RDY_MIN_TIME 2000
218#define TSENS_TRDY_RDY_MAX_TIME 2100
219#define TSENS_THRESHOLD_MAX_CODE 0x3ff
220#define TSENS_THRESHOLD_MIN_CODE 0x0
221
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700222#define TSENS_GLOBAL_INIT_DATA 0x302f16c
223#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700224#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700225#define TSENS_SN_REMOTE_CFG_DATA 0x11c3
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700226
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700227#define TSENS_QFPROM_BACKUP_SEL 0x3
228#define TSENS_QFPROM_BACKUP_REDUN_SEL 0xe0000000
229#define TSENS_QFPROM_BACKUP_REDUN_SHIFT 29
230
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800231enum tsens_calib_fuse_map_type {
232 TSENS_CALIB_FUSE_MAP_8974 = 0,
233 TSENS_CALIB_FUSE_MAP_8X26,
234 TSENS_CALIB_FUSE_MAP_8X10,
235 TSENS_CALIB_FUSE_MAP_NUM,
236};
237
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700238/* Trips: warm and cool */
239enum tsens_trip_type {
240 TSENS_TRIP_WARM = 0,
241 TSENS_TRIP_COOL,
242 TSENS_TRIP_NUM,
243};
244
245struct tsens_tm_device_sensor {
246 struct thermal_zone_device *tz_dev;
247 enum thermal_device_mode mode;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700248 /* Physical HW sensor number */
249 unsigned int sensor_hw_num;
250 /* Software index. This is keep track of the HW/SW
251 * sensor_ID mapping */
252 unsigned int sensor_sw_id;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700253 struct work_struct work;
254 int offset;
255 int calib_data_point1;
256 int calib_data_point2;
257 uint32_t slope_mul_tsens_factor;
258};
259
260struct tsens_tm_device {
261 struct platform_device *pdev;
Matt Wagantall83026d62013-05-22 18:07:04 -0700262 struct workqueue_struct *tsens_wq;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700263 bool prev_reading_avail;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -0700264 bool calibration_less_mode;
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700265 bool tsens_local_init;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700266 int tsens_factor;
267 uint32_t tsens_num_sensor;
268 int tsens_irq;
269 void *tsens_addr;
270 void *tsens_calib_addr;
271 int tsens_len;
272 int calib_len;
273 struct resource *res_tsens_mem;
274 struct resource *res_calib_mem;
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700275 struct work_struct tsens_work;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800276 uint32_t calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700277 struct tsens_tm_device_sensor sensor[0];
278};
279
280struct tsens_tm_device *tmdev;
281
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700282int tsens_get_sw_id_mapping(int sensor_hw_num, int *sensor_sw_idx)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700283{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700284 int i = 0;
285 bool id_found = false;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700286
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700287 while (i < tmdev->tsens_num_sensor && !id_found) {
288 if (sensor_hw_num == tmdev->sensor[i].sensor_hw_num) {
Siddartha Mohanadossee00f422013-04-17 11:33:01 -0700289 *sensor_sw_idx = tmdev->sensor[i].sensor_sw_id;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700290 id_found = true;
291 }
292 i++;
293 }
294
295 if (!id_found)
296 return -EINVAL;
297
298 return 0;
299}
300EXPORT_SYMBOL(tsens_get_sw_id_mapping);
301
302int tsens_get_hw_id_mapping(int sensor_sw_id, int *sensor_hw_num)
303{
304 int i = 0;
305 bool id_found = false;
306
307 while (i < tmdev->tsens_num_sensor && !id_found) {
308 if (sensor_sw_id == tmdev->sensor[i].sensor_sw_id) {
Siddartha Mohanadossee00f422013-04-17 11:33:01 -0700309 *sensor_hw_num = tmdev->sensor[i].sensor_hw_num;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700310 id_found = true;
311 }
312 i++;
313 }
314
315 if (!id_found)
316 return -EINVAL;
317
318 return 0;
319}
320EXPORT_SYMBOL(tsens_get_hw_id_mapping);
321
322static int tsens_tz_code_to_degc(int adc_code, int sensor_sw_id)
323{
324 int degc, num, den, idx;
325
326 idx = sensor_sw_id;
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700327 num = ((adc_code * tmdev->tsens_factor) -
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700328 tmdev->sensor[idx].offset);
329 den = (int) tmdev->sensor[idx].slope_mul_tsens_factor;
Siddartha Mohanadossa9387a32012-10-14 20:39:41 -0700330
Siddartha Mohanadoss8cc1fbc2013-04-05 15:10:52 -0700331 if (num > 0)
332 degc = ((num + (den/2))/den);
333 else if (num < 0)
334 degc = ((num - (den/2))/den);
335 else
336 degc = num/den;
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -0700337
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700338 pr_debug("raw_code:0x%x, sensor_num:%d, degc:%d\n",
339 adc_code, idx, degc);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700340 return degc;
341}
342
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700343static int tsens_tz_degc_to_code(int degc, int idx)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700344{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700345 int code = ((degc * tmdev->sensor[idx].slope_mul_tsens_factor)
346 + tmdev->sensor[idx].offset)/tmdev->tsens_factor;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700347
348 if (code > TSENS_THRESHOLD_MAX_CODE)
349 code = TSENS_THRESHOLD_MAX_CODE;
350 else if (code < TSENS_THRESHOLD_MIN_CODE)
351 code = TSENS_THRESHOLD_MIN_CODE;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700352 pr_debug("raw_code:0x%x, sensor_num:%d, degc:%d\n",
353 code, idx, degc);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700354 return code;
355}
356
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700357static void msm_tsens_get_temp(int sensor_hw_num, unsigned long *temp)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700358{
359 unsigned int code, sensor_addr;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700360 int sensor_sw_id = -EINVAL, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700361
362 if (!tmdev->prev_reading_avail) {
363 while (!(readl_relaxed(TSENS_TRDY_ADDR(tmdev->tsens_addr))
364 & TSENS_TRDY_MASK))
365 usleep_range(TSENS_TRDY_RDY_MIN_TIME,
366 TSENS_TRDY_RDY_MAX_TIME);
367 tmdev->prev_reading_avail = true;
368 }
369
370 sensor_addr =
371 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
372 code = readl_relaxed(sensor_addr +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700373 (sensor_hw_num << TSENS_STATUS_ADDR_OFFSET));
374 /* Obtain SW index to map the corresponding thermal zone's
375 * offset and slope for code to degc conversion. */
376 rc = tsens_get_sw_id_mapping(sensor_hw_num, &sensor_sw_id);
377 if (rc < 0) {
378 pr_err("tsens mapping index not found\n");
379 return;
380 }
381
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700382 *temp = tsens_tz_code_to_degc((code & TSENS_SN_STATUS_TEMP_MASK),
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700383 sensor_sw_id);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700384}
385
386static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
387 unsigned long *temp)
388{
389 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
390
391 if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
392 return -EINVAL;
393
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700394 msm_tsens_get_temp(tm_sensor->sensor_hw_num, temp);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700395
396 return 0;
397}
398
399int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
400{
401 if (!tmdev)
402 return -ENODEV;
403
404 msm_tsens_get_temp(device->sensor_num, temp);
405
406 return 0;
407}
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700408EXPORT_SYMBOL(tsens_get_temp);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700409
Siddartha Mohanadossb66effc2013-04-04 19:48:17 -0700410int tsens_get_max_sensor_num(uint32_t *tsens_num_sensors)
411{
412 if (!tmdev)
413 return -ENODEV;
414
415 *tsens_num_sensors = tmdev->tsens_num_sensor;
416
417 return 0;
418}
419EXPORT_SYMBOL(tsens_get_max_sensor_num);
420
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700421static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
422 enum thermal_device_mode *mode)
423{
424 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
425
426 if (!tm_sensor || !mode)
427 return -EINVAL;
428
429 *mode = tm_sensor->mode;
430
431 return 0;
432}
433
434static int tsens_tz_get_trip_type(struct thermal_zone_device *thermal,
435 int trip, enum thermal_trip_type *type)
436{
437 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
438
439 if (!tm_sensor || trip < 0 || !type)
440 return -EINVAL;
441
442 switch (trip) {
443 case TSENS_TRIP_WARM:
444 *type = THERMAL_TRIP_CONFIGURABLE_HI;
445 break;
446 case TSENS_TRIP_COOL:
447 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
448 break;
449 default:
450 return -EINVAL;
451 }
452
453 return 0;
454}
455
456static int tsens_tz_activate_trip_type(struct thermal_zone_device *thermal,
457 int trip, enum thermal_trip_activation_mode mode)
458{
459 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
460 unsigned int reg_cntl, code, hi_code, lo_code, mask;
461
462 if (!tm_sensor || trip < 0)
463 return -EINVAL;
464
465 lo_code = TSENS_THRESHOLD_MIN_CODE;
466 hi_code = TSENS_THRESHOLD_MAX_CODE;
467
468 reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700469 (tmdev->tsens_addr) +
470 (tm_sensor->sensor_hw_num *
471 TSENS_SN_ADDR_OFFSET)));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700472 switch (trip) {
473 case TSENS_TRIP_WARM:
474 code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
475 >> TSENS_UPPER_THRESHOLD_SHIFT;
476 mask = TSENS_UPPER_STATUS_CLR;
477
478 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
479 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
480 break;
481 case TSENS_TRIP_COOL:
482 code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
483 mask = TSENS_LOWER_STATUS_CLR;
484
485 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
486 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
487 >> TSENS_UPPER_THRESHOLD_SHIFT;
488 break;
489 default:
490 return -EINVAL;
491 }
492
493 if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
494 writel_relaxed(reg_cntl | mask,
495 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700496 (tmdev->tsens_addr) +
497 (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET)));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700498 else {
499 if (code < lo_code || code > hi_code) {
500 pr_err("%s with invalid code %x\n", __func__, code);
501 return -EINVAL;
502 }
503 writel_relaxed(reg_cntl & ~mask,
504 (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_addr) +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700505 (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET)));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700506 }
507 mb();
508 return 0;
509}
510
511static int tsens_tz_get_trip_temp(struct thermal_zone_device *thermal,
512 int trip, unsigned long *temp)
513{
514 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
515 unsigned int reg;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700516 int sensor_sw_id = -EINVAL, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700517
518 if (!tm_sensor || trip < 0 || !temp)
519 return -EINVAL;
520
521 reg = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
522 (tmdev->tsens_addr) +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700523 (tm_sensor->sensor_hw_num * TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700524 switch (trip) {
525 case TSENS_TRIP_WARM:
526 reg = (reg & TSENS_UPPER_THRESHOLD_MASK) >>
527 TSENS_UPPER_THRESHOLD_SHIFT;
528 break;
529 case TSENS_TRIP_COOL:
530 reg = (reg & TSENS_LOWER_THRESHOLD_MASK);
531 break;
532 default:
533 return -EINVAL;
534 }
535
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700536 rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id);
537 if (rc < 0) {
538 pr_err("tsens mapping index not found\n");
539 return rc;
540 }
541 *temp = tsens_tz_code_to_degc(reg, sensor_sw_id);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700542
543 return 0;
544}
545
546static int tsens_tz_notify(struct thermal_zone_device *thermal,
547 int count, enum thermal_trip_type type)
548{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700549 /* Critical temperature threshold are enabled and will
550 * shutdown the device once critical thresholds are crossed. */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700551 pr_debug("%s debug\n", __func__);
552 return 1;
553}
554
555static int tsens_tz_set_trip_temp(struct thermal_zone_device *thermal,
556 int trip, long temp)
557{
558 struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
559 unsigned int reg_cntl;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700560 int code, hi_code, lo_code, code_err_chk, sensor_sw_id = 0, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700561
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700562 rc = tsens_get_sw_id_mapping(tm_sensor->sensor_hw_num, &sensor_sw_id);
563 if (rc < 0) {
564 pr_err("tsens mapping index not found\n");
565 return rc;
566 }
567 code_err_chk = code = tsens_tz_degc_to_code(temp, sensor_sw_id);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700568 if (!tm_sensor || trip < 0)
569 return -EINVAL;
570
571 lo_code = TSENS_THRESHOLD_MIN_CODE;
572 hi_code = TSENS_THRESHOLD_MAX_CODE;
573
574 reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700575 (tmdev->tsens_addr) + (tm_sensor->sensor_hw_num *
576 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700577 switch (trip) {
578 case TSENS_TRIP_WARM:
579 code <<= TSENS_UPPER_THRESHOLD_SHIFT;
580 reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
581 if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
582 lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
583 break;
584 case TSENS_TRIP_COOL:
585 reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
586 if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
587 hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
588 >> TSENS_UPPER_THRESHOLD_SHIFT;
589 break;
590 default:
591 return -EINVAL;
592 }
593
594 if (code_err_chk < lo_code || code_err_chk > hi_code)
595 return -EINVAL;
596
597 writel_relaxed(reg_cntl | code, (TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
598 (tmdev->tsens_addr) +
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700599 (tm_sensor->sensor_hw_num *
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700600 TSENS_SN_ADDR_OFFSET)));
601 mb();
602 return 0;
603}
604
605static struct thermal_zone_device_ops tsens_thermal_zone_ops = {
606 .get_temp = tsens_tz_get_temp,
607 .get_mode = tsens_tz_get_mode,
608 .get_trip_type = tsens_tz_get_trip_type,
609 .activate_trip_type = tsens_tz_activate_trip_type,
610 .get_trip_temp = tsens_tz_get_trip_temp,
611 .set_trip_temp = tsens_tz_set_trip_temp,
612 .notify = tsens_tz_notify,
613};
614
615static void notify_uspace_tsens_fn(struct work_struct *work)
616{
617 struct tsens_tm_device_sensor *tm = container_of(work,
618 struct tsens_tm_device_sensor, work);
619
620 sysfs_notify(&tm->tz_dev->device.kobj,
621 NULL, "type");
622}
623
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700624static void tsens_scheduler_fn(struct work_struct *work)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700625{
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700626 struct tsens_tm_device *tm = container_of(work, struct tsens_tm_device,
627 tsens_work);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700628 unsigned int i, status, threshold;
629 unsigned int sensor_status_addr, sensor_status_ctrl_addr;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700630 int sensor_sw_id = -EINVAL, rc = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700631
632 sensor_status_addr =
633 (unsigned int)TSENS_S0_STATUS_ADDR(tmdev->tsens_addr);
634 sensor_status_ctrl_addr =
635 (unsigned int)TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
636 (tmdev->tsens_addr);
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700637 for (i = 0; i < tm->tsens_num_sensor; i++) {
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700638 bool upper_thr = false, lower_thr = false;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700639 uint32_t addr_offset;
640
641 addr_offset = tm->sensor[i].sensor_hw_num *
642 TSENS_SN_ADDR_OFFSET;
643 status = readl_relaxed(sensor_status_addr + addr_offset);
644 threshold = readl_relaxed(sensor_status_ctrl_addr +
645 addr_offset);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700646 if (status & TSENS_SN_STATUS_UPPER_STATUS) {
647 writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700648 TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
649 tmdev->tsens_addr + addr_offset));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700650 upper_thr = true;
651 }
652 if (status & TSENS_SN_STATUS_LOWER_STATUS) {
653 writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700654 TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
655 tmdev->tsens_addr + addr_offset));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700656 lower_thr = true;
657 }
658 if (upper_thr || lower_thr) {
659 /* Notify user space */
Matt Wagantall83026d62013-05-22 18:07:04 -0700660 queue_work(tm->tsens_wq, &tm->sensor[i].work);
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700661 rc = tsens_get_sw_id_mapping(
662 tm->sensor[i].sensor_hw_num,
663 &sensor_sw_id);
664 if (rc < 0)
665 pr_err("tsens mapping index not found\n");
666 pr_debug("sensor:%d trigger temp (%d degC)\n",
667 tm->sensor[i].sensor_hw_num,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700668 tsens_tz_code_to_degc((status &
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700669 TSENS_SN_STATUS_TEMP_MASK),
670 sensor_sw_id));
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700671 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700672 }
673 mb();
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700674}
675
676static irqreturn_t tsens_isr(int irq, void *data)
677{
Matt Wagantall83026d62013-05-22 18:07:04 -0700678 queue_work(tmdev->tsens_wq, &tmdev->tsens_work);
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -0700679
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700680 return IRQ_HANDLED;
681}
682
683static void tsens_hw_init(void)
684{
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700685 unsigned int reg_cntl = 0, sensor_en = 0;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700686 unsigned int i;
687
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700688 if (tmdev->tsens_local_init) {
689 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
690 writel_relaxed(reg_cntl | TSENS_SW_RST,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700691 TSENS_CTRL_ADDR(tmdev->tsens_addr));
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700692 reg_cntl |= (TSENS_62_5_MS_MEAS_PERIOD <<
693 TSENS_MEAS_PERIOD_SHIFT);
694 for (i = 0; i < tmdev->tsens_num_sensor; i++)
695 sensor_en |= (1 << tmdev->sensor[i].sensor_hw_num);
696 sensor_en <<= TSENS_SENSOR0_SHIFT;
697 reg_cntl |= (sensor_en | TSENS_EN);
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700698 writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
699 writel_relaxed(TSENS_GLOBAL_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700700 TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700701 writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700702 TSENS_S0_MAIN_CONFIG(tmdev->tsens_addr));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700703 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
704 writel_relaxed(TSENS_SN_MIN_MAX_STATUS_CTRL_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700705 TSENS_SN_MIN_MAX_STATUS_CTRL(tmdev->tsens_addr)
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700706 + (tmdev->sensor[i].sensor_hw_num *
707 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700708 writel_relaxed(TSENS_SN_REMOTE_CFG_DATA,
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700709 TSENS_SN_REMOTE_CONFIG(tmdev->tsens_addr)
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -0700710 + (tmdev->sensor[i].sensor_hw_num *
711 TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -0700712 }
713 pr_debug("Local TSENS control initialization\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700714 }
715 writel_relaxed(TSENS_INTERRUPT_EN,
716 TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_addr));
717}
718
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700719static int tsens_calib_8x10_sensors(void)
720{
721 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
722 int tsens0_point2 = 0, tsens1_point2 = 0;
723 int tsens_base1_data = 0, tsens_calibration_mode = 0;
724 uint32_t calib_data[2];
725 uint32_t calib_tsens_point1_data[2], calib_tsens_point2_data[2];
726
727 if (tmdev->calibration_less_mode)
728 goto calibration_less_mode;
729
730 calib_data[0] = readl_relaxed(
731 TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr));
732 calib_data[1] = readl_relaxed(
733 (TSENS_EEPROM_8X10_1(tmdev->tsens_calib_addr) +
734 TSENS_EEPROM_8X10_1_OFFSET));
735
736 tsens_calibration_mode = (calib_data[0] & TSENS_8X10_TSENS_CAL_SEL)
737 >> TSENS_8X10_CAL_SEL_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700738 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700739
740 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
741 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
742 tsens_base0_data = (calib_data[0] & TSENS_8X10_BASE0_MASK);
743 tsens0_point1 = (calib_data[0] & TSENS0_8X10_POINT1_MASK) >>
744 TSENS0_8X10_POINT1_SHIFT;
745 tsens1_point1 = calib_data[1] & TSENS1_8X10_POINT1_MASK;
746 } else
747 goto calibration_less_mode;
748
749 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
750 tsens_base1_data = (calib_data[0] & TSENS_8X10_BASE1_MASK) >>
751 TSENS_8X10_BASE1_SHIFT;
752 tsens0_point2 = (calib_data[0] & TSENS0_8X10_POINT2_MASK) >>
753 TSENS0_8X10_POINT2_SHIFT;
754 tsens1_point2 = (calib_data[1] & TSENS1_8X10_POINT2_MASK) >>
755 TSENS1_8X10_POINT2_SHIFT;
756 }
757
758 if (tsens_calibration_mode == 0) {
759calibration_less_mode:
760 pr_debug("TSENS is calibrationless mode\n");
761 for (i = 0; i < tmdev->tsens_num_sensor; i++)
762 calib_tsens_point2_data[i] = 780;
763 calib_tsens_point1_data[0] = 595;
764 calib_tsens_point1_data[1] = 629;
765 goto compute_intercept_slope;
766 }
767
768 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
769 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
770 calib_tsens_point1_data[0] =
771 ((((tsens_base0_data) + tsens0_point1) << 2) |
772 TSENS_BIT_APPEND);
773 calib_tsens_point1_data[1] =
774 ((((tsens_base0_data) + tsens1_point1) << 2) |
775 TSENS_BIT_APPEND);
776 }
777
778 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
779 pr_debug("two point calibration calculation\n");
780 calib_tsens_point2_data[0] =
781 (((tsens_base1_data + tsens0_point2) << 2) |
782 TSENS_BIT_APPEND);
783 calib_tsens_point2_data[1] =
784 (((tsens_base1_data + tsens1_point2) << 2) |
785 TSENS_BIT_APPEND);
786 }
787
788compute_intercept_slope:
789 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
790 int32_t num = 0, den = 0;
791 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
792 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700793 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
794 i, tmdev->sensor[i].calib_data_point1,
795 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700796 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
797 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
798 temp_120_degc - temp_30_degc (x2 - x1) */
799 num = tmdev->sensor[i].calib_data_point2 -
800 tmdev->sensor[i].calib_data_point1;
801 num *= tmdev->tsens_factor;
802 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
803 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
804 }
805 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
806 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
807 tmdev->sensor[i].slope_mul_tsens_factor);
808 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
809 tmdev->prev_reading_avail = false;
810 }
811
812 return 0;
813}
814
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800815static int tsens_calib_8x26_sensors(void)
816{
817 int i, tsens_base0_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
818 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
819 int tsens5_point1 = 0, tsens6_point1 = 0, tsens6_point2 = 0;
820 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
821 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
822 int tsens_base1_data = 0, tsens_calibration_mode = 0;
823 uint32_t calib_data[6];
824 uint32_t calib_tsens_point1_data[7], calib_tsens_point2_data[7];
825
826 if (tmdev->calibration_less_mode)
827 goto calibration_less_mode;
828
829 for (i = 0; i < TSENS_8X26_MAIN_CALIB_ADDR_RANGE; i++)
830 calib_data[i] = readl_relaxed(
831 (TSENS_EEPROM_8X26_1(tmdev->tsens_calib_addr))
832 + (i * TSENS_SN_ADDR_OFFSET));
833 calib_data[4] = readl_relaxed(
834 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)));
835 calib_data[5] = readl_relaxed(
836 (TSENS_EEPROM_8X26_2(tmdev->tsens_calib_addr)) + 0x8);
837
Siddartha Mohanadoss2114b2d2013-03-07 17:43:00 -0800838 tsens_calibration_mode = (calib_data[5] & TSENS_8X26_TSENS_CAL_SEL)
839 >> TSENS_8X26_CAL_SEL_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700840 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800841
842 if ((tsens_calibration_mode == TSENS_TWO_POINT_CALIB) ||
843 (tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2)) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800844 tsens_base0_data = (calib_data[0] & TSENS_8X26_BASE0_MASK)
845 >> TSENS_8X26_BASE0_SHIFT;
846 tsens0_point1 = (calib_data[0] & TSENS0_8X26_POINT1_MASK) >>
847 TSENS0_8X26_POINT1_SHIFT;
848 tsens1_point1 = calib_data[1] & TSENS1_8X26_POINT1_MASK;
849 tsens2_point1 = (calib_data[1] & TSENS2_8X26_POINT1_MASK) >>
850 TSENS2_8X26_POINT1_SHIFT;
851 tsens3_point1 = (calib_data[1] & TSENS3_8X26_POINT1_MASK) >>
852 TSENS3_8X26_POINT1_SHIFT;
853 tsens4_point1 = (calib_data[1] & TSENS4_8X26_POINT1_MASK) >>
854 TSENS4_8X26_POINT1_SHIFT;
855 tsens5_point1 = (calib_data[1] & TSENS5_8X26_POINT1_MASK) >>
856 TSENS5_8X26_POINT1_SHIFT;
857 tsens6_point1 = (calib_data[2] & TSENS6_8X26_POINT1_MASK) >>
858 TSENS6_8X26_POINT1_SHIFT;
859 } else
860 goto calibration_less_mode;
861
862 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800863 tsens_base1_data = (calib_data[3] & TSENS_8X26_BASE1_MASK);
864 tsens0_point2 = (calib_data[3] & TSENS0_8X26_POINT2_MASK) >>
865 TSENS0_8X26_POINT2_SHIFT;
866 tsens1_point2 = (calib_data[3] & TSENS1_8X26_POINT2_MASK) >>
867 TSENS1_8X26_POINT2_SHIFT;
868 tsens2_point2 = (calib_data[3] & TSENS2_8X26_POINT2_MASK) >>
869 TSENS2_8X26_POINT2_SHIFT;
870 tsens3_point2 = (calib_data[3] & TSENS3_8X26_POINT2_MASK) >>
871 TSENS3_8X26_POINT2_SHIFT;
872 tsens4_point2 = (calib_data[4] & TSENS4_8X26_POINT2_MASK) >>
873 TSENS4_8X26_POINT2_SHIFT;
874 tsens5_point2 = (calib_data[4] & TSENS5_8X26_POINT2_MASK) >>
875 TSENS5_8X26_POINT2_SHIFT;
876 tsens6_point2 = (calib_data[5] & TSENS6_8X26_POINT2_MASK) >>
877 TSENS6_8X26_POINT2_SHIFT;
878 }
879
880 if (tsens_calibration_mode == 0) {
881calibration_less_mode:
882 pr_debug("TSENS is calibrationless mode\n");
883 for (i = 0; i < tmdev->tsens_num_sensor; i++)
884 calib_tsens_point2_data[i] = 780;
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -0700885 calib_tsens_point1_data[0] = 595;
886 calib_tsens_point1_data[1] = 625;
887 calib_tsens_point1_data[2] = 553;
888 calib_tsens_point1_data[3] = 578;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800889 calib_tsens_point1_data[4] = 505;
890 calib_tsens_point1_data[5] = 509;
891 calib_tsens_point1_data[6] = 507;
892 goto compute_intercept_slope;
893 }
894
895 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
896 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800897 calib_tsens_point1_data[0] =
898 ((((tsens_base0_data) + tsens0_point1) << 2) |
899 TSENS_BIT_APPEND);
900 calib_tsens_point1_data[1] =
901 ((((tsens_base0_data) + tsens1_point1) << 2) |
902 TSENS_BIT_APPEND);
903 calib_tsens_point1_data[2] =
904 ((((tsens_base0_data) + tsens2_point1) << 2) |
905 TSENS_BIT_APPEND);
906 calib_tsens_point1_data[3] =
907 ((((tsens_base0_data) + tsens3_point1) << 2) |
908 TSENS_BIT_APPEND);
909 calib_tsens_point1_data[4] =
910 ((((tsens_base0_data) + tsens4_point1) << 2) |
911 TSENS_BIT_APPEND);
912 calib_tsens_point1_data[5] =
913 ((((tsens_base0_data) + tsens5_point1) << 2) |
914 TSENS_BIT_APPEND);
915 calib_tsens_point1_data[6] =
916 ((((tsens_base0_data) + tsens6_point1) << 2) |
917 TSENS_BIT_APPEND);
918 }
919
920 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
921 pr_debug("two point calibration calculation\n");
922 calib_tsens_point2_data[0] =
923 (((tsens_base1_data + tsens0_point2) << 2) |
924 TSENS_BIT_APPEND);
925 calib_tsens_point2_data[1] =
926 (((tsens_base1_data + tsens1_point2) << 2) |
927 TSENS_BIT_APPEND);
928 calib_tsens_point2_data[2] =
929 (((tsens_base1_data + tsens2_point2) << 2) |
930 TSENS_BIT_APPEND);
931 calib_tsens_point2_data[3] =
932 (((tsens_base1_data + tsens3_point2) << 2) |
933 TSENS_BIT_APPEND);
934 calib_tsens_point2_data[4] =
935 (((tsens_base1_data + tsens4_point2) << 2) |
936 TSENS_BIT_APPEND);
937 calib_tsens_point2_data[5] =
938 (((tsens_base1_data + tsens5_point2) << 2) |
939 TSENS_BIT_APPEND);
940 calib_tsens_point2_data[6] =
941 (((tsens_base1_data + tsens6_point2) << 2) |
942 TSENS_BIT_APPEND);
943 }
944
945compute_intercept_slope:
946 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
947 int32_t num = 0, den = 0;
948 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
949 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700950 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
951 i, tmdev->sensor[i].calib_data_point1,
952 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -0800953 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
954 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
955 temp_120_degc - temp_30_degc (x2 - x1) */
956 num = tmdev->sensor[i].calib_data_point2 -
957 tmdev->sensor[i].calib_data_point1;
958 num *= tmdev->tsens_factor;
959 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
960 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
961 }
962 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
963 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
964 tmdev->sensor[i].slope_mul_tsens_factor);
965 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
966 tmdev->prev_reading_avail = false;
967 }
968
969 return 0;
970}
971
972static int tsens_calib_8974_sensors(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700973{
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -0700974 int i, tsens_base1_data = 0, tsens0_point1 = 0, tsens1_point1 = 0;
975 int tsens2_point1 = 0, tsens3_point1 = 0, tsens4_point1 = 0;
976 int tsens5_point1 = 0, tsens6_point1 = 0, tsens7_point1 = 0;
977 int tsens8_point1 = 0, tsens9_point1 = 0, tsens10_point1 = 0;
978 int tsens0_point2 = 0, tsens1_point2 = 0, tsens2_point2 = 0;
979 int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
980 int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
981 int tsens9_point2 = 0, tsens10_point2 = 0;
Siddartha Mohanadoss59d36792012-08-15 23:17:39 -0700982 int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700983 uint32_t calib_data[6], calib_redun_sel, calib_data_backup[4];
Siddartha Mohanadossce288362012-10-25 20:02:47 -0700984 uint32_t calib_tsens_point1_data[11], calib_tsens_point2_data[11];
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700985
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -0700986 if (tmdev->calibration_less_mode)
987 goto calibration_less_mode;
988
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700989 calib_redun_sel = readl_relaxed(
990 TSENS_EEPROM_REDUNDANCY_SEL(tmdev->tsens_calib_addr));
991 calib_redun_sel = calib_redun_sel & TSENS_QFPROM_BACKUP_REDUN_SEL;
992 calib_redun_sel >>= TSENS_QFPROM_BACKUP_REDUN_SHIFT;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700993 pr_debug("calib_redun_sel:%x\n", calib_redun_sel);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700994
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700995 for (i = 0; i < TSENS_MAIN_CALIB_ADDR_RANGE; i++) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -0700996 calib_data[i] = readl_relaxed(
997 (TSENS_EEPROM(tmdev->tsens_calib_addr))
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -0700998 + (i * TSENS_SN_ADDR_OFFSET));
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -0700999 pr_debug("calib raw data row%d:0x%x\n", i, calib_data[i]);
1000 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001001
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001002 if (calib_redun_sel == TSENS_QFPROM_BACKUP_SEL) {
1003 tsens_calibration_mode = (calib_data[4] & TSENS_CAL_SEL_0_1)
1004 >> TSENS_CAL_SEL_SHIFT;
1005 temp = (calib_data[5] & TSENS_CAL_SEL_2)
1006 >> TSENS_CAL_SEL_SHIFT_2;
1007 tsens_calibration_mode |= temp;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001008 pr_debug("backup calib mode:%x\n", calib_redun_sel);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001009
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001010 for (i = 0; i < TSENS_BACKUP_CALIB_ADDR_RANGE; i++)
1011 calib_data_backup[i] = readl_relaxed(
1012 (TSENS_EEPROM_BACKUP_REGION(
1013 tmdev->tsens_calib_addr))
1014 + (i * TSENS_SN_ADDR_OFFSET));
1015
1016 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB)
1017 || (tsens_calibration_mode ==
1018 TSENS_TWO_POINT_CALIB) ||
1019 (tsens_calibration_mode ==
1020 TSENS_ONE_POINT_CALIB_OPTION_2)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001021 tsens_base1_data = (calib_data_backup[0] &
1022 TSENS_BASE1_MASK);
1023 tsens0_point1 = (calib_data_backup[0] &
1024 TSENS0_POINT1_MASK) >>
1025 TSENS0_POINT1_SHIFT;
1026 tsens1_point1 = (calib_data_backup[0] &
1027 TSENS1_POINT1_MASK) >> TSENS1_POINT1_SHIFT;
1028 tsens2_point1 = (calib_data_backup[0] &
1029 TSENS2_POINT1_MASK) >> TSENS2_POINT1_SHIFT;
1030 tsens3_point1 = (calib_data_backup[0] &
1031 TSENS3_POINT1_MASK) >> TSENS3_POINT1_SHIFT;
1032 tsens4_point1 = (calib_data_backup[1] &
1033 TSENS4_POINT1_MASK);
1034 tsens5_point1 = (calib_data_backup[1] &
1035 TSENS5_POINT1_MASK) >> TSENS5_POINT1_SHIFT;
1036 tsens6_point1 = (calib_data_backup[1] &
1037 TSENS6_POINT1_MASK) >> TSENS6_POINT1_SHIFT;
1038 tsens7_point1 = (calib_data_backup[1] &
1039 TSENS7_POINT1_MASK) >> TSENS7_POINT1_SHIFT;
1040 tsens8_point1 = (calib_data_backup[2] &
1041 TSENS8_POINT1_MASK_BACKUP) >>
1042 TSENS8_POINT1_SHIFT;
1043 tsens9_point1 = (calib_data_backup[2] &
1044 TSENS9_POINT1_MASK_BACKUP) >>
1045 TSENS9_POINT1_BACKUP_SHIFT;
1046 tsens10_point1 = (calib_data_backup[2] &
1047 TSENS10_POINT1_MASK_BACKUP) >>
1048 TSENS10_POINT1_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001049 } else
1050 goto calibration_less_mode;
1051
1052 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001053 tsens_base2_data = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001054 TSENS_BASE2_BACKUP_MASK) >>
1055 TSENS_POINT2_BASE_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001056 tsens0_point2 = (calib_data_backup[2] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001057 TSENS0_POINT2_BACKUP_MASK) >>
1058 TSENS0_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001059 tsens1_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001060 TSENS1_POINT2_BACKUP_MASK);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001061 tsens2_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001062 TSENS2_POINT2_BACKUP_MASK) >>
1063 TSENS2_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001064 tsens3_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001065 TSENS3_POINT2_BACKUP_MASK) >>
1066 TSENS3_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001067 tsens4_point2 = (calib_data_backup[3] &
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001068 TSENS4_POINT2_BACKUP_MASK) >>
1069 TSENS4_POINT2_BACKUP_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001070 tsens5_point2 = (calib_data[4] &
1071 TSENS5_POINT2_BACKUP_MASK) >>
1072 TSENS5_POINT2_BACKUP_SHIFT;
1073 tsens6_point2 = (calib_data[5] &
1074 TSENS6_POINT2_BACKUP_MASK);
1075 tsens7_point2 = (calib_data[5] &
1076 TSENS7_POINT2_BACKUP_MASK) >>
1077 TSENS7_POINT2_BACKUP_SHIFT;
1078 tsens8_point2 = (calib_data[5] &
1079 TSENS8_POINT2_BACKUP_MASK) >>
1080 TSENS8_POINT2_BACKUP_SHIFT;
1081 tsens9_point2 = (calib_data[5] &
1082 TSENS9_POINT2_BACKUP_MASK) >>
1083 TSENS9_POINT2_BACKUP_SHIFT;
1084 tsens10_point2 = (calib_data[5] &
1085 TSENS10_POINT2_BACKUP_MASK)
1086 >> TSENS10_POINT2_BACKUP_SHIFT;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001087 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001088 } else {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001089 tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
1090 >> TSENS_CAL_SEL_SHIFT;
1091 temp = (calib_data[3] & TSENS_CAL_SEL_2)
1092 >> TSENS_CAL_SEL_SHIFT_2;
1093 tsens_calibration_mode |= temp;
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001094 pr_debug("calib mode scheme:%x\n", tsens_calibration_mode);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001095 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB) ||
1096 (tsens_calibration_mode ==
1097 TSENS_ONE_POINT_CALIB_OPTION_2) ||
1098 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001099 tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
1100 tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
1101 TSENS0_POINT1_SHIFT;
1102 tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
1103 TSENS1_POINT1_SHIFT;
1104 tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
1105 TSENS2_POINT1_SHIFT;
1106 tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
1107 TSENS3_POINT1_SHIFT;
1108 tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
1109 tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
1110 TSENS5_POINT1_SHIFT;
1111 tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
1112 TSENS6_POINT1_SHIFT;
1113 tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
1114 TSENS7_POINT1_SHIFT;
1115 tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
1116 TSENS8_POINT1_SHIFT;
1117 tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
1118 tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK)
1119 >> TSENS10_POINT1_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001120 } else
1121 goto calibration_less_mode;
1122
1123 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001124 tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
1125 TSENS_POINT2_BASE_SHIFT;
1126 tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
1127 TSENS0_POINT2_SHIFT;
1128 tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
1129 TSENS1_POINT2_SHIFT;
1130 tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
1131 tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
1132 TSENS3_POINT2_SHIFT;
1133 tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
1134 TSENS4_POINT2_SHIFT;
1135 tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
1136 TSENS5_POINT2_SHIFT;
1137 tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
1138 TSENS6_POINT2_SHIFT;
1139 tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
1140 tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
1141 TSENS8_POINT2_SHIFT;
1142 tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
1143 TSENS9_POINT2_SHIFT;
1144 tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK)
1145 >> TSENS10_POINT2_SHIFT;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001146 }
1147
1148 if (tsens_calibration_mode == 0) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001149calibration_less_mode:
1150 pr_debug("TSENS is calibrationless mode\n");
1151 for (i = 0; i < tmdev->tsens_num_sensor; i++)
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001152 calib_tsens_point2_data[i] = 780;
1153 calib_tsens_point1_data[0] = 502;
1154 calib_tsens_point1_data[1] = 509;
1155 calib_tsens_point1_data[2] = 503;
1156 calib_tsens_point1_data[3] = 509;
1157 calib_tsens_point1_data[4] = 505;
1158 calib_tsens_point1_data[5] = 509;
1159 calib_tsens_point1_data[6] = 507;
1160 calib_tsens_point1_data[7] = 510;
1161 calib_tsens_point1_data[8] = 508;
1162 calib_tsens_point1_data[9] = 509;
1163 calib_tsens_point1_data[10] = 508;
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001164 goto compute_intercept_slope;
1165 }
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001166 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001167
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001168 if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001169 calib_tsens_point1_data[0] =
1170 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1171 + tsens0_point1;
1172 calib_tsens_point1_data[1] =
1173 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1174 + tsens1_point1;
1175 calib_tsens_point1_data[2] =
1176 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1177 + tsens2_point1;
1178 calib_tsens_point1_data[3] =
1179 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1180 + tsens3_point1;
1181 calib_tsens_point1_data[4] =
1182 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1183 + tsens4_point1;
1184 calib_tsens_point1_data[5] =
1185 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1186 + tsens5_point1;
1187 calib_tsens_point1_data[6] =
1188 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1189 + tsens6_point1;
1190 calib_tsens_point1_data[7] =
1191 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1192 + tsens7_point1;
1193 calib_tsens_point1_data[8] =
1194 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1195 + tsens8_point1;
1196 calib_tsens_point1_data[9] =
1197 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1198 + tsens9_point1;
1199 calib_tsens_point1_data[10] =
1200 (((tsens_base1_data) << 2) | TSENS_BIT_APPEND)
1201 + tsens10_point1;
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001202 }
1203
Siddartha Mohanadoss4d9815a2012-09-09 17:16:05 -07001204 if ((tsens_calibration_mode == TSENS_ONE_POINT_CALIB_OPTION_2) ||
1205 (tsens_calibration_mode == TSENS_TWO_POINT_CALIB)) {
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001206 pr_debug("one point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001207 calib_tsens_point1_data[0] =
1208 ((((tsens_base1_data) + tsens0_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001209 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001210 calib_tsens_point1_data[1] =
1211 ((((tsens_base1_data) + tsens1_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001212 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001213 calib_tsens_point1_data[2] =
1214 ((((tsens_base1_data) + tsens2_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001215 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001216 calib_tsens_point1_data[3] =
1217 ((((tsens_base1_data) + tsens3_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001218 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001219 calib_tsens_point1_data[4] =
1220 ((((tsens_base1_data) + tsens4_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001221 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001222 calib_tsens_point1_data[5] =
1223 ((((tsens_base1_data) + tsens5_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001224 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001225 calib_tsens_point1_data[6] =
1226 ((((tsens_base1_data) + tsens6_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001227 TSENS_BIT_APPEND);
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001228 calib_tsens_point1_data[7] =
1229 ((((tsens_base1_data) + tsens7_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[8] =
1232 ((((tsens_base1_data) + tsens8_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[9] =
1235 ((((tsens_base1_data) + tsens9_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[10] =
1238 ((((tsens_base1_data) + tsens10_point1) << 2) |
Siddartha Mohanadossa6b6b9cb2012-08-21 00:59:16 -07001239 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001240 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001241
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001242 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001243 pr_debug("two point calibration calculation\n");
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001244 calib_tsens_point2_data[0] =
1245 (((tsens_base2_data + tsens0_point2) << 2) |
1246 TSENS_BIT_APPEND);
1247 calib_tsens_point2_data[1] =
1248 (((tsens_base2_data + tsens1_point2) << 2) |
1249 TSENS_BIT_APPEND);
1250 calib_tsens_point2_data[2] =
1251 (((tsens_base2_data + tsens2_point2) << 2) |
1252 TSENS_BIT_APPEND);
1253 calib_tsens_point2_data[3] =
1254 (((tsens_base2_data + tsens3_point2) << 2) |
1255 TSENS_BIT_APPEND);
1256 calib_tsens_point2_data[4] =
1257 (((tsens_base2_data + tsens4_point2) << 2) |
1258 TSENS_BIT_APPEND);
1259 calib_tsens_point2_data[5] =
1260 (((tsens_base2_data + tsens5_point2) << 2) |
1261 TSENS_BIT_APPEND);
1262 calib_tsens_point2_data[6] =
1263 (((tsens_base2_data + tsens6_point2) << 2) |
1264 TSENS_BIT_APPEND);
1265 calib_tsens_point2_data[7] =
1266 (((tsens_base2_data + tsens7_point2) << 2) |
1267 TSENS_BIT_APPEND);
1268 calib_tsens_point2_data[8] =
1269 (((tsens_base2_data + tsens8_point2) << 2) |
1270 TSENS_BIT_APPEND);
1271 calib_tsens_point2_data[9] =
1272 (((tsens_base2_data + tsens9_point2) << 2) |
1273 TSENS_BIT_APPEND);
1274 calib_tsens_point2_data[10] =
1275 (((tsens_base2_data + tsens10_point2) << 2) |
1276 TSENS_BIT_APPEND);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001277 }
1278
1279compute_intercept_slope:
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001280 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1281 int32_t num = 0, den = 0;
Siddartha Mohanadossce288362012-10-25 20:02:47 -07001282 tmdev->sensor[i].calib_data_point2 = calib_tsens_point2_data[i];
1283 tmdev->sensor[i].calib_data_point1 = calib_tsens_point1_data[i];
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001284 pr_debug("sensor:%d - calib_data_point1:0x%x, calib_data_point2:0x%x\n",
1285 i, tmdev->sensor[i].calib_data_point1,
1286 tmdev->sensor[i].calib_data_point2);
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001287 if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001288 /* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
1289 temp_120_degc - temp_30_degc (x2 - x1) */
1290 num = tmdev->sensor[i].calib_data_point2 -
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001291 tmdev->sensor[i].calib_data_point1;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001292 num *= tmdev->tsens_factor;
Siddartha Mohanadossd4dac7a2013-02-01 15:35:40 -08001293 den = TSENS_CAL_DEGC_POINT2 - TSENS_CAL_DEGC_POINT1;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001294 tmdev->sensor[i].slope_mul_tsens_factor = num/den;
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001295 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001296 tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
1297 tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
1298 tmdev->sensor[i].slope_mul_tsens_factor);
Siddartha Mohanadoss36ea2df2013-04-16 10:16:40 -07001299 pr_debug("offset:%d\n", tmdev->sensor[i].offset);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001300 INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
1301 tmdev->prev_reading_avail = false;
1302 }
1303
1304 return 0;
1305}
1306
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001307static int tsens_calib_sensors(void)
1308{
1309 int rc = 0;
1310
1311 if (!tmdev)
1312 return -ENODEV;
1313
1314 if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8974)
1315 rc = tsens_calib_8974_sensors();
1316 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X26)
1317 rc = tsens_calib_8x26_sensors();
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -07001318 else if (tmdev->calib_mode == TSENS_CALIB_FUSE_MAP_8X10)
1319 rc = tsens_calib_8x10_sensors();
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001320 else
1321 rc = -ENODEV;
1322
1323 return rc;
1324}
1325
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001326static int get_device_tree_data(struct platform_device *pdev)
1327{
1328 const struct device_node *of_node = pdev->dev.of_node;
1329 struct resource *res_mem = NULL;
1330 u32 *tsens_slope_data;
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001331 u32 *sensor_id;
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001332 u32 rc = 0, i, tsens_num_sensors, calib_type;
1333 const char *tsens_calib_mode;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001334
1335 rc = of_property_read_u32(of_node,
1336 "qcom,sensors", &tsens_num_sensors);
1337 if (rc) {
1338 dev_err(&pdev->dev, "missing sensor number\n");
1339 return -ENODEV;
1340 }
1341
1342 tsens_slope_data = devm_kzalloc(&pdev->dev,
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001343 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001344 if (!tsens_slope_data) {
1345 dev_err(&pdev->dev, "can not allocate slope data\n");
1346 return -ENOMEM;
1347 }
1348
1349 rc = of_property_read_u32_array(of_node,
Siddartha Mohanadoss205bce62012-07-27 17:17:18 -07001350 "qcom,slope", tsens_slope_data, tsens_num_sensors);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001351 if (rc) {
1352 dev_err(&pdev->dev, "invalid or missing property: tsens-slope\n");
1353 return rc;
1354 };
1355
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001356 tsens_calib_mode = of_get_property(of_node,
1357 "qcom,calib-mode", NULL);
1358 if (!strncmp(tsens_calib_mode, "fuse_map1", 9))
1359 calib_type = TSENS_CALIB_FUSE_MAP_8974;
1360 else if (!strncmp(tsens_calib_mode, "fuse_map2", 9))
1361 calib_type = TSENS_CALIB_FUSE_MAP_8X26;
1362 else if (!strncmp(tsens_calib_mode, "fuse_map3", 9))
1363 calib_type = TSENS_CALIB_FUSE_MAP_8X10;
1364 else {
1365 pr_err("%s: Invalid calibration property\n", __func__);
1366 return -EINVAL;
1367 }
1368
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001369 tmdev = devm_kzalloc(&pdev->dev,
1370 sizeof(struct tsens_tm_device) +
1371 tsens_num_sensors *
1372 sizeof(struct tsens_tm_device_sensor),
1373 GFP_KERNEL);
1374 if (tmdev == NULL) {
1375 pr_err("%s: kzalloc() failed.\n", __func__);
1376 return -ENOMEM;
1377 }
1378
1379 for (i = 0; i < tsens_num_sensors; i++)
1380 tmdev->sensor[i].slope_mul_tsens_factor = tsens_slope_data[i];
1381 tmdev->tsens_factor = TSENS_SLOPE_FACTOR;
1382 tmdev->tsens_num_sensor = tsens_num_sensors;
Siddartha Mohanadoss28ac1ad2012-10-15 12:22:17 -07001383 tmdev->calibration_less_mode = of_property_read_bool(of_node,
1384 "qcom,calibration-less-mode");
Siddartha Mohanadoss3f8cd142013-02-06 17:24:33 -08001385 tmdev->calib_mode = calib_type;
Siddartha Mohanadoss0ca83312013-03-14 11:43:18 -07001386 tmdev->tsens_local_init = of_property_read_bool(of_node,
Siddartha Mohanadoss21c96ed2013-03-26 10:35:42 -07001387 "qcom,tsens-local-init");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001388
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001389 sensor_id = devm_kzalloc(&pdev->dev,
1390 tsens_num_sensors * sizeof(u32), GFP_KERNEL);
1391 if (!sensor_id) {
1392 dev_err(&pdev->dev, "can not allocate sensor id\n");
1393 return -ENOMEM;
1394 }
1395
1396 rc = of_property_read_u32_array(of_node,
1397 "qcom,sensor-id", sensor_id, tsens_num_sensors);
1398 if (rc) {
1399 pr_debug("Default sensor id mapping\n");
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001400 for (i = 0; i < tsens_num_sensors; i++) {
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001401 tmdev->sensor[i].sensor_hw_num = i;
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001402 tmdev->sensor[i].sensor_sw_id = i;
1403 }
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001404 } else {
1405 pr_debug("Use specified sensor id mapping\n");
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001406 for (i = 0; i < tsens_num_sensors; i++) {
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001407 tmdev->sensor[i].sensor_hw_num = sensor_id[i];
Siddartha Mohanadossee00f422013-04-17 11:33:01 -07001408 tmdev->sensor[i].sensor_sw_id = i;
1409 }
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001410 }
1411
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001412 tmdev->tsens_irq = platform_get_irq(pdev, 0);
1413 if (tmdev->tsens_irq < 0) {
1414 pr_err("Invalid get irq\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001415 rc = tmdev->tsens_irq;
1416 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001417 }
1418
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001419 /* TSENS register region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001420 tmdev->res_tsens_mem = platform_get_resource_byname(pdev,
1421 IORESOURCE_MEM, "tsens_physical");
1422 if (!tmdev->res_tsens_mem) {
1423 pr_err("Could not get tsens physical address resource\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001424 rc = -EINVAL;
1425 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001426 }
1427
1428 tmdev->tsens_len = tmdev->res_tsens_mem->end -
1429 tmdev->res_tsens_mem->start + 1;
1430
1431 res_mem = request_mem_region(tmdev->res_tsens_mem->start,
1432 tmdev->tsens_len, tmdev->res_tsens_mem->name);
1433 if (!res_mem) {
1434 pr_err("Request tsens physical memory region failed\n");
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001435 rc = -EINVAL;
1436 goto fail_tmdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001437 }
1438
1439 tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
1440 if (!tmdev->tsens_addr) {
1441 pr_err("Failed to IO map TSENS registers.\n");
1442 rc = -EINVAL;
1443 goto fail_unmap_tsens_region;
1444 }
1445
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001446 /* TSENS calibration region */
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001447 tmdev->res_calib_mem = platform_get_resource_byname(pdev,
1448 IORESOURCE_MEM, "tsens_eeprom_physical");
1449 if (!tmdev->res_calib_mem) {
1450 pr_err("Could not get qfprom physical address resource\n");
1451 rc = -EINVAL;
1452 goto fail_unmap_tsens;
1453 }
1454
1455 tmdev->calib_len = tmdev->res_calib_mem->end -
1456 tmdev->res_calib_mem->start + 1;
1457
1458 res_mem = request_mem_region(tmdev->res_calib_mem->start,
1459 tmdev->calib_len, tmdev->res_calib_mem->name);
1460 if (!res_mem) {
1461 pr_err("Request calibration memory region failed\n");
1462 rc = -EINVAL;
1463 goto fail_unmap_tsens;
1464 }
1465
1466 tmdev->tsens_calib_addr = ioremap(res_mem->start,
1467 tmdev->calib_len);
1468 if (!tmdev->tsens_calib_addr) {
1469 pr_err("Failed to IO map EEPROM registers.\n");
1470 rc = -EINVAL;
1471 goto fail_unmap_calib_region;
1472 }
1473
1474 return 0;
1475
1476fail_unmap_calib_region:
1477 if (tmdev->res_calib_mem)
1478 release_mem_region(tmdev->res_calib_mem->start,
1479 tmdev->calib_len);
1480fail_unmap_tsens:
1481 if (tmdev->tsens_addr)
1482 iounmap(tmdev->tsens_addr);
1483fail_unmap_tsens_region:
1484 if (tmdev->res_tsens_mem)
1485 release_mem_region(tmdev->res_tsens_mem->start,
1486 tmdev->tsens_len);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001487fail_tmdev:
1488 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001489 return rc;
1490}
1491
1492static int __devinit tsens_tm_probe(struct platform_device *pdev)
1493{
1494 int rc;
1495
1496 if (tmdev) {
1497 pr_err("TSENS device already in use\n");
1498 return -EBUSY;
1499 }
1500
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001501 if (pdev->dev.of_node) {
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001502 rc = get_device_tree_data(pdev);
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001503 if (rc) {
1504 pr_err("Error reading TSENS DT\n");
1505 return rc;
1506 }
1507 } else
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001508 return -ENODEV;
1509
1510 tmdev->pdev = pdev;
Matt Wagantall83026d62013-05-22 18:07:04 -07001511 tmdev->tsens_wq = alloc_workqueue("tsens_wq", WQ_HIGHPRI, 0);
1512 if (!tmdev->tsens_wq) {
1513 rc = -ENOMEM;
1514 goto fail;
1515 }
1516
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001517 rc = tsens_calib_sensors();
Michael Bohanb89167e2012-10-04 16:24:23 -07001518 if (rc < 0) {
1519 pr_err("Calibration failed\n");
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001520 goto fail;
Michael Bohanb89167e2012-10-04 16:24:23 -07001521 }
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001522
1523 tsens_hw_init();
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001524
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001525 tmdev->prev_reading_avail = true;
1526
1527 platform_set_drvdata(pdev, tmdev);
1528
1529 return 0;
1530fail:
Matt Wagantall83026d62013-05-22 18:07:04 -07001531 if (tmdev->tsens_wq)
1532 destroy_workqueue(tmdev->tsens_wq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001533 if (tmdev->tsens_calib_addr)
1534 iounmap(tmdev->tsens_calib_addr);
1535 if (tmdev->res_calib_mem)
1536 release_mem_region(tmdev->res_calib_mem->start,
1537 tmdev->calib_len);
1538 if (tmdev->tsens_addr)
1539 iounmap(tmdev->tsens_addr);
1540 if (tmdev->res_tsens_mem)
1541 release_mem_region(tmdev->res_tsens_mem->start,
1542 tmdev->tsens_len);
Michael Bohanb89167e2012-10-04 16:24:23 -07001543 tmdev = NULL;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001544
1545 return rc;
1546}
1547
1548static int __devinit _tsens_register_thermal(void)
1549{
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001550 struct platform_device *pdev;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001551 int rc, i;
1552
1553 if (!tmdev) {
1554 pr_err("%s: TSENS early init not done\n", __func__);
1555 return -ENODEV;
1556 }
1557
Stepan Moskovchenkoda77bde2012-08-06 14:35:09 -07001558 pdev = tmdev->pdev;
1559
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001560 for (i = 0; i < tmdev->tsens_num_sensor; i++) {
1561 char name[18];
Siddartha Mohanadosse071ff12013-04-11 19:37:41 -07001562 snprintf(name, sizeof(name), "tsens_tz_sensor%d",
1563 tmdev->sensor[i].sensor_hw_num);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001564 tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001565 tmdev->sensor[i].tz_dev = thermal_zone_device_register(name,
1566 TSENS_TRIP_NUM, &tmdev->sensor[i],
1567 &tsens_thermal_zone_ops, 0, 0, 0, 0);
1568 if (IS_ERR(tmdev->sensor[i].tz_dev)) {
1569 pr_err("%s: thermal_zone_device_register() failed.\n",
1570 __func__);
1571 rc = -ENODEV;
1572 goto fail;
1573 }
1574 }
Siddartha Mohanadossc7a86072012-08-13 17:12:31 -07001575
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001576 rc = request_irq(tmdev->tsens_irq, tsens_isr,
1577 IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
1578 if (rc < 0) {
1579 pr_err("%s: request_irq FAIL: %d\n", __func__, rc);
1580 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1581 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1582 goto fail;
Siddartha Mohanadossb9be9812013-02-13 11:03:32 -08001583 } else {
1584 enable_irq_wake(tmdev->tsens_irq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001585 }
1586 platform_set_drvdata(pdev, tmdev);
1587
Siddartha Mohanadoss466b4ac2012-08-27 09:10:13 -07001588 INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
1589
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001590 return 0;
1591fail:
1592 if (tmdev->tsens_calib_addr)
1593 iounmap(tmdev->tsens_calib_addr);
1594 if (tmdev->res_calib_mem)
1595 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001596 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001597 if (tmdev->tsens_addr)
1598 iounmap(tmdev->tsens_addr);
1599 if (tmdev->res_tsens_mem)
1600 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001601 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001602 return rc;
1603}
1604
1605static int __devexit tsens_tm_remove(struct platform_device *pdev)
1606{
1607 struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
1608 int i;
1609
1610 for (i = 0; i < tmdev->tsens_num_sensor; i++)
1611 thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
1612 if (tmdev->tsens_calib_addr)
1613 iounmap(tmdev->tsens_calib_addr);
1614 if (tmdev->res_calib_mem)
1615 release_mem_region(tmdev->res_calib_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001616 tmdev->calib_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001617 if (tmdev->tsens_addr)
1618 iounmap(tmdev->tsens_addr);
1619 if (tmdev->res_tsens_mem)
1620 release_mem_region(tmdev->res_tsens_mem->start,
Siddartha Mohanadoss18c1edd2012-09-11 11:49:21 -07001621 tmdev->tsens_len);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001622 free_irq(tmdev->tsens_irq, tmdev);
Matt Wagantall83026d62013-05-22 18:07:04 -07001623 destroy_workqueue(tmdev->tsens_wq);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001624 platform_set_drvdata(pdev, NULL);
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001625
1626 return 0;
1627}
1628
1629static struct of_device_id tsens_match[] = {
1630 { .compatible = "qcom,msm-tsens",
1631 },
1632 {}
1633};
1634
1635static struct platform_driver tsens_tm_driver = {
1636 .probe = tsens_tm_probe,
1637 .remove = tsens_tm_remove,
1638 .driver = {
1639 .name = "msm-tsens",
1640 .owner = THIS_MODULE,
1641 .of_match_table = tsens_match,
1642 },
1643};
1644
Siddartha Mohanadoss4cef5f42013-04-11 13:59:41 -07001645int __init tsens_tm_init_driver(void)
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001646{
1647 return platform_driver_register(&tsens_tm_driver);
1648}
Siddartha Mohanadoss05a6e382012-05-14 15:13:37 -07001649
1650static int __init tsens_thermal_register(void)
1651{
1652 return _tsens_register_thermal();
1653}
1654module_init(tsens_thermal_register);
1655
1656static void __exit _tsens_tm_remove(void)
1657{
1658 platform_driver_unregister(&tsens_tm_driver);
1659}
1660module_exit(_tsens_tm_remove);
1661
1662MODULE_ALIAS("platform:" TSENS_DRIVER_NAME);
1663MODULE_LICENSE("GPL v2");