blob: eb647fa0efc0403c8a500fe656325cdd893ff52f [file] [log] [blame]
Siddartha Mohanadoss58ffe0e2014-02-11 17:40:13 -08001/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08002 *
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 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/of.h>
18#include <linux/err.h>
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/delay.h>
22#include <linux/mutex.h>
23#include <linux/types.h>
24#include <linux/hwmon.h>
25#include <linux/module.h>
26#include <linux/debugfs.h>
27#include <linux/spmi.h>
28#include <linux/of_irq.h>
29#include <linux/wakelock.h>
30#include <linux/interrupt.h>
31#include <linux/completion.h>
32#include <linux/hwmon-sysfs.h>
33#include <linux/qpnp/qpnp-adc.h>
34#include <linux/thermal.h>
35#include <linux/platform_device.h>
36
37/* QPNP VADC TM register definition */
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -070038#define QPNP_REVISION3 0x2
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -070039#define QPNP_PERPH_SUBTYPE 0x5
40#define QPNP_PERPH_TYPE2 0x2
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080041#define QPNP_REVISION_EIGHT_CHANNEL_SUPPORT 2
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080042#define QPNP_STATUS1 0x8
43#define QPNP_STATUS1_OP_MODE 4
44#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
45#define QPNP_STATUS1_REQ_STS BIT(1)
46#define QPNP_STATUS1_EOC BIT(0)
47#define QPNP_STATUS2 0x9
48#define QPNP_STATUS2_CONV_SEQ_STATE 6
49#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
50#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
51#define QPNP_CONV_TIMEOUT_ERR 2
52
53#define QPNP_MODE_CTL 0x40
54#define QPNP_OP_MODE_SHIFT 3
55#define QPNP_VREF_XO_THM_FORCE BIT(2)
56#define QPNP_AMUX_TRIM_EN BIT(1)
57#define QPNP_ADC_TRIM_EN BIT(0)
58#define QPNP_EN_CTL1 0x46
59#define QPNP_ADC_TM_EN BIT(7)
60#define QPNP_ADC_CH_SEL_CTL 0x48
61#define QPNP_ADC_DIG_PARAM 0x50
62#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 3
63#define QPNP_HW_SETTLE_DELAY 0x51
64#define QPNP_CONV_REQ 0x52
65#define QPNP_CONV_REQ_SET BIT(7)
66#define QPNP_CONV_SEQ_CTL 0x54
67#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
68#define QPNP_CONV_SEQ_TRIG_CTL 0x55
69#define QPNP_ADC_TM_MEAS_INTERVAL_CTL 0x57
70#define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT 0x3
71#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2 0x58
72#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT 0x4
73#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK 0xf0
74#define QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK 0xf
75
76#define QPNP_ADC_MEAS_INTERVAL_OP_CTL 0x59
77#define QPNP_ADC_MEAS_INTERVAL_OP BIT(7)
78
79#define QPNP_FAST_AVG_CTL 0x5a
80#define QPNP_FAST_AVG_EN 0x5b
81
82#define QPNP_M0_LOW_THR_LSB 0x5c
83#define QPNP_M0_LOW_THR_MSB 0x5d
84#define QPNP_M0_HIGH_THR_LSB 0x5e
85#define QPNP_M0_HIGH_THR_MSB 0x5f
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080086#define QPNP_M1_ADC_CH_SEL_CTL 0x68
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080087#define QPNP_M1_LOW_THR_LSB 0x69
88#define QPNP_M1_LOW_THR_MSB 0x6a
89#define QPNP_M1_HIGH_THR_LSB 0x6b
90#define QPNP_M1_HIGH_THR_MSB 0x6c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080091#define QPNP_M2_ADC_CH_SEL_CTL 0x70
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080092#define QPNP_M2_LOW_THR_LSB 0x71
93#define QPNP_M2_LOW_THR_MSB 0x72
Xiaozhe Shi2a503db2013-05-10 17:27:52 -070094#define QPNP_M2_HIGH_THR_LSB 0x73
95#define QPNP_M2_HIGH_THR_MSB 0x74
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080096#define QPNP_M3_ADC_CH_SEL_CTL 0x78
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080097#define QPNP_M3_LOW_THR_LSB 0x79
98#define QPNP_M3_LOW_THR_MSB 0x7a
99#define QPNP_M3_HIGH_THR_LSB 0x7b
100#define QPNP_M3_HIGH_THR_MSB 0x7c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800101#define QPNP_M4_ADC_CH_SEL_CTL 0x80
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800102#define QPNP_M4_LOW_THR_LSB 0x81
103#define QPNP_M4_LOW_THR_MSB 0x82
104#define QPNP_M4_HIGH_THR_LSB 0x83
105#define QPNP_M4_HIGH_THR_MSB 0x84
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800106#define QPNP_M5_ADC_CH_SEL_CTL 0x88
107#define QPNP_M5_LOW_THR_LSB 0x89
108#define QPNP_M5_LOW_THR_MSB 0x8a
109#define QPNP_M5_HIGH_THR_LSB 0x8b
110#define QPNP_M5_HIGH_THR_MSB 0x8c
111#define QPNP_M6_ADC_CH_SEL_CTL 0x90
112#define QPNP_M6_LOW_THR_LSB 0x91
113#define QPNP_M6_LOW_THR_MSB 0x92
114#define QPNP_M6_HIGH_THR_LSB 0x93
115#define QPNP_M6_HIGH_THR_MSB 0x94
116#define QPNP_M7_ADC_CH_SEL_CTL 0x98
117#define QPNP_M7_LOW_THR_LSB 0x99
118#define QPNP_M7_LOW_THR_MSB 0x9a
119#define QPNP_M7_HIGH_THR_LSB 0x9b
120#define QPNP_M7_HIGH_THR_MSB 0x9c
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800121
122#define QPNP_ADC_TM_MULTI_MEAS_EN 0x41
123#define QPNP_ADC_TM_MULTI_MEAS_EN_M0 BIT(0)
124#define QPNP_ADC_TM_MULTI_MEAS_EN_M1 BIT(1)
125#define QPNP_ADC_TM_MULTI_MEAS_EN_M2 BIT(2)
126#define QPNP_ADC_TM_MULTI_MEAS_EN_M3 BIT(3)
127#define QPNP_ADC_TM_MULTI_MEAS_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800128#define QPNP_ADC_TM_MULTI_MEAS_EN_M5 BIT(5)
129#define QPNP_ADC_TM_MULTI_MEAS_EN_M6 BIT(6)
130#define QPNP_ADC_TM_MULTI_MEAS_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800131#define QPNP_ADC_TM_LOW_THR_INT_EN 0x42
132#define QPNP_ADC_TM_LOW_THR_INT_EN_M0 BIT(0)
133#define QPNP_ADC_TM_LOW_THR_INT_EN_M1 BIT(1)
134#define QPNP_ADC_TM_LOW_THR_INT_EN_M2 BIT(2)
135#define QPNP_ADC_TM_LOW_THR_INT_EN_M3 BIT(3)
136#define QPNP_ADC_TM_LOW_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800137#define QPNP_ADC_TM_LOW_THR_INT_EN_M5 BIT(5)
138#define QPNP_ADC_TM_LOW_THR_INT_EN_M6 BIT(6)
139#define QPNP_ADC_TM_LOW_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800140#define QPNP_ADC_TM_HIGH_THR_INT_EN 0x43
141#define QPNP_ADC_TM_HIGH_THR_INT_EN_M0 BIT(0)
142#define QPNP_ADC_TM_HIGH_THR_INT_EN_M1 BIT(1)
143#define QPNP_ADC_TM_HIGH_THR_INT_EN_M2 BIT(2)
144#define QPNP_ADC_TM_HIGH_THR_INT_EN_M3 BIT(3)
145#define QPNP_ADC_TM_HIGH_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800146#define QPNP_ADC_TM_HIGH_THR_INT_EN_M5 BIT(5)
147#define QPNP_ADC_TM_HIGH_THR_INT_EN_M6 BIT(6)
148#define QPNP_ADC_TM_HIGH_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800149
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800150#define QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL 0x59
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800151#define QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL 0x6d
152#define QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL 0x75
153#define QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL 0x7d
154#define QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL 0x85
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800155#define QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL 0x8d
156#define QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL 0x95
157#define QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL 0x9d
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800158#define QPNP_ADC_TM_STATUS1 0x8
159#define QPNP_ADC_TM_STATUS_LOW 0xa
160#define QPNP_ADC_TM_STATUS_HIGH 0xb
161
162#define QPNP_ADC_TM_M0_LOW_THR 0x5d5c
163#define QPNP_ADC_TM_M0_HIGH_THR 0x5f5e
164#define QPNP_ADC_TM_MEAS_INTERVAL 0x0
165
166#define QPNP_ADC_TM_THR_LSB_MASK(val) (val & 0xff)
167#define QPNP_ADC_TM_THR_MSB_MASK(val) ((val & 0xff00) >> 8)
168
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800169#define QPNP_MIN_TIME 2000
170#define QPNP_MAX_TIME 2100
171
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700172struct qpnp_adc_thr_client_info {
173 struct list_head list;
174 struct qpnp_adc_tm_btm_param *btm_param;
175 int32_t low_thr_requested;
176 int32_t high_thr_requested;
177 enum qpnp_state_request state_requested;
178 enum qpnp_state_request state_req_copy;
179 bool low_thr_set;
180 bool high_thr_set;
181 bool notify_low_thr;
182 bool notify_high_thr;
183};
184
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800185struct qpnp_adc_tm_sensor {
186 struct thermal_zone_device *tz_dev;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700187 struct qpnp_adc_tm_chip *chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800188 enum thermal_device_mode mode;
189 uint32_t sensor_num;
190 enum qpnp_adc_meas_timer_select timer_select;
191 uint32_t meas_interval;
192 uint32_t low_thr;
193 uint32_t high_thr;
194 uint32_t btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800195 uint32_t vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800196 struct work_struct work;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800197 bool thermal_node;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700198 uint32_t scale_type;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700199 struct list_head thr_list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800200};
201
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700202struct qpnp_adc_tm_chip {
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700203 struct device *dev;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800204 struct qpnp_adc_drv *adc;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700205 struct list_head list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800206 bool adc_tm_initialized;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800207 int max_channels_available;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700208 struct qpnp_vadc_chip *vadc_dev;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700209 struct work_struct trigger_high_thr_work;
210 struct work_struct trigger_low_thr_work;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800211 struct qpnp_adc_tm_sensor sensor[0];
212};
213
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700214LIST_HEAD(qpnp_adc_tm_device_list);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800215
216struct qpnp_adc_tm_trip_reg_type {
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700217 enum qpnp_adc_tm_channel_select btm_amux_chan;
218 uint16_t low_thr_lsb_addr;
219 uint16_t low_thr_msb_addr;
220 uint16_t high_thr_lsb_addr;
221 uint16_t high_thr_msb_addr;
222 u8 multi_meas_en;
223 u8 low_thr_int_chan_en;
224 u8 high_thr_int_chan_en;
225 u8 meas_interval_ctl;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800226};
227
228static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700229 [QPNP_ADC_TM_CHAN0] = {QPNP_ADC_TM_M0_ADC_CH_SEL_CTL,
230 QPNP_M0_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800231 QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
232 QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800233 QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
234 QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700235 [QPNP_ADC_TM_CHAN1] = {QPNP_ADC_TM_M1_ADC_CH_SEL_CTL,
236 QPNP_M1_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800237 QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
238 QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800239 QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
240 QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700241 [QPNP_ADC_TM_CHAN2] = {QPNP_ADC_TM_M2_ADC_CH_SEL_CTL,
242 QPNP_M2_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800243 QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
244 QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800245 QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
246 QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700247 [QPNP_ADC_TM_CHAN3] = {QPNP_ADC_TM_M3_ADC_CH_SEL_CTL,
248 QPNP_M3_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800249 QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
250 QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800251 QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
252 QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700253 [QPNP_ADC_TM_CHAN4] = {QPNP_ADC_TM_M4_ADC_CH_SEL_CTL,
254 QPNP_M4_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800255 QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
256 QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800257 QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
258 QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700259 [QPNP_ADC_TM_CHAN5] = {QPNP_ADC_TM_M5_ADC_CH_SEL_CTL,
260 QPNP_M5_LOW_THR_LSB,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800261 QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
262 QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
263 QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
264 QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700265 [QPNP_ADC_TM_CHAN6] = {QPNP_ADC_TM_M6_ADC_CH_SEL_CTL,
266 QPNP_M6_LOW_THR_LSB,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800267 QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
268 QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
269 QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
270 QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700271 [QPNP_ADC_TM_CHAN7] = {QPNP_ADC_TM_M7_ADC_CH_SEL_CTL,
272 QPNP_M7_LOW_THR_LSB,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800273 QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
274 QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
275 QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
276 QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL},
277};
278
279static struct qpnp_adc_tm_reverse_scale_fn adc_tm_rscale_fn[] = {
280 [SCALE_R_VBATT] = {qpnp_adc_vbatt_rscaler},
281 [SCALE_RBATT_THERM] = {qpnp_adc_btm_scaler},
282 [SCALE_R_USB_ID] = {qpnp_adc_usb_scaler},
283 [SCALE_RPMIC_THERM] = {qpnp_adc_scale_millidegc_pmic_voltage_thr},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800284};
285
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700286static int32_t qpnp_adc_tm_read_reg(struct qpnp_adc_tm_chip *chip,
287 int16_t reg, u8 *data)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800288{
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800289 int rc = 0;
290
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700291 rc = spmi_ext_register_readl(chip->adc->spmi->ctrl,
292 chip->adc->slave, (chip->adc->offset + reg), data, 1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800293 if (rc < 0)
294 pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
295
296 return rc;
297}
298
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700299static int32_t qpnp_adc_tm_write_reg(struct qpnp_adc_tm_chip *chip,
300 int16_t reg, u8 data)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800301{
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800302 int rc = 0;
303 u8 *buf;
304
305 buf = &data;
306
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700307 rc = spmi_ext_register_writel(chip->adc->spmi->ctrl,
308 chip->adc->slave, (chip->adc->offset + reg), buf, 1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800309 if (rc < 0)
310 pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
311
312 return rc;
313}
314
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700315static int32_t qpnp_adc_tm_enable(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800316{
317 int rc = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800318 u8 data = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800319
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800320 data = QPNP_ADC_TM_EN;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700321 rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800322 if (rc < 0)
323 pr_err("adc-tm enable failed\n");
324
325 return rc;
326}
327
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700328static int32_t qpnp_adc_tm_disable(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800329{
330 u8 data = 0;
331 int rc = 0;
332
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700333 rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800334 if (rc < 0)
335 pr_err("adc-tm disable failed\n");
336
337 return rc;
338}
339
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700340static int qpnp_adc_tm_is_valid(struct qpnp_adc_tm_chip *chip)
341{
342 struct qpnp_adc_tm_chip *adc_tm_chip = NULL;
343
344 list_for_each_entry(adc_tm_chip, &qpnp_adc_tm_device_list, list)
345 if (chip == adc_tm_chip)
346 return 0;
347
348 return -EINVAL;
349}
350
351static int32_t qpnp_adc_tm_enable_if_channel_meas(
352 struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800353{
354 u8 adc_tm_meas_en = 0;
355 int rc = 0;
356
357 /* Check if a measurement request is still required */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700358 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800359 &adc_tm_meas_en);
360 if (rc) {
361 pr_err("adc-tm-tm read status high failed with %d\n", rc);
362 return rc;
363 }
364
365 /* Enable only if there are pending measurement requests */
366 if (adc_tm_meas_en) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700367 qpnp_adc_tm_enable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800368
369 /* Request conversion */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700370 rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ,
371 QPNP_CONV_REQ_SET);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800372 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800373 pr_err("adc-tm request conversion failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800374 return rc;
375 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800376 }
377
378 return rc;
379}
380
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700381static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800382{
383 u8 status1;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800384 int rc, count = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800385
386 /* The VADC_TM bank needs to be disabled for new conversion request */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700387 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800388 if (rc) {
389 pr_err("adc-tm read status1 failed\n");
390 return rc;
391 }
392
393 /* Disable the bank if a conversion is occuring */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800394 while ((status1 & QPNP_STATUS1_REQ_STS) && (count < 5)) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700395 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800396 if (rc < 0)
397 pr_err("adc-tm disable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800398 /* Wait time is based on the optimum sampling rate
399 * and adding enough time buffer to account for ADC conversions
400 * occuring on different peripheral banks */
401 usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
402 count++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800403 }
404
405 return rc;
406}
407
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700408static int32_t qpnp_adc_tm_get_btm_idx(uint32_t btm_chan,
409 uint32_t *btm_chan_idx)
410{
411 int rc = 0, i;
412 bool chan_found = false;
413
414 for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
415 if (adc_tm_data[i].btm_amux_chan == btm_chan) {
416 *btm_chan_idx = i;
417 chan_found = true;
418 }
419 }
420
421 if (!chan_found)
422 return -EINVAL;
423
424 return rc;
425}
426
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700427static int32_t qpnp_adc_tm_check_revision(struct qpnp_adc_tm_chip *chip,
428 uint32_t btm_chan_num)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800429{
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -0700430 u8 rev, perph_subtype;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800431 int rc = 0;
432
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700433 rc = qpnp_adc_tm_read_reg(chip, QPNP_REVISION3, &rev);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800434 if (rc) {
435 pr_err("adc-tm revision read failed\n");
436 return rc;
437 }
438
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700439 rc = qpnp_adc_tm_read_reg(chip, QPNP_PERPH_SUBTYPE, &perph_subtype);
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -0700440 if (rc) {
441 pr_err("adc-tm perph_subtype read failed\n");
442 return rc;
443 }
444
445 if (perph_subtype == QPNP_PERPH_TYPE2) {
446 if ((rev < QPNP_REVISION_EIGHT_CHANNEL_SUPPORT) &&
447 (btm_chan_num > QPNP_ADC_TM_M4_ADC_CH_SEL_CTL)) {
448 pr_debug("Version does not support more than 5 channels\n");
449 return -EINVAL;
450 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800451 }
452
453 return rc;
454}
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700455static int32_t qpnp_adc_tm_mode_select(struct qpnp_adc_tm_chip *chip,
456 u8 mode_ctl)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800457{
458 int rc;
459
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800460 mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
461
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800462 /* VADC_BTM current sets mode to recurring measurements */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700463 rc = qpnp_adc_tm_write_reg(chip, QPNP_MODE_CTL, mode_ctl);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800464 if (rc < 0)
465 pr_err("adc-tm write mode selection err\n");
466
467 return rc;
468}
469
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700470static int32_t qpnp_adc_tm_timer_interval_select(
471 struct qpnp_adc_tm_chip *chip, uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800472 struct qpnp_vadc_chan_properties *chan_prop)
473{
Siddartha Mohanadoss58ffe0e2014-02-11 17:40:13 -0800474 int rc, chan_idx = 0, i = 0;
475 bool chan_found = false;
476 u8 meas_interval_timer2 = 0, timer_interval_store = 0;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700477 uint32_t btm_chan_idx = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800478
Siddartha Mohanadoss58ffe0e2014-02-11 17:40:13 -0800479 while (i < chip->max_channels_available) {
480 if (chip->sensor[i].btm_channel_num == btm_chan) {
481 chan_idx = i;
482 chan_found = true;
483 i++;
484 } else
485 i++;
486 }
487
488 if (!chan_found) {
489 pr_err("Channel not found\n");
490 return -EINVAL;
491 }
492
493 switch (chip->sensor[chan_idx].timer_select) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800494 case ADC_MEAS_TIMER_SELECT1:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700495 rc = qpnp_adc_tm_write_reg(chip,
496 QPNP_ADC_TM_MEAS_INTERVAL_CTL,
Siddartha Mohanadoss58ffe0e2014-02-11 17:40:13 -0800497 chip->sensor[chan_idx].meas_interval);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800498 if (rc < 0) {
499 pr_err("timer1 configure failed\n");
500 return rc;
501 }
502 break;
503 case ADC_MEAS_TIMER_SELECT2:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800504 /* Thermal channels uses timer2, default to 1 second */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700505 rc = qpnp_adc_tm_read_reg(chip,
506 QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800507 &meas_interval_timer2);
508 if (rc < 0) {
509 pr_err("timer2 configure read failed\n");
510 return rc;
511 }
Siddartha Mohanadoss58ffe0e2014-02-11 17:40:13 -0800512 timer_interval_store = chip->sensor[chan_idx].meas_interval;
513 timer_interval_store <<= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT;
514 timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK;
515 meas_interval_timer2 |= timer_interval_store;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700516 rc = qpnp_adc_tm_write_reg(chip,
517 QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800518 meas_interval_timer2);
519 if (rc < 0) {
520 pr_err("timer2 configure failed\n");
521 return rc;
522 }
523 break;
524 case ADC_MEAS_TIMER_SELECT3:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700525 rc = qpnp_adc_tm_read_reg(chip,
526 QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800527 &meas_interval_timer2);
528 if (rc < 0) {
529 pr_err("timer3 read failed\n");
530 return rc;
531 }
Siddartha Mohanadoss58ffe0e2014-02-11 17:40:13 -0800532 timer_interval_store = chip->sensor[chan_idx].meas_interval;
533 timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK;
534 meas_interval_timer2 |= timer_interval_store;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700535 rc = qpnp_adc_tm_write_reg(chip,
536 QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800537 meas_interval_timer2);
538 if (rc < 0) {
539 pr_err("timer3 configure failed\n");
540 return rc;
541 }
542 break;
543 default:
544 pr_err("Invalid timer selection\n");
545 return -EINVAL;
546 }
547
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800548 /* Select the timer to use for the corresponding channel */
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700549 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
550 if (rc < 0) {
551 pr_err("Invalid btm channel idx\n");
552 return rc;
553 }
Siddartha Mohanadoss58ffe0e2014-02-11 17:40:13 -0800554 rc = qpnp_adc_tm_write_reg(chip,
555 adc_tm_data[btm_chan_idx].meas_interval_ctl,
556 chip->sensor[chan_idx].timer_select);
557 if (rc < 0) {
558 pr_err("TM channel timer configure failed\n");
559 return rc;
560 }
561
562 pr_debug("timer select:%d, timer_value_within_select:%d, channel:%x\n",
563 chip->sensor[chan_idx].timer_select,
564 chip->sensor[chan_idx].meas_interval,
565 btm_chan);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800566
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800567 return rc;
568}
569
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700570static int32_t qpnp_adc_tm_add_to_list(struct qpnp_adc_tm_chip *chip,
571 uint32_t dt_index,
572 struct qpnp_adc_tm_btm_param *param,
573 struct qpnp_vadc_chan_properties *chan_prop)
574{
575 struct qpnp_adc_thr_client_info *client_info = NULL;
576 bool client_info_exists = false;
577
578 list_for_each_entry(client_info,
579 &chip->sensor[dt_index].thr_list, list) {
580 if (client_info->btm_param == param) {
581 client_info->low_thr_requested = chan_prop->low_thr;
582 client_info->high_thr_requested = chan_prop->high_thr;
583 client_info->state_requested = param->state_request;
584 client_info->state_req_copy = param->state_request;
585 client_info->notify_low_thr = false;
586 client_info->notify_high_thr = false;
587 client_info_exists = true;
588 pr_debug("client found\n");
589 }
590 }
591
592 if (!client_info_exists) {
593 client_info = devm_kzalloc(chip->dev,
594 sizeof(struct qpnp_adc_thr_client_info), GFP_KERNEL);
595 if (!client_info) {
596 pr_err("%s: kzalloc() failed.\n", __func__);
597 return -ENOMEM;
598 }
599
600 pr_debug("new client\n");
601 client_info->btm_param = param;
602 client_info->low_thr_requested = chan_prop->low_thr;
603 client_info->high_thr_requested = chan_prop->high_thr;
604 client_info->state_requested = param->state_request;
605 client_info->state_req_copy = param->state_request;
606
607 list_add_tail(&client_info->list,
608 &chip->sensor[dt_index].thr_list);
609 }
610
611 return 0;
612}
613
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700614static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
615 uint16_t addr, u8 mask, bool state)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800616{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800617 u8 reg_value = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800618 int rc = 0;
619
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700620 rc = qpnp_adc_tm_read_reg(chip, addr, &reg_value);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800621 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800622 pr_err("read failed for addr:0x%x\n", addr);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800623 return rc;
624 }
625
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800626 reg_value = reg_value & ~mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800627 if (state)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800628 reg_value |= mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800629
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800630 pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n",
631 state, addr, reg_value, ~mask);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700632 rc = qpnp_adc_tm_write_reg(chip, addr, reg_value);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800633 if (rc < 0) {
634 pr_err("write failed for addr:%x\n", addr);
635 return rc;
636 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800637
638 return rc;
639}
640
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700641static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700642 uint32_t btm_chan, int32_t high_thr, int32_t low_thr)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800643{
644 int rc = 0;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700645 uint32_t btm_chan_idx = 0;
646
647 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
648 if (rc < 0) {
649 pr_err("Invalid btm channel idx\n");
650 return rc;
651 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800652
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700653 rc = qpnp_adc_tm_write_reg(chip,
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700654 adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700655 QPNP_ADC_TM_THR_LSB_MASK(low_thr));
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800656 if (rc < 0) {
657 pr_err("low threshold lsb setting failed\n");
658 return rc;
659 }
660
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700661 rc = qpnp_adc_tm_write_reg(chip,
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700662 adc_tm_data[btm_chan_idx].low_thr_msb_addr,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700663 QPNP_ADC_TM_THR_MSB_MASK(low_thr));
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800664 if (rc < 0) {
665 pr_err("low threshold msb setting failed\n");
666 return rc;
667 }
668
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700669 rc = qpnp_adc_tm_write_reg(chip,
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700670 adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700671 QPNP_ADC_TM_THR_LSB_MASK(high_thr));
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800672 if (rc < 0) {
673 pr_err("high threshold lsb setting failed\n");
674 return rc;
675 }
676
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700677 rc = qpnp_adc_tm_write_reg(chip,
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700678 adc_tm_data[btm_chan_idx].high_thr_msb_addr,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700679 QPNP_ADC_TM_THR_MSB_MASK(high_thr));
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800680 if (rc < 0)
681 pr_err("high threshold msb setting failed\n");
682
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700683 pr_debug("client requested high:%d and low:%d\n",
684 high_thr, low_thr);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800685
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800686 return rc;
687}
688
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700689static int32_t qpnp_adc_tm_manage_thresholds(struct qpnp_adc_tm_chip *chip,
690 uint32_t dt_index, uint32_t btm_chan)
691{
692 struct qpnp_adc_thr_client_info *client_info = NULL;
693 struct list_head *thr_list;
694 int high_thr = 0, low_thr = 0, rc = 0;
695
696
697 /* high_thr/low_thr starting point and reset the high_thr_set and
698 low_thr_set back to reset since the thresholds will be
699 recomputed */
700 list_for_each(thr_list,
701 &chip->sensor[dt_index].thr_list) {
702 client_info = list_entry(thr_list,
703 struct qpnp_adc_thr_client_info, list);
704 high_thr = client_info->high_thr_requested;
705 low_thr = client_info->low_thr_requested;
706 client_info->high_thr_set = false;
707 client_info->low_thr_set = false;
708 }
709
710 pr_debug("init threshold is high:%d and low:%d\n", high_thr, low_thr);
711
712 /* Find the min of high_thr and max of low_thr */
713 list_for_each(thr_list,
714 &chip->sensor[dt_index].thr_list) {
715 client_info = list_entry(thr_list,
716 struct qpnp_adc_thr_client_info, list);
717 if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
718 (client_info->state_req_copy ==
719 ADC_TM_HIGH_LOW_THR_ENABLE))
720 if (client_info->high_thr_requested < high_thr)
721 high_thr = client_info->high_thr_requested;
722
723 if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
724 (client_info->state_req_copy ==
725 ADC_TM_HIGH_LOW_THR_ENABLE))
726 if (client_info->low_thr_requested > low_thr)
727 low_thr = client_info->low_thr_requested;
728
729 pr_debug("threshold compared is high:%d and low:%d\n",
730 client_info->high_thr_requested,
731 client_info->low_thr_requested);
732 pr_debug("current threshold is high:%d and low:%d\n",
733 high_thr, low_thr);
734 }
735
736 /* Check which of the high_thr and low_thr got set */
737 list_for_each(thr_list,
738 &chip->sensor[dt_index].thr_list) {
739 client_info = list_entry(thr_list,
740 struct qpnp_adc_thr_client_info, list);
741 if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
742 (client_info->state_req_copy ==
743 ADC_TM_HIGH_LOW_THR_ENABLE))
744 if (high_thr == client_info->high_thr_requested)
745 client_info->high_thr_set = true;
746
747 if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
748 (client_info->state_req_copy ==
749 ADC_TM_HIGH_LOW_THR_ENABLE))
750 if (low_thr == client_info->low_thr_requested)
751 client_info->low_thr_set = true;
752 }
753
754 rc = qpnp_adc_tm_thr_update(chip, btm_chan, high_thr, low_thr);
755 if (rc < 0)
756 pr_err("setting chan:%d threshold failed\n", btm_chan);
757
758 pr_debug("threshold written is high:%d and low:%d\n",
759 high_thr, low_thr);
760
761 return 0;
762}
763
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700764static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
765 uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800766 struct qpnp_vadc_chan_properties *chan_prop,
767 uint32_t amux_channel)
768{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800769 int rc = 0, i = 0, chan_idx = 0;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700770 bool chan_found = false, high_thr_set = false, low_thr_set = false;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800771 u8 sensor_mask = 0;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700772 struct qpnp_adc_thr_client_info *client_info = NULL;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800773
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700774 while (i < chip->max_channels_available) {
775 if (chip->sensor[i].btm_channel_num == btm_chan) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800776 chan_idx = i;
777 chan_found = true;
778 i++;
779 } else
780 i++;
781 }
782
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -0700783 if (!chan_found) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800784 pr_err("Channel not found\n");
785 return -EINVAL;
786 }
787
788 sensor_mask = 1 << chan_idx;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700789 if (!chip->sensor[chan_idx].thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800790 /* Update low and high notification thresholds */
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700791 rc = qpnp_adc_tm_manage_thresholds(chip, chan_idx,
792 btm_chan);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800793 if (rc < 0) {
794 pr_err("setting chan:%d threshold failed\n", btm_chan);
795 return rc;
796 }
797
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700798 list_for_each_entry(client_info,
799 &chip->sensor[chan_idx].thr_list, list) {
800 if (client_info->high_thr_set == true)
801 high_thr_set = true;
802 if (client_info->low_thr_set == true)
803 low_thr_set = true;
804 }
805
806 if (low_thr_set) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800807 pr_debug("low sensor mask:%x with state:%d\n",
808 sensor_mask, chan_prop->state_request);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800809 /* Enable low threshold's interrupt */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700810 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800811 QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800812 if (rc < 0) {
813 pr_err("low thr enable err:%d\n", btm_chan);
814 return rc;
815 }
816 }
817
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700818 if (high_thr_set) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800819 /* Enable high threshold's interrupt */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800820 pr_debug("high sensor mask:%x\n", sensor_mask);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700821 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800822 QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800823 if (rc < 0) {
824 pr_err("high thr enable err:%d\n", btm_chan);
825 return rc;
826 }
827 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800828 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800829
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800830 /* Enable corresponding BTM channel measurement */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700831 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800832 QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
833 if (rc < 0) {
834 pr_err("multi measurement en failed\n");
835 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800836 }
837
838 return rc;
839}
840
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700841static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800842 struct qpnp_adc_amux_properties *chan_prop)
843{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800844 u8 decimation = 0, op_cntrl = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800845 int rc = 0;
846 uint32_t btm_chan = 0;
847
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800848 /* Disable bank */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700849 rc = qpnp_adc_tm_disable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800850 if (rc)
851 return rc;
852
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800853 /* Check if a conversion is in progress */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700854 rc = qpnp_adc_tm_req_sts_check(chip);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800855 if (rc < 0) {
856 pr_err("adc-tm req_sts check failed\n");
857 return rc;
858 }
859
860 /* Set measurement in recurring mode */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700861 rc = qpnp_adc_tm_mode_select(chip, chan_prop->mode_sel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800862 if (rc < 0) {
863 pr_err("adc-tm mode select failed\n");
864 return rc;
865 }
866
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800867 /* Configure AMUX channel select for the corresponding BTM channel*/
868 btm_chan = chan_prop->chan_prop->tm_channel_select;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700869 rc = qpnp_adc_tm_write_reg(chip, btm_chan, chan_prop->amux_channel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800870 if (rc < 0) {
871 pr_err("adc-tm channel selection err\n");
872 return rc;
873 }
874
875 /* Digital paramater setup */
876 decimation |= chan_prop->decimation <<
877 QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700878 rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_DIG_PARAM, decimation);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800879 if (rc < 0) {
880 pr_err("adc-tm digital parameter setup err\n");
881 return rc;
882 }
883
884 /* Hardware setting time */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700885 rc = qpnp_adc_tm_write_reg(chip, QPNP_HW_SETTLE_DELAY,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800886 chan_prop->hw_settle_time);
887 if (rc < 0) {
888 pr_err("adc-tm hw settling time setup err\n");
889 return rc;
890 }
891
892 /* Fast averaging setup */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700893 rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_CTL,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800894 chan_prop->fast_avg_setup);
895 if (rc < 0) {
896 pr_err("adc-tm fast-avg setup err\n");
897 return rc;
898 }
899
900 /* Measurement interval setup */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700901 rc = qpnp_adc_tm_timer_interval_select(chip, btm_chan,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800902 chan_prop->chan_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800903 if (rc < 0) {
904 pr_err("adc-tm timer select failed\n");
905 return rc;
906 }
907
908 /* Channel configuration setup */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700909 rc = qpnp_adc_tm_channel_configure(chip, btm_chan,
910 chan_prop->chan_prop, chan_prop->amux_channel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800911 if (rc < 0) {
912 pr_err("adc-tm channel configure failed\n");
913 return rc;
914 }
915
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800916 /* Recurring interval measurement enable */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700917 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
918 &op_cntrl);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800919 op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700920 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800921 op_cntrl, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800922 if (rc < 0) {
923 pr_err("adc-tm meas interval op configure failed\n");
924 return rc;
925 }
926
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800927 /* Enable bank */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700928 rc = qpnp_adc_tm_enable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800929 if (rc)
930 return rc;
931
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800932 /* Request conversion */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700933 rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800934 if (rc < 0) {
935 pr_err("adc-tm request conversion failed\n");
936 return rc;
937 }
938
939 return 0;
940}
941
942static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
943 enum thermal_device_mode *mode)
944{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700945 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800946
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700947 if ((IS_ERR(adc_tm)) || qpnp_adc_tm_check_revision(
948 adc_tm->chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800949 return -EINVAL;
950
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700951 *mode = adc_tm->mode;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800952
953 return 0;
954}
955
956static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
957 enum thermal_device_mode mode)
958{
959 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700960 struct qpnp_adc_tm_chip *chip = adc_tm->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800961 int rc = 0, channel;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800962 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800963
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700964 if (qpnp_adc_tm_is_valid(chip)) {
965 pr_err("invalid device\n");
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700966 return -ENODEV;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700967 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700968
969 if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800970 return -EINVAL;
971
972 if (mode == THERMAL_DEVICE_ENABLED) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700973 chip->adc->amux_prop->amux_channel =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800974 adc_tm->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800975 channel = adc_tm->sensor_num;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700976 chip->adc->amux_prop->decimation =
977 chip->adc->adc_channels[channel].adc_decimation;
978 chip->adc->amux_prop->hw_settle_time =
979 chip->adc->adc_channels[channel].hw_settle_time;
980 chip->adc->amux_prop->fast_avg_setup =
981 chip->adc->adc_channels[channel].fast_avg_setup;
982 chip->adc->amux_prop->mode_sel =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800983 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700984 chip->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
985 chip->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
986 chip->adc->amux_prop->chan_prop->tm_channel_select =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800987 adc_tm->btm_channel_num;
988
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700989 rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800990 if (rc) {
991 pr_err("adc-tm tm configure failed with %d\n", rc);
992 return -EINVAL;
993 }
994 } else if (mode == THERMAL_DEVICE_DISABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800995 sensor_mask = 1 << adc_tm->sensor_num;
996 /* Disable bank */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700997 rc = qpnp_adc_tm_disable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800998 if (rc < 0) {
999 pr_err("adc-tm disable failed\n");
1000 return rc;
1001 }
1002
1003 /* Check if a conversion is in progress */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001004 rc = qpnp_adc_tm_req_sts_check(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001005 if (rc < 0) {
1006 pr_err("adc-tm req_sts check failed\n");
1007 return rc;
1008 }
1009
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001010 rc = qpnp_adc_tm_reg_update(chip,
1011 QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001012 if (rc < 0) {
1013 pr_err("multi measurement update failed\n");
1014 return rc;
1015 }
1016
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001017 rc = qpnp_adc_tm_enable_if_channel_meas(chip);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001018 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001019 pr_err("re-enabling measurement failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001020 return rc;
1021 }
1022 }
1023
1024 adc_tm->mode = mode;
1025
1026 return 0;
1027}
1028
1029static int qpnp_adc_tm_get_trip_type(struct thermal_zone_device *thermal,
1030 int trip, enum thermal_trip_type *type)
1031{
1032 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001033 struct qpnp_adc_tm_chip *chip = adc_tm->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001034
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001035 if (qpnp_adc_tm_is_valid(chip))
1036 return -ENODEV;
1037
1038 if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001039 return -EINVAL;
1040
1041 switch (trip) {
1042 case ADC_TM_TRIP_HIGH_WARM:
1043 *type = THERMAL_TRIP_CONFIGURABLE_HI;
1044 break;
1045 case ADC_TM_TRIP_LOW_COOL:
1046 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
1047 break;
1048 default:
1049 return -EINVAL;
1050 }
1051
1052 return 0;
1053}
1054
1055static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
1056 int trip, unsigned long *temp)
1057{
1058 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001059 struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001060 int64_t result = 0;
1061 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001062 unsigned int reg, rc = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001063 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
1064 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001065 uint32_t btm_chan_idx = 0, btm_chan = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001066
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001067 if (qpnp_adc_tm_is_valid(chip))
1068 return -ENODEV;
1069
1070 if (qpnp_adc_tm_check_revision(chip, adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001071 return -EINVAL;
1072
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001073 btm_chan = adc_tm_sensor->btm_channel_num;
1074 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
1075 if (rc < 0) {
1076 pr_err("Invalid btm channel idx\n");
1077 return rc;
1078 }
1079
1080 reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
1081 reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
1082 reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
1083 reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001084
1085 switch (trip) {
1086 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001087 rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_lsb,
1088 &trip_warm_thr0);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001089 if (rc) {
1090 pr_err("adc-tm low_thr_lsb err\n");
1091 return rc;
1092 }
1093
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001094 rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_msb,
1095 &trip_warm_thr1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001096 if (rc) {
1097 pr_err("adc-tm low_thr_msb err\n");
1098 return rc;
1099 }
1100 reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
1101 break;
1102 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001103 rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_lsb,
1104 &trip_cool_thr0);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001105 if (rc) {
1106 pr_err("adc-tm_tm high_thr_lsb err\n");
1107 return rc;
1108 }
1109
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001110 rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_msb,
1111 &trip_cool_thr1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001112 if (rc) {
1113 pr_err("adc-tm_tm high_thr_lsb err\n");
1114 return rc;
1115 }
1116 reg = (trip_cool_thr1 << 8) | trip_cool_thr0;
1117 break;
1118 default:
1119 return -EINVAL;
1120 }
1121
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001122 rc = qpnp_adc_tm_scale_voltage_therm_pu2(chip->vadc_dev, reg,
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001123 &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001124 if (rc < 0) {
1125 pr_err("Failed to lookup the therm thresholds\n");
1126 return rc;
1127 }
1128
1129 *temp = result;
1130
1131 return 0;
1132}
1133
1134static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
1135 int trip, long temp)
1136{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001137 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
1138 struct qpnp_adc_tm_chip *chip = adc_tm->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001139 struct qpnp_adc_tm_config tm_config;
1140 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
1141 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
1142 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001143 int rc = 0;
1144 uint32_t btm_chan = 0, btm_chan_idx = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001145
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001146 if (qpnp_adc_tm_is_valid(chip))
1147 return -ENODEV;
1148
1149 if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001150 return -EINVAL;
1151
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001152 tm_config.channel = adc_tm->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001153 switch (trip) {
1154 case ADC_TM_TRIP_HIGH_WARM:
1155 tm_config.high_thr_temp = temp;
1156 break;
1157 case ADC_TM_TRIP_LOW_COOL:
1158 tm_config.low_thr_temp = temp;
1159 break;
1160 default:
1161 return -EINVAL;
1162 }
1163
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001164 pr_debug("requested a high - %d and low - %d with trip - %d\n",
1165 tm_config.high_thr_temp, tm_config.low_thr_temp, trip);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001166 rc = qpnp_adc_tm_scale_therm_voltage_pu2(chip->vadc_dev, &tm_config);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001167 if (rc < 0) {
1168 pr_err("Failed to lookup the adc-tm thresholds\n");
1169 return rc;
1170 }
1171
1172 trip_warm_thr0 = ((tm_config.low_thr_voltage << 24) >> 24);
1173 trip_warm_thr1 = ((tm_config.low_thr_voltage << 16) >> 24);
1174 trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
1175 trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
1176
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001177 btm_chan = adc_tm->btm_channel_num;
1178 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
1179 if (rc < 0) {
1180 pr_err("Invalid btm channel idx\n");
1181 return rc;
1182 }
1183
1184 reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
1185 reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
1186 reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
1187 reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001188
1189 switch (trip) {
1190 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001191 rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_lsb,
1192 trip_cool_thr0);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001193 if (rc) {
1194 pr_err("adc-tm_tm read threshold err\n");
1195 return rc;
1196 }
1197
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001198 rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_msb,
1199 trip_cool_thr1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001200 if (rc) {
1201 pr_err("adc-tm_tm read threshold err\n");
1202 return rc;
1203 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001204 adc_tm->low_thr = tm_config.high_thr_voltage;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001205 break;
1206 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001207 rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_lsb,
1208 trip_warm_thr0);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001209 if (rc) {
1210 pr_err("adc-tm_tm read threshold err\n");
1211 return rc;
1212 }
1213
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001214 rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_msb,
1215 trip_warm_thr1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001216 if (rc) {
1217 pr_err("adc-tm_tm read threshold err\n");
1218 return rc;
1219 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001220 adc_tm->high_thr = tm_config.low_thr_voltage;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001221 break;
1222 default:
1223 return -EINVAL;
1224 }
1225
1226 return 0;
1227}
1228
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001229static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
1230{
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001231 struct qpnp_adc_thr_client_info *client_info = NULL;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001232
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001233 list_for_each_entry(client_info,
1234 &adc_tm->thr_list, list) {
1235 /* Batt therm's warm temperature translates to low voltage */
1236 if (client_info->notify_low_thr) {
1237 /* HIGH_STATE = WARM_TEMP for battery client */
1238 client_info->btm_param->threshold_notification(
1239 ADC_TM_WARM_STATE, client_info->btm_param->btm_ctx);
1240 client_info->notify_low_thr = false;
1241 }
1242
1243 /* Batt therm's cool temperature translates to high voltage */
1244 if (client_info->notify_high_thr) {
1245 /* LOW_STATE = COOL_TEMP for battery client */
1246 client_info->btm_param->threshold_notification(
1247 ADC_TM_COOL_STATE, client_info->btm_param->btm_ctx);
1248 client_info->notify_high_thr = false;
1249 }
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001250 }
1251
1252 return;
1253}
1254
1255static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
1256{
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001257 struct qpnp_adc_thr_client_info *client_info = NULL;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001258
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001259 list_for_each_entry(client_info,
1260 &adc_tm->thr_list, list) {
1261 /* For non batt therm clients */
1262 if (client_info->notify_low_thr) {
1263 if (client_info->btm_param->threshold_notification
1264 != NULL) {
1265 pr_debug("notify kernel with low state\n");
1266 client_info->btm_param->threshold_notification(
1267 ADC_TM_LOW_STATE,
1268 client_info->btm_param->btm_ctx);
1269 client_info->notify_low_thr = false;
1270 }
1271 }
1272
1273 if (client_info->notify_high_thr) {
1274 if (client_info->btm_param->threshold_notification
1275 != NULL) {
1276 pr_debug("notify kernel with high state\n");
1277 client_info->btm_param->threshold_notification(
1278 ADC_TM_HIGH_STATE,
1279 client_info->btm_param->btm_ctx);
1280 client_info->notify_high_thr = false;
1281 }
1282 }
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001283 }
1284
1285 return;
1286}
1287
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001288static void notify_adc_tm_fn(struct work_struct *work)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001289{
1290 struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
1291 struct qpnp_adc_tm_sensor, work);
1292
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001293 if (adc_tm->thermal_node) {
1294 sysfs_notify(&adc_tm->tz_dev->device.kobj,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001295 NULL, "btm");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001296 pr_debug("notifying uspace client\n");
1297 } else {
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001298 if (adc_tm->scale_type == SCALE_RBATT_THERM)
1299 notify_battery_therm(adc_tm);
1300 else
1301 notify_clients(adc_tm);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001302 }
1303
1304 return;
1305}
1306
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001307static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
1308 int trip, enum thermal_trip_activation_mode mode)
1309{
1310 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001311 struct qpnp_adc_tm_chip *chip = adc_tm->chip;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001312 int rc = 0, sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001313 u8 thr_int_en = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001314 bool state = false;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001315 uint32_t btm_chan_idx = 0, btm_chan = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001316
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001317 if (qpnp_adc_tm_is_valid(chip))
1318 return -ENODEV;
1319
1320 if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001321 return -EINVAL;
1322
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001323 if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
1324 state = true;
1325
1326 sensor_mask = 1 << adc_tm->sensor_num;
1327
1328 pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
1329
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001330 btm_chan = adc_tm->btm_channel_num;
1331 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
1332 if (rc < 0) {
1333 pr_err("Invalid btm channel idx\n");
1334 return rc;
1335 }
1336
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001337 switch (trip) {
1338 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001339 /* low_thr (lower voltage) for higher temp */
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001340 thr_int_en = adc_tm_data[btm_chan_idx].low_thr_int_chan_en;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001341 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001342 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001343 if (rc)
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001344 pr_err("channel:%x failed\n", btm_chan);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001345 break;
1346 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001347 /* high_thr (higher voltage) for cooler temp */
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001348 thr_int_en = adc_tm_data[btm_chan_idx].high_thr_int_chan_en;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001349 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001350 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001351 if (rc)
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001352 pr_err("channel:%x failed\n", btm_chan);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001353 break;
1354 default:
1355 return -EINVAL;
1356 }
1357
1358 return rc;
1359}
1360
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001361static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001362{
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001363 u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
1364 u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
Siddartha Mohanadoss91c33c92013-11-18 17:20:23 -08001365 u8 sensor_mask = 0, adc_tm_low_thr_set = 0, adc_tm_high_thr_set = 0;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001366 int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
1367 uint32_t btm_chan_num = 0;
1368 struct qpnp_adc_thr_client_info *client_info = NULL;
1369 struct list_head *thr_list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001370
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001371 if (qpnp_adc_tm_is_valid(chip))
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001372 return -ENODEV;
1373
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001374 mutex_lock(&chip->adc->adc_lock);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001375
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001376 rc = qpnp_adc_tm_req_sts_check(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001377 if (rc) {
1378 pr_err("adc-tm-tm req sts check failed with %d\n", rc);
1379 goto fail;
1380 }
1381
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001382 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_LOW, &status_low);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001383 if (rc) {
1384 pr_err("adc-tm-tm read status low failed with %d\n", rc);
1385 goto fail;
1386 }
1387
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001388 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_HIGH, &status_high);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001389 if (rc) {
1390 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1391 goto fail;
1392 }
1393
Siddartha Mohanadoss91c33c92013-11-18 17:20:23 -08001394 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
1395 &adc_tm_low_thr_set);
1396 if (rc) {
1397 pr_err("adc-tm-tm read low thr failed with %d\n", rc);
1398 goto fail;
1399 }
1400
1401 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
1402 &adc_tm_high_thr_set);
1403 if (rc) {
1404 pr_err("adc-tm-tm read high thr failed with %d\n", rc);
1405 goto fail;
1406 }
1407
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001408 /* Check which interrupt threshold is lower and measure against the
1409 * enabled channel */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001410 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001411 &qpnp_adc_tm_meas_en);
1412 if (rc) {
1413 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1414 goto fail;
1415 }
1416
1417 adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
Siddartha Mohanadoss91c33c92013-11-18 17:20:23 -08001418 adc_tm_low_enable &= adc_tm_low_thr_set;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001419 adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
Siddartha Mohanadoss91c33c92013-11-18 17:20:23 -08001420 adc_tm_high_enable &= adc_tm_high_thr_set;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001421
1422 if (adc_tm_high_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001423 sensor_notify_num = adc_tm_high_enable;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001424 while (i < chip->max_channels_available) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001425 if ((sensor_notify_num & 0x1) == 1)
1426 sensor_num = i;
1427 sensor_notify_num >>= 1;
1428 i++;
1429 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001430
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001431 btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001432 pr_debug("high:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1433 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1434 qpnp_adc_tm_meas_en);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001435 if (!chip->sensor[sensor_num].thermal_node) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001436 /* For non thermal registered clients
1437 such as usb_id, vbatt, pmic_therm */
1438 sensor_mask = 1 << sensor_num;
1439 pr_debug("non thermal node - mask:%x\n", sensor_mask);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001440 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001441 QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001442 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001443 if (rc < 0) {
1444 pr_err("high threshold int read failed\n");
1445 goto fail;
1446 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001447 } else {
1448 /* Uses the thermal sysfs registered device to disable
1449 the corresponding high voltage threshold which
1450 is triggered by low temp */
1451 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001452 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001453 chip->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001454 ADC_TM_TRIP_LOW_COOL,
1455 THERMAL_TRIP_ACTIVATION_DISABLED);
1456 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001457 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001458 goto fail;
1459 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001460 }
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001461 list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
1462 client_info = list_entry(thr_list,
1463 struct qpnp_adc_thr_client_info, list);
1464 if (client_info->high_thr_set) {
1465 client_info->high_thr_set = false;
1466 client_info->notify_high_thr = true;
1467 if (client_info->state_req_copy ==
1468 ADC_TM_HIGH_LOW_THR_ENABLE)
1469 client_info->state_req_copy =
1470 ADC_TM_LOW_THR_ENABLE;
1471 else
1472 client_info->state_req_copy =
1473 ADC_TM_HIGH_THR_DISABLE;
1474 }
1475 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001476 }
1477
1478 if (adc_tm_low_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001479 sensor_notify_num = adc_tm_low_enable;
1480 i = 0;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001481 while (i < chip->max_channels_available) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001482 if ((sensor_notify_num & 0x1) == 1)
1483 sensor_num = i;
1484 sensor_notify_num >>= 1;
1485 i++;
1486 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001487
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001488 btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001489 pr_debug("low:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1490 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1491 qpnp_adc_tm_meas_en);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001492 if (!chip->sensor[sensor_num].thermal_node) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001493 /* For non thermal registered clients
1494 such as usb_id, vbatt, pmic_therm */
1495 pr_debug("non thermal node - mask:%x\n", sensor_mask);
1496 sensor_mask = 1 << sensor_num;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001497 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001498 QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001499 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001500 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001501 pr_err("low threshold int read failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001502 goto fail;
1503 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001504 } else {
1505 /* Uses the thermal sysfs registered device to disable
1506 the corresponding low voltage threshold which
1507 is triggered by high temp */
1508 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001509 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001510 chip->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001511 ADC_TM_TRIP_HIGH_WARM,
1512 THERMAL_TRIP_ACTIVATION_DISABLED);
1513 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001514 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001515 goto fail;
1516 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001517 }
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001518 list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
1519 client_info = list_entry(thr_list,
1520 struct qpnp_adc_thr_client_info, list);
1521 if (client_info->low_thr_set) {
1522 /* mark the corresponding clients threshold
1523 as not set */
1524 client_info->low_thr_set = false;
1525 client_info->notify_low_thr = true;
1526 if (client_info->state_req_copy ==
1527 ADC_TM_HIGH_LOW_THR_ENABLE)
1528 client_info->state_req_copy =
1529 ADC_TM_HIGH_THR_ENABLE;
1530 else
1531 client_info->state_req_copy =
1532 ADC_TM_LOW_THR_DISABLE;
1533 }
1534 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001535 }
1536
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001537 qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
1538
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001539 if (adc_tm_high_enable || adc_tm_low_enable) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001540 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001541 sensor_mask, false);
1542 if (rc < 0) {
1543 pr_err("multi meas disable for channel failed\n");
1544 goto fail;
1545 }
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001546
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001547 rc = qpnp_adc_tm_enable_if_channel_meas(chip);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001548 if (rc < 0) {
1549 pr_err("re-enabling measurement failed\n");
1550 return rc;
1551 }
1552 } else
1553 pr_debug("No threshold status enable %d for high/low??\n",
1554 sensor_mask);
1555
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001556fail:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001557 mutex_unlock(&chip->adc->adc_lock);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001558
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001559 if (adc_tm_high_enable || adc_tm_low_enable)
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001560 schedule_work(&chip->sensor[sensor_num].work);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001561
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001562 return rc;
1563}
1564
1565static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
1566{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001567 struct qpnp_adc_tm_chip *chip = container_of(work,
1568 struct qpnp_adc_tm_chip, trigger_high_thr_work);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001569 int rc;
1570
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001571 rc = qpnp_adc_tm_read_status(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001572 if (rc < 0)
1573 pr_err("adc-tm high thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001574
1575 return;
1576}
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001577
1578static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
1579{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001580 struct qpnp_adc_tm_chip *chip = data;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001581
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001582 qpnp_adc_tm_disable(chip);
1583
1584 schedule_work(&chip->trigger_high_thr_work);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001585
1586 return IRQ_HANDLED;
1587}
1588
1589static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
1590{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001591 struct qpnp_adc_tm_chip *chip = container_of(work,
1592 struct qpnp_adc_tm_chip, trigger_low_thr_work);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001593 int rc;
1594
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001595 rc = qpnp_adc_tm_read_status(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001596 if (rc < 0)
1597 pr_err("adc-tm low thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001598
1599 return;
1600}
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001601
1602static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
1603{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001604 struct qpnp_adc_tm_chip *chip = data;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001605
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001606 qpnp_adc_tm_disable(chip);
1607
1608 schedule_work(&chip->trigger_low_thr_work);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001609
1610 return IRQ_HANDLED;
1611}
1612
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001613static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
1614 unsigned long *temp)
1615{
1616 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001617 struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001618 struct qpnp_vadc_result result;
1619 int rc = 0;
1620
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001621 rc = qpnp_vadc_read(chip->vadc_dev,
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001622 adc_tm_sensor->vadc_channel_num, &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001623 if (rc)
1624 return rc;
1625
1626 *temp = result.physical;
1627
1628 return rc;
1629}
1630
1631static struct thermal_zone_device_ops qpnp_adc_tm_thermal_ops = {
1632 .get_temp = qpnp_adc_read_temp,
1633 .get_mode = qpnp_adc_tm_get_mode,
1634 .set_mode = qpnp_adc_tm_set_mode,
1635 .get_trip_type = qpnp_adc_tm_get_trip_type,
1636 .activate_trip_type = qpnp_adc_tm_activate_trip_type,
1637 .get_trip_temp = qpnp_adc_tm_get_trip_temp,
1638 .set_trip_temp = qpnp_adc_tm_set_trip_temp,
1639};
1640
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001641int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_chip *chip,
1642 struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001643{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001644 uint32_t channel, dt_index = 0, scale_type = 0;
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001645 int rc = 0, i = 0;
1646 bool chan_found = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001647
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001648 if (qpnp_adc_tm_is_valid(chip)) {
1649 pr_err("chip not valid\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001650 return -ENODEV;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001651 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001652
1653 if (param->threshold_notification == NULL) {
Siddartha Mohanadoss8707b512013-07-16 18:43:41 -07001654 pr_debug("No notification for high/low temp??\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001655 return -EINVAL;
1656 }
1657
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001658 mutex_lock(&chip->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001659
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001660 channel = param->channel;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001661 while (i < chip->max_channels_available) {
1662 if (chip->adc->adc_channels[i].channel_num ==
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001663 channel) {
1664 dt_index = i;
1665 chan_found = true;
1666 i++;
1667 } else
1668 i++;
1669 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001670
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001671 if (!chan_found) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001672 pr_err("not a valid ADC_TM channel\n");
1673 rc = -EINVAL;
1674 goto fail_unlock;
1675 }
1676
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001677 rc = qpnp_adc_tm_check_revision(chip,
1678 chip->sensor[dt_index].btm_channel_num);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001679 if (rc < 0)
1680 goto fail_unlock;
1681
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001682 scale_type = chip->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001683 if (scale_type >= SCALE_RSCALE_NONE) {
1684 rc = -EBADF;
1685 goto fail_unlock;
1686 }
1687
1688 pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
1689 channel, scale_type, dt_index);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001690 chip->adc->amux_prop->amux_channel = channel;
1691 chip->adc->amux_prop->decimation =
1692 chip->adc->adc_channels[dt_index].adc_decimation;
1693 chip->adc->amux_prop->hw_settle_time =
1694 chip->adc->adc_channels[dt_index].hw_settle_time;
1695 chip->adc->amux_prop->fast_avg_setup =
1696 chip->adc->adc_channels[dt_index].fast_avg_setup;
1697 chip->adc->amux_prop->mode_sel =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001698 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001699 adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, param,
1700 &chip->adc->amux_prop->chan_prop->low_thr,
1701 &chip->adc->amux_prop->chan_prop->high_thr);
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001702 qpnp_adc_tm_add_to_list(chip, dt_index, param,
1703 chip->adc->amux_prop->chan_prop);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001704 chip->adc->amux_prop->chan_prop->tm_channel_select =
1705 chip->sensor[dt_index].btm_channel_num;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001706 chip->adc->amux_prop->chan_prop->state_request =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001707 param->state_request;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001708 rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001709 if (rc) {
1710 pr_err("adc-tm configure failed with %d\n", rc);
1711 goto fail_unlock;
1712 }
1713
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001714 chip->sensor[dt_index].scale_type = scale_type;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001715
1716fail_unlock:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001717 mutex_unlock(&chip->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001718
1719 return rc;
1720}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001721EXPORT_SYMBOL(qpnp_adc_tm_channel_measure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001722
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001723int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_chip *chip,
1724 struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001725{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001726 uint32_t channel, dt_index = 0, btm_chan_num;
1727 u8 sensor_mask = 0;
1728 int rc = 0;
1729
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001730 if (qpnp_adc_tm_is_valid(chip))
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001731 return -ENODEV;
1732
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001733 mutex_lock(&chip->adc->adc_lock);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001734
1735 /* Disable bank */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001736 rc = qpnp_adc_tm_disable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001737 if (rc < 0) {
1738 pr_err("adc-tm disable failed\n");
1739 goto fail;
1740 }
1741
1742 /* Check if a conversion is in progress */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001743 rc = qpnp_adc_tm_req_sts_check(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001744 if (rc < 0) {
1745 pr_err("adc-tm req_sts check failed\n");
1746 goto fail;
1747 }
1748
1749 channel = param->channel;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001750 while ((chip->adc->adc_channels[dt_index].channel_num
1751 != channel) && (dt_index < chip->max_channels_available))
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001752 dt_index++;
1753
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001754 if (dt_index >= chip->max_channels_available) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001755 pr_err("not a valid ADC_TMN channel\n");
1756 rc = -EINVAL;
1757 goto fail;
1758 }
1759
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001760 btm_chan_num = chip->sensor[dt_index].btm_channel_num;
1761 sensor_mask = 1 << chip->sensor[dt_index].sensor_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001762
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001763 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001764 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001765 if (rc < 0) {
1766 pr_err("low threshold int write failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001767 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001768 }
1769
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001770 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001771 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001772 if (rc < 0) {
1773 pr_err("high threshold int enable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001774 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001775 }
1776
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001777 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001778 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001779 if (rc < 0) {
1780 pr_err("multi measurement en failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001781 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001782 }
1783
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001784 rc = qpnp_adc_tm_enable_if_channel_meas(chip);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001785 if (rc < 0)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001786 pr_err("re-enabling measurement failed\n");
1787
1788fail:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001789 mutex_unlock(&chip->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001790
1791 return rc;
1792}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001793EXPORT_SYMBOL(qpnp_adc_tm_disable_chan_meas);
1794
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001795int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_chip *chip,
1796 struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001797{
1798 param->channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001799 return qpnp_adc_tm_channel_measure(chip, param);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001800}
1801EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001802
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001803int32_t qpnp_adc_tm_usbid_end(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001804{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001805 struct qpnp_adc_tm_btm_param param;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001806
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001807 return qpnp_adc_tm_disable_chan_meas(chip, &param);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001808}
1809EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
1810
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001811struct qpnp_adc_tm_chip *qpnp_get_adc_tm(struct device *dev, const char *name)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001812{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001813 struct qpnp_adc_tm_chip *chip;
1814 struct device_node *node = NULL;
1815 char prop_name[QPNP_MAX_PROP_NAME_LEN];
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001816
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001817 snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-adc_tm", name);
1818
1819 node = of_parse_phandle(dev->of_node, prop_name, 0);
1820 if (node == NULL)
1821 return ERR_PTR(-ENODEV);
1822
1823 list_for_each_entry(chip, &qpnp_adc_tm_device_list, list)
1824 if (chip->adc->spmi->dev.of_node == node)
1825 return chip;
1826
1827 return ERR_PTR(-EPROBE_DEFER);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001828}
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001829EXPORT_SYMBOL(qpnp_get_adc_tm);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001830
1831static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
1832{
1833 struct device_node *node = spmi->dev.of_node, *child;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001834 struct qpnp_adc_tm_chip *chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001835 struct qpnp_adc_drv *adc_qpnp;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001836 int32_t count_adc_channel_list = 0, rc, sen_idx = 0, i = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001837 u8 thr_init = 0;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001838 bool thermal_node = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001839
1840 for_each_child_of_node(node, child)
1841 count_adc_channel_list++;
1842
1843 if (!count_adc_channel_list) {
1844 pr_err("No channel listing\n");
1845 return -EINVAL;
1846 }
1847
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001848 chip = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_chip) +
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001849 (count_adc_channel_list *
1850 sizeof(struct qpnp_adc_tm_sensor)),
1851 GFP_KERNEL);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001852 if (!chip) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001853 dev_err(&spmi->dev, "Unable to allocate memory\n");
1854 return -ENOMEM;
1855 }
1856
1857 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1858 GFP_KERNEL);
1859 if (!adc_qpnp) {
1860 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001861 rc = -ENOMEM;
1862 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001863 }
1864
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001865 chip->dev = &(spmi->dev);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001866 chip->adc = adc_qpnp;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001867
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001868 rc = qpnp_adc_get_devicetree_data(spmi, chip->adc);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001869 if (rc) {
1870 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001871 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001872 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001873 mutex_init(&chip->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001874
1875 /* Register the ADC peripheral interrupt */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001876 chip->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001877 NULL, "high-thr-en-set");
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001878 if (chip->adc->adc_high_thr_irq < 0) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001879 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001880 rc = -ENXIO;
1881 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001882 }
1883
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001884 chip->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001885 NULL, "low-thr-en-set");
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001886 if (chip->adc->adc_low_thr_irq < 0) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001887 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001888 rc = -ENXIO;
1889 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001890 }
1891
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001892 chip->vadc_dev = qpnp_get_vadc(&spmi->dev, "adc_tm");
1893 if (IS_ERR(chip->vadc_dev)) {
1894 rc = PTR_ERR(chip->vadc_dev);
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001895 if (rc != -EPROBE_DEFER)
1896 pr_err("vadc property missing, rc=%d\n", rc);
1897 goto fail;
1898 }
1899
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001900 for_each_child_of_node(node, child) {
1901 char name[25];
Siddartha Mohanadoss58ffe0e2014-02-11 17:40:13 -08001902 int btm_channel_num, timer_select = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001903
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001904 rc = of_property_read_u32(child,
1905 "qcom,btm-channel-number", &btm_channel_num);
1906 if (rc) {
1907 pr_err("Invalid btm channel number\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001908 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001909 }
Siddartha Mohanadoss58ffe0e2014-02-11 17:40:13 -08001910 rc = of_property_read_u32(child,
1911 "qcom,meas-interval-timer-idx", &timer_select);
1912 if (rc) {
1913 pr_debug("Default to timer1 with interval of 1 sec\n");
1914 chip->sensor[sen_idx].timer_select =
1915 ADC_MEAS_TIMER_SELECT1;
1916 chip->sensor[sen_idx].meas_interval =
1917 ADC_MEAS1_INTERVAL_1S;
1918 } else {
1919 if (timer_select >= ADC_MEAS_TIMER_NUM) {
1920 pr_err("Invalid timer selection number\n");
1921 goto fail;
1922 }
1923 chip->sensor[sen_idx].timer_select = timer_select;
1924 if (timer_select == ADC_MEAS_TIMER_SELECT2)
1925 chip->sensor[sen_idx].meas_interval =
1926 ADC_MEAS2_INTERVAL_500MS;
1927 if (timer_select == ADC_MEAS_TIMER_SELECT3)
1928 chip->sensor[sen_idx].meas_interval =
1929 ADC_MEAS3_INTERVAL_4S;
1930 }
1931
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001932 chip->sensor[sen_idx].btm_channel_num = btm_channel_num;
1933 chip->sensor[sen_idx].vadc_channel_num =
1934 chip->adc->adc_channels[sen_idx].channel_num;
1935 chip->sensor[sen_idx].sensor_num = sen_idx;
1936 chip->sensor[sen_idx].chip = chip;
Siddartha Mohanadossb2795e42013-03-22 09:00:28 -07001937 pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001938 chip->adc->adc_channels[sen_idx].channel_num);
Siddartha Mohanadossea65d9e2013-04-16 18:26:39 -07001939 thermal_node = of_property_read_bool(child,
1940 "qcom,thermal-node");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001941 if (thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001942 /* Register with the thermal zone */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001943 pr_debug("thermal node%x\n", btm_channel_num);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001944 chip->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
1945 chip->sensor[sen_idx].thermal_node = true;
Dipen Parmar114616f2013-10-18 15:53:36 +05301946 snprintf(name, sizeof(name), "%s",
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001947 chip->adc->adc_channels[sen_idx].name);
1948 chip->sensor[sen_idx].meas_interval =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001949 QPNP_ADC_TM_MEAS_INTERVAL;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001950 chip->sensor[sen_idx].low_thr =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001951 QPNP_ADC_TM_M0_LOW_THR;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001952 chip->sensor[sen_idx].high_thr =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001953 QPNP_ADC_TM_M0_HIGH_THR;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001954 chip->sensor[sen_idx].tz_dev =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001955 thermal_zone_device_register(name,
1956 ADC_TM_TRIP_NUM,
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001957 &chip->sensor[sen_idx],
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001958 &qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001959 if (IS_ERR(chip->sensor[sen_idx].tz_dev))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001960 pr_err("thermal device register failed.\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001961 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001962 INIT_WORK(&chip->sensor[sen_idx].work, notify_adc_tm_fn);
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001963 INIT_LIST_HEAD(&chip->sensor[sen_idx].thr_list);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001964 sen_idx++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001965 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001966 chip->max_channels_available = count_adc_channel_list;
1967 INIT_WORK(&chip->trigger_high_thr_work, qpnp_adc_tm_high_thr_work);
1968 INIT_WORK(&chip->trigger_low_thr_work, qpnp_adc_tm_low_thr_work);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001969
1970 rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
1971 thr_init);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001972 if (rc < 0) {
1973 pr_err("high thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001974 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001975 }
1976
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001977 rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
1978 thr_init);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001979 if (rc < 0) {
1980 pr_err("low thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001981 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001982 }
1983
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001984 rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
1985 thr_init);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001986 if (rc < 0) {
1987 pr_err("multi meas en failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001988 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001989 }
1990
Siddartha Mohanadoss73fb1512013-08-08 22:38:13 -07001991 rc = devm_request_irq(&spmi->dev, chip->adc->adc_high_thr_irq,
1992 qpnp_adc_tm_high_thr_isr,
1993 IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", chip);
1994 if (rc) {
1995 dev_err(&spmi->dev, "failed to request adc irq\n");
1996 goto fail;
1997 } else {
1998 enable_irq_wake(chip->adc->adc_high_thr_irq);
1999 }
2000
2001 rc = devm_request_irq(&spmi->dev, chip->adc->adc_low_thr_irq,
2002 qpnp_adc_tm_low_thr_isr,
2003 IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", chip);
2004 if (rc) {
2005 dev_err(&spmi->dev, "failed to request adc irq\n");
2006 goto fail;
2007 } else {
2008 enable_irq_wake(chip->adc->adc_low_thr_irq);
2009 }
2010
2011 dev_set_drvdata(&spmi->dev, chip);
2012 list_add(&chip->list, &qpnp_adc_tm_device_list);
2013
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08002014 pr_debug("OK\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08002015 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08002016fail:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002017 for_each_child_of_node(node, child) {
2018 thermal_node = of_property_read_bool(child,
2019 "qcom,thermal-node");
2020 if (thermal_node)
2021 thermal_zone_device_unregister(chip->sensor[i].tz_dev);
2022 i++;
2023 }
2024 dev_set_drvdata(&spmi->dev, NULL);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08002025 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08002026}
2027
2028static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
2029{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002030 struct qpnp_adc_tm_chip *chip = dev_get_drvdata(&spmi->dev);
2031 struct device_node *node = spmi->dev.of_node, *child;
2032 bool thermal_node = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08002033 int i = 0;
2034
2035 for_each_child_of_node(node, child) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002036 thermal_node = of_property_read_bool(child,
2037 "qcom,thermal-node");
2038 if (thermal_node)
2039 thermal_zone_device_unregister(chip->sensor[i].tz_dev);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08002040 i++;
2041 }
2042
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08002043 dev_set_drvdata(&spmi->dev, NULL);
2044
2045 return 0;
2046}
2047
2048static const struct of_device_id qpnp_adc_tm_match_table[] = {
2049 { .compatible = "qcom,qpnp-adc-tm" },
2050 {}
2051};
2052
2053static struct spmi_driver qpnp_adc_tm_driver = {
2054 .driver = {
2055 .name = "qcom,qpnp-adc-tm",
2056 .of_match_table = qpnp_adc_tm_match_table,
2057 },
2058 .probe = qpnp_adc_tm_probe,
2059 .remove = qpnp_adc_tm_remove,
2060};
2061
2062static int __init qpnp_adc_tm_init(void)
2063{
2064 return spmi_driver_register(&qpnp_adc_tm_driver);
2065}
2066module_init(qpnp_adc_tm_init);
2067
2068static void __exit qpnp_adc_tm_exit(void)
2069{
2070 spmi_driver_unregister(&qpnp_adc_tm_driver);
2071}
2072module_exit(qpnp_adc_tm_exit);
2073
2074MODULE_DESCRIPTION("QPNP PMIC ADC Threshold Monitoring driver");
2075MODULE_LICENSE("GPL v2");