blob: c02db14450bb993de53bbfdec4f84d2a7a643736 [file] [log] [blame]
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001/* Copyright (c) 2012-2013, 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 Mohanadossa3e35512013-02-22 17:06:07 -080038#define QPNP_REVISION3 0x3
39#define QPNP_REVISION_EIGHT_CHANNEL_SUPPORT 2
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080040#define QPNP_STATUS1 0x8
41#define QPNP_STATUS1_OP_MODE 4
42#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
43#define QPNP_STATUS1_REQ_STS BIT(1)
44#define QPNP_STATUS1_EOC BIT(0)
45#define QPNP_STATUS2 0x9
46#define QPNP_STATUS2_CONV_SEQ_STATE 6
47#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
48#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
49#define QPNP_CONV_TIMEOUT_ERR 2
50
51#define QPNP_MODE_CTL 0x40
52#define QPNP_OP_MODE_SHIFT 3
53#define QPNP_VREF_XO_THM_FORCE BIT(2)
54#define QPNP_AMUX_TRIM_EN BIT(1)
55#define QPNP_ADC_TRIM_EN BIT(0)
56#define QPNP_EN_CTL1 0x46
57#define QPNP_ADC_TM_EN BIT(7)
58#define QPNP_ADC_CH_SEL_CTL 0x48
59#define QPNP_ADC_DIG_PARAM 0x50
60#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 3
61#define QPNP_HW_SETTLE_DELAY 0x51
62#define QPNP_CONV_REQ 0x52
63#define QPNP_CONV_REQ_SET BIT(7)
64#define QPNP_CONV_SEQ_CTL 0x54
65#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
66#define QPNP_CONV_SEQ_TRIG_CTL 0x55
67#define QPNP_ADC_TM_MEAS_INTERVAL_CTL 0x57
68#define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT 0x3
69#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2 0x58
70#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT 0x4
71#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK 0xf0
72#define QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK 0xf
73
74#define QPNP_ADC_MEAS_INTERVAL_OP_CTL 0x59
75#define QPNP_ADC_MEAS_INTERVAL_OP BIT(7)
76
77#define QPNP_FAST_AVG_CTL 0x5a
78#define QPNP_FAST_AVG_EN 0x5b
79
80#define QPNP_M0_LOW_THR_LSB 0x5c
81#define QPNP_M0_LOW_THR_MSB 0x5d
82#define QPNP_M0_HIGH_THR_LSB 0x5e
83#define QPNP_M0_HIGH_THR_MSB 0x5f
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080084#define QPNP_M1_ADC_CH_SEL_CTL 0x68
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080085#define QPNP_M1_LOW_THR_LSB 0x69
86#define QPNP_M1_LOW_THR_MSB 0x6a
87#define QPNP_M1_HIGH_THR_LSB 0x6b
88#define QPNP_M1_HIGH_THR_MSB 0x6c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080089#define QPNP_M2_ADC_CH_SEL_CTL 0x70
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080090#define QPNP_M2_LOW_THR_LSB 0x71
91#define QPNP_M2_LOW_THR_MSB 0x72
92#define QPNP_M2_HIGH_THR_LSB 0x7b
93#define QPNP_M2_HIGH_THR_MSB 0x7c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080094#define QPNP_M3_ADC_CH_SEL_CTL 0x78
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080095#define QPNP_M3_LOW_THR_LSB 0x79
96#define QPNP_M3_LOW_THR_MSB 0x7a
97#define QPNP_M3_HIGH_THR_LSB 0x7b
98#define QPNP_M3_HIGH_THR_MSB 0x7c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080099#define QPNP_M4_ADC_CH_SEL_CTL 0x80
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800100#define QPNP_M4_LOW_THR_LSB 0x81
101#define QPNP_M4_LOW_THR_MSB 0x82
102#define QPNP_M4_HIGH_THR_LSB 0x83
103#define QPNP_M4_HIGH_THR_MSB 0x84
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800104#define QPNP_M5_ADC_CH_SEL_CTL 0x88
105#define QPNP_M5_LOW_THR_LSB 0x89
106#define QPNP_M5_LOW_THR_MSB 0x8a
107#define QPNP_M5_HIGH_THR_LSB 0x8b
108#define QPNP_M5_HIGH_THR_MSB 0x8c
109#define QPNP_M6_ADC_CH_SEL_CTL 0x90
110#define QPNP_M6_LOW_THR_LSB 0x91
111#define QPNP_M6_LOW_THR_MSB 0x92
112#define QPNP_M6_HIGH_THR_LSB 0x93
113#define QPNP_M6_HIGH_THR_MSB 0x94
114#define QPNP_M7_ADC_CH_SEL_CTL 0x98
115#define QPNP_M7_LOW_THR_LSB 0x99
116#define QPNP_M7_LOW_THR_MSB 0x9a
117#define QPNP_M7_HIGH_THR_LSB 0x9b
118#define QPNP_M7_HIGH_THR_MSB 0x9c
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800119
120#define QPNP_ADC_TM_MULTI_MEAS_EN 0x41
121#define QPNP_ADC_TM_MULTI_MEAS_EN_M0 BIT(0)
122#define QPNP_ADC_TM_MULTI_MEAS_EN_M1 BIT(1)
123#define QPNP_ADC_TM_MULTI_MEAS_EN_M2 BIT(2)
124#define QPNP_ADC_TM_MULTI_MEAS_EN_M3 BIT(3)
125#define QPNP_ADC_TM_MULTI_MEAS_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800126#define QPNP_ADC_TM_MULTI_MEAS_EN_M5 BIT(5)
127#define QPNP_ADC_TM_MULTI_MEAS_EN_M6 BIT(6)
128#define QPNP_ADC_TM_MULTI_MEAS_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800129#define QPNP_ADC_TM_LOW_THR_INT_EN 0x42
130#define QPNP_ADC_TM_LOW_THR_INT_EN_M0 BIT(0)
131#define QPNP_ADC_TM_LOW_THR_INT_EN_M1 BIT(1)
132#define QPNP_ADC_TM_LOW_THR_INT_EN_M2 BIT(2)
133#define QPNP_ADC_TM_LOW_THR_INT_EN_M3 BIT(3)
134#define QPNP_ADC_TM_LOW_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800135#define QPNP_ADC_TM_LOW_THR_INT_EN_M5 BIT(5)
136#define QPNP_ADC_TM_LOW_THR_INT_EN_M6 BIT(6)
137#define QPNP_ADC_TM_LOW_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800138#define QPNP_ADC_TM_HIGH_THR_INT_EN 0x43
139#define QPNP_ADC_TM_HIGH_THR_INT_EN_M0 BIT(0)
140#define QPNP_ADC_TM_HIGH_THR_INT_EN_M1 BIT(1)
141#define QPNP_ADC_TM_HIGH_THR_INT_EN_M2 BIT(2)
142#define QPNP_ADC_TM_HIGH_THR_INT_EN_M3 BIT(3)
143#define QPNP_ADC_TM_HIGH_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800144#define QPNP_ADC_TM_HIGH_THR_INT_EN_M5 BIT(5)
145#define QPNP_ADC_TM_HIGH_THR_INT_EN_M6 BIT(6)
146#define QPNP_ADC_TM_HIGH_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800147
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800148#define QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL 0x59
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800149#define QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL 0x6d
150#define QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL 0x75
151#define QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL 0x7d
152#define QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL 0x85
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800153#define QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL 0x8d
154#define QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL 0x95
155#define QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL 0x9d
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800156#define QPNP_ADC_TM_STATUS1 0x8
157#define QPNP_ADC_TM_STATUS_LOW 0xa
158#define QPNP_ADC_TM_STATUS_HIGH 0xb
159
160#define QPNP_ADC_TM_M0_LOW_THR 0x5d5c
161#define QPNP_ADC_TM_M0_HIGH_THR 0x5f5e
162#define QPNP_ADC_TM_MEAS_INTERVAL 0x0
163
164#define QPNP_ADC_TM_THR_LSB_MASK(val) (val & 0xff)
165#define QPNP_ADC_TM_THR_MSB_MASK(val) ((val & 0xff00) >> 8)
166
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800167#define QPNP_MIN_TIME 2000
168#define QPNP_MAX_TIME 2100
169
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800170struct qpnp_adc_tm_sensor {
171 struct thermal_zone_device *tz_dev;
172 enum thermal_device_mode mode;
173 uint32_t sensor_num;
174 enum qpnp_adc_meas_timer_select timer_select;
175 uint32_t meas_interval;
176 uint32_t low_thr;
177 uint32_t high_thr;
178 uint32_t btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800179 uint32_t vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800180 struct work_struct work;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800181 struct qpnp_adc_tm_btm_param *btm_param;
182 bool thermal_node;
183 bool low_thr_notify;
184 bool high_thr_notify;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700185 uint32_t scale_type;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800186};
187
188struct qpnp_adc_tm_drv {
189 struct qpnp_adc_drv *adc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800190 bool adc_tm_initialized;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800191 int max_channels_available;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800192 struct qpnp_adc_tm_sensor sensor[0];
193};
194
195struct qpnp_adc_tm_drv *qpnp_adc_tm;
196
197struct qpnp_adc_tm_trip_reg_type {
198 uint16_t low_thr_lsb_addr;
199 uint16_t low_thr_msb_addr;
200 uint16_t high_thr_lsb_addr;
201 uint16_t high_thr_msb_addr;
202 u8 multi_meas_en;
203 u8 low_thr_int_chan_en;
204 u8 high_thr_int_chan_en;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800205 u8 meas_interval_ctl;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800206};
207
208static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
209 [QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
210 QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
211 QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800212 QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
213 QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800214 [QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
215 QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
216 QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800217 QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
218 QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800219 [QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
220 QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
221 QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800222 QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
223 QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800224 [QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
225 QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
226 QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800227 QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
228 QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800229 [QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
230 QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
231 QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800232 QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
233 QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
234 [QPNP_ADC_TM_M5_ADC_CH_SEL_CTL] = {QPNP_M5_LOW_THR_LSB,
235 QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
236 QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
237 QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
238 QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
239 [QPNP_ADC_TM_M6_ADC_CH_SEL_CTL] = {QPNP_M6_LOW_THR_LSB,
240 QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
241 QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
242 QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
243 QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
244 [QPNP_ADC_TM_M7_ADC_CH_SEL_CTL] = {QPNP_M7_LOW_THR_LSB,
245 QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
246 QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
247 QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
248 QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL},
249};
250
251static struct qpnp_adc_tm_reverse_scale_fn adc_tm_rscale_fn[] = {
252 [SCALE_R_VBATT] = {qpnp_adc_vbatt_rscaler},
253 [SCALE_RBATT_THERM] = {qpnp_adc_btm_scaler},
254 [SCALE_R_USB_ID] = {qpnp_adc_usb_scaler},
255 [SCALE_RPMIC_THERM] = {qpnp_adc_scale_millidegc_pmic_voltage_thr},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800256};
257
258static int32_t qpnp_adc_tm_read_reg(int16_t reg, u8 *data)
259{
260 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
261 int rc = 0;
262
263 rc = spmi_ext_register_readl(adc_tm->adc->spmi->ctrl,
264 adc_tm->adc->slave, (adc_tm->adc->offset + reg), data, 1);
265 if (rc < 0)
266 pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
267
268 return rc;
269}
270
271static int32_t qpnp_adc_tm_write_reg(int16_t reg, u8 data)
272{
273 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
274 int rc = 0;
275 u8 *buf;
276
277 buf = &data;
278
279 rc = spmi_ext_register_writel(adc_tm->adc->spmi->ctrl,
280 adc_tm->adc->slave, (adc_tm->adc->offset + reg), buf, 1);
281 if (rc < 0)
282 pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
283
284 return rc;
285}
286
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800287static int32_t qpnp_adc_tm_enable(void)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800288{
289 int rc = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800290 u8 data = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800291
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800292 data = QPNP_ADC_TM_EN;
293 rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
294 if (rc < 0)
295 pr_err("adc-tm enable failed\n");
296
297 return rc;
298}
299
300static int32_t qpnp_adc_tm_disable(void)
301{
302 u8 data = 0;
303 int rc = 0;
304
305 rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
306 if (rc < 0)
307 pr_err("adc-tm disable failed\n");
308
309 return rc;
310}
311
312static int32_t qpnp_adc_tm_enable_if_channel_meas(void)
313{
314 u8 adc_tm_meas_en = 0;
315 int rc = 0;
316
317 /* Check if a measurement request is still required */
318 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
319 &adc_tm_meas_en);
320 if (rc) {
321 pr_err("adc-tm-tm read status high failed with %d\n", rc);
322 return rc;
323 }
324
325 /* Enable only if there are pending measurement requests */
326 if (adc_tm_meas_en) {
327 qpnp_adc_tm_enable();
328
329 /* Request conversion */
330 rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800331 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800332 pr_err("adc-tm request conversion failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800333 return rc;
334 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800335 }
336
337 return rc;
338}
339
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800340static int32_t qpnp_adc_tm_req_sts_check(void)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800341{
342 u8 status1;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800343 int rc, count = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800344
345 /* The VADC_TM bank needs to be disabled for new conversion request */
346 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
347 if (rc) {
348 pr_err("adc-tm read status1 failed\n");
349 return rc;
350 }
351
352 /* Disable the bank if a conversion is occuring */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800353 while ((status1 & QPNP_STATUS1_REQ_STS) && (count < 5)) {
354 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800355 if (rc < 0)
356 pr_err("adc-tm disable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800357 /* Wait time is based on the optimum sampling rate
358 * and adding enough time buffer to account for ADC conversions
359 * occuring on different peripheral banks */
360 usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
361 count++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800362 }
363
364 return rc;
365}
366
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800367static int32_t qpnp_adc_tm_check_revision(uint32_t btm_chan_num)
368{
369 u8 rev;
370 int rc = 0;
371
372 rc = qpnp_adc_tm_read_reg(QPNP_REVISION3, &rev);
373 if (rc) {
374 pr_err("adc-tm revision read failed\n");
375 return rc;
376 }
377
378 if ((rev < QPNP_REVISION_EIGHT_CHANNEL_SUPPORT) &&
379 (btm_chan_num > QPNP_ADC_TM_M4_ADC_CH_SEL_CTL)) {
380 pr_debug("Version does not support more than 5 channels\n");
381 return -EINVAL;
382 }
383
384 return rc;
385}
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800386static int32_t qpnp_adc_tm_mode_select(u8 mode_ctl)
387{
388 int rc;
389
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800390 mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
391
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800392 /* VADC_BTM current sets mode to recurring measurements */
393 rc = qpnp_adc_tm_write_reg(QPNP_MODE_CTL, mode_ctl);
394 if (rc < 0)
395 pr_err("adc-tm write mode selection err\n");
396
397 return rc;
398}
399
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800400static int32_t qpnp_adc_tm_timer_interval_select(uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800401 struct qpnp_vadc_chan_properties *chan_prop)
402{
403 int rc;
404 u8 meas_interval_timer2 = 0;
405
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800406 /* Configure kernel clients to timer1 */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800407 switch (chan_prop->timer_select) {
408 case ADC_MEAS_TIMER_SELECT1:
409 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL,
410 chan_prop->meas_interval1);
411 if (rc < 0) {
412 pr_err("timer1 configure failed\n");
413 return rc;
414 }
415 break;
416 case ADC_MEAS_TIMER_SELECT2:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800417 /* Thermal channels uses timer2, default to 1 second */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800418 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
419 &meas_interval_timer2);
420 if (rc < 0) {
421 pr_err("timer2 configure read failed\n");
422 return rc;
423 }
424 meas_interval_timer2 |=
425 (chan_prop->meas_interval2 <<
426 QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
427 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
428 meas_interval_timer2);
429 if (rc < 0) {
430 pr_err("timer2 configure failed\n");
431 return rc;
432 }
433 break;
434 case ADC_MEAS_TIMER_SELECT3:
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800435 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
436 &meas_interval_timer2);
437 if (rc < 0) {
438 pr_err("timer3 read failed\n");
439 return rc;
440 }
441 chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
442 meas_interval_timer2 |= chan_prop->meas_interval2;
443 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
444 meas_interval_timer2);
445 if (rc < 0) {
446 pr_err("timer3 configure failed\n");
447 return rc;
448 }
449 break;
450 default:
451 pr_err("Invalid timer selection\n");
452 return -EINVAL;
453 }
454
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800455 /* Select the timer to use for the corresponding channel */
456 adc_tm_data[btm_chan].meas_interval_ctl = chan_prop->timer_select;
457
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800458 return rc;
459}
460
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700461static int32_t qpnp_adc_tm_reg_update(uint16_t addr,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800462 u8 mask, bool state)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800463{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800464 u8 reg_value = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800465 int rc = 0;
466
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800467 rc = qpnp_adc_tm_read_reg(addr, &reg_value);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800468 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800469 pr_err("read failed for addr:0x%x\n", addr);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800470 return rc;
471 }
472
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800473 reg_value = reg_value & ~mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800474 if (state)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800475 reg_value |= mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800476
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800477 pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n",
478 state, addr, reg_value, ~mask);
479 rc = qpnp_adc_tm_write_reg(addr, reg_value);
480 if (rc < 0) {
481 pr_err("write failed for addr:%x\n", addr);
482 return rc;
483 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800484
485 return rc;
486}
487
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700488static int32_t qpnp_adc_tm_thr_update(uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800489 struct qpnp_vadc_chan_properties *chan_prop)
490{
491 int rc = 0;
492
493 rc = qpnp_adc_tm_write_reg(
494 adc_tm_data[btm_chan].low_thr_lsb_addr,
495 QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
496 if (rc < 0) {
497 pr_err("low threshold lsb setting failed\n");
498 return rc;
499 }
500
501 rc = qpnp_adc_tm_write_reg(
502 adc_tm_data[btm_chan].low_thr_msb_addr,
503 QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
504 if (rc < 0) {
505 pr_err("low threshold msb setting failed\n");
506 return rc;
507 }
508
509 rc = qpnp_adc_tm_write_reg(
510 adc_tm_data[btm_chan].high_thr_lsb_addr,
511 QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
512 if (rc < 0) {
513 pr_err("high threshold lsb setting failed\n");
514 return rc;
515 }
516
517 rc = qpnp_adc_tm_write_reg(
518 adc_tm_data[btm_chan].high_thr_msb_addr,
519 QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
520 if (rc < 0)
521 pr_err("high threshold msb setting failed\n");
522
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700523 pr_debug("client requested low:%d and high:%d\n",
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800524 chan_prop->low_thr, chan_prop->high_thr);
525
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800526 return rc;
527}
528
529static int32_t qpnp_adc_tm_channel_configure(uint32_t btm_chan,
530 struct qpnp_vadc_chan_properties *chan_prop,
531 uint32_t amux_channel)
532{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800533 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
534 int rc = 0, i = 0, chan_idx = 0;
535 bool chan_found = false;
536 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800537
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800538 while (i < adc_tm->max_channels_available) {
539 if (adc_tm->sensor[i].btm_channel_num == btm_chan) {
540 chan_idx = i;
541 chan_found = true;
542 i++;
543 } else
544 i++;
545 }
546
547 if ((i == adc_tm->max_channels_available) && (!chan_found)) {
548 pr_err("Channel not found\n");
549 return -EINVAL;
550 }
551
552 sensor_mask = 1 << chan_idx;
553 if (!adc_tm->sensor[chan_idx].thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800554 /* Update low and high notification thresholds */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700555 rc = qpnp_adc_tm_thr_update(btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800556 chan_prop);
557 if (rc < 0) {
558 pr_err("setting chan:%d threshold failed\n", btm_chan);
559 return rc;
560 }
561
562 if ((chan_prop->state_request ==
563 ADC_TM_LOW_THR_ENABLE) ||
564 (chan_prop->state_request ==
565 ADC_TM_HIGH_LOW_THR_ENABLE)) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800566 pr_debug("low sensor mask:%x with state:%d\n",
567 sensor_mask, chan_prop->state_request);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800568 /* Enable low threshold's interrupt */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700569 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800570 QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800571 if (rc < 0) {
572 pr_err("low thr enable err:%d\n", btm_chan);
573 return rc;
574 }
575 }
576
577 if ((chan_prop->state_request ==
578 ADC_TM_HIGH_THR_ENABLE) ||
579 (chan_prop->state_request ==
580 ADC_TM_HIGH_LOW_THR_ENABLE)) {
581 /* Enable high threshold's interrupt */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800582 pr_debug("high sensor mask:%x\n", sensor_mask);
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700583 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800584 QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800585 if (rc < 0) {
586 pr_err("high thr enable err:%d\n", btm_chan);
587 return rc;
588 }
589 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800590 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800591
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800592 /* Enable corresponding BTM channel measurement */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700593 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800594 QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
595 if (rc < 0) {
596 pr_err("multi measurement en failed\n");
597 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800598 }
599
600 return rc;
601}
602
603static int32_t qpnp_adc_tm_configure(
604 struct qpnp_adc_amux_properties *chan_prop)
605{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800606 u8 decimation = 0, op_cntrl = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800607 int rc = 0;
608 uint32_t btm_chan = 0;
609
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800610 /* Disable bank */
611 rc = qpnp_adc_tm_disable();
612 if (rc)
613 return rc;
614
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800615 /* Check if a conversion is in progress */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800616 rc = qpnp_adc_tm_req_sts_check();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800617 if (rc < 0) {
618 pr_err("adc-tm req_sts check failed\n");
619 return rc;
620 }
621
622 /* Set measurement in recurring mode */
623 rc = qpnp_adc_tm_mode_select(chan_prop->mode_sel);
624 if (rc < 0) {
625 pr_err("adc-tm mode select failed\n");
626 return rc;
627 }
628
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800629 /* Configure AMUX channel select for the corresponding BTM channel*/
630 btm_chan = chan_prop->chan_prop->tm_channel_select;
631 rc = qpnp_adc_tm_write_reg(btm_chan, chan_prop->amux_channel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800632 if (rc < 0) {
633 pr_err("adc-tm channel selection err\n");
634 return rc;
635 }
636
637 /* Digital paramater setup */
638 decimation |= chan_prop->decimation <<
639 QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
640 rc = qpnp_adc_tm_write_reg(QPNP_ADC_DIG_PARAM, decimation);
641 if (rc < 0) {
642 pr_err("adc-tm digital parameter setup err\n");
643 return rc;
644 }
645
646 /* Hardware setting time */
647 rc = qpnp_adc_tm_write_reg(QPNP_HW_SETTLE_DELAY,
648 chan_prop->hw_settle_time);
649 if (rc < 0) {
650 pr_err("adc-tm hw settling time setup err\n");
651 return rc;
652 }
653
654 /* Fast averaging setup */
655 rc = qpnp_adc_tm_write_reg(QPNP_FAST_AVG_CTL,
656 chan_prop->fast_avg_setup);
657 if (rc < 0) {
658 pr_err("adc-tm fast-avg setup err\n");
659 return rc;
660 }
661
662 /* Measurement interval setup */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800663 rc = qpnp_adc_tm_timer_interval_select(btm_chan,
664 chan_prop->chan_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800665 if (rc < 0) {
666 pr_err("adc-tm timer select failed\n");
667 return rc;
668 }
669
670 /* Channel configuration setup */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800671 rc = qpnp_adc_tm_channel_configure(btm_chan, chan_prop->chan_prop,
672 chan_prop->amux_channel);
673 if (rc < 0) {
674 pr_err("adc-tm channel configure failed\n");
675 return rc;
676 }
677
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800678 /* Recurring interval measurement enable */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800679 rc = qpnp_adc_tm_read_reg(QPNP_ADC_MEAS_INTERVAL_OP_CTL, &op_cntrl);
680 op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700681 rc = qpnp_adc_tm_reg_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800682 op_cntrl, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800683 if (rc < 0) {
684 pr_err("adc-tm meas interval op configure failed\n");
685 return rc;
686 }
687
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800688 /* Enable bank */
689 rc = qpnp_adc_tm_enable();
690 if (rc)
691 return rc;
692
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800693 /* Request conversion */
694 rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
695 if (rc < 0) {
696 pr_err("adc-tm request conversion failed\n");
697 return rc;
698 }
699
700 return 0;
701}
702
703static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
704 enum thermal_device_mode *mode)
705{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800706 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800707
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800708 if (!adc_tm_sensor || qpnp_adc_tm_check_revision(
709 adc_tm_sensor->btm_channel_num) || !mode)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800710 return -EINVAL;
711
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800712 *mode = adc_tm_sensor->mode;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800713
714 return 0;
715}
716
717static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
718 enum thermal_device_mode mode)
719{
720 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
721 struct qpnp_adc_tm_drv *adc_drv = qpnp_adc_tm;
722 int rc = 0, channel;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800723 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800724
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800725 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800726 return -EINVAL;
727
728 if (mode == THERMAL_DEVICE_ENABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800729 adc_drv->adc->amux_prop->amux_channel =
730 adc_tm->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800731 channel = adc_tm->sensor_num;
732 adc_drv->adc->amux_prop->decimation =
733 adc_drv->adc->adc_channels[channel].adc_decimation;
734 adc_drv->adc->amux_prop->hw_settle_time =
735 adc_drv->adc->adc_channels[channel].hw_settle_time;
736 adc_drv->adc->amux_prop->fast_avg_setup =
737 adc_drv->adc->adc_channels[channel].fast_avg_setup;
738 adc_drv->adc->amux_prop->mode_sel =
739 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
740 adc_drv->adc->amux_prop->chan_prop->timer_select =
741 ADC_MEAS_TIMER_SELECT1;
742 adc_drv->adc->amux_prop->chan_prop->meas_interval1 =
743 ADC_MEAS1_INTERVAL_1S;
744 adc_drv->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
745 adc_drv->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
746 adc_drv->adc->amux_prop->chan_prop->tm_channel_select =
747 adc_tm->btm_channel_num;
748
749 rc = qpnp_adc_tm_configure(adc_drv->adc->amux_prop);
750 if (rc) {
751 pr_err("adc-tm tm configure failed with %d\n", rc);
752 return -EINVAL;
753 }
754 } else if (mode == THERMAL_DEVICE_DISABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800755 sensor_mask = 1 << adc_tm->sensor_num;
756 /* Disable bank */
757 rc = qpnp_adc_tm_disable();
758 if (rc < 0) {
759 pr_err("adc-tm disable failed\n");
760 return rc;
761 }
762
763 /* Check if a conversion is in progress */
764 rc = qpnp_adc_tm_req_sts_check();
765 if (rc < 0) {
766 pr_err("adc-tm req_sts check failed\n");
767 return rc;
768 }
769
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700770 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800771 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800772 if (rc < 0) {
773 pr_err("multi measurement update failed\n");
774 return rc;
775 }
776
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800777 rc = qpnp_adc_tm_enable_if_channel_meas();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800778 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800779 pr_err("re-enabling measurement failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800780 return rc;
781 }
782 }
783
784 adc_tm->mode = mode;
785
786 return 0;
787}
788
789static int qpnp_adc_tm_get_trip_type(struct thermal_zone_device *thermal,
790 int trip, enum thermal_trip_type *type)
791{
792 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
793
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800794 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num)
795 || !type || type < 0)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800796 return -EINVAL;
797
798 switch (trip) {
799 case ADC_TM_TRIP_HIGH_WARM:
800 *type = THERMAL_TRIP_CONFIGURABLE_HI;
801 break;
802 case ADC_TM_TRIP_LOW_COOL:
803 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
804 break;
805 default:
806 return -EINVAL;
807 }
808
809 return 0;
810}
811
812static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
813 int trip, unsigned long *temp)
814{
815 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
816 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
817 int64_t result = 0;
818 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
819 unsigned int reg, rc = 0, btm_channel_num;
820 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
821 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
822
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800823 if (!adc_tm || qpnp_adc_tm_check_revision(
824 adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800825 return -EINVAL;
826
827 btm_channel_num = adc_tm_sensor->btm_channel_num;
828 reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
829 reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
830 reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
831 reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
832
833 switch (trip) {
834 case ADC_TM_TRIP_HIGH_WARM:
835 rc = qpnp_adc_tm_read_reg(reg_low_thr_lsb, &trip_warm_thr0);
836 if (rc) {
837 pr_err("adc-tm low_thr_lsb err\n");
838 return rc;
839 }
840
841 rc = qpnp_adc_tm_read_reg(reg_low_thr_msb, &trip_warm_thr1);
842 if (rc) {
843 pr_err("adc-tm low_thr_msb err\n");
844 return rc;
845 }
846 reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
847 break;
848 case ADC_TM_TRIP_LOW_COOL:
849 rc = qpnp_adc_tm_read_reg(reg_high_thr_lsb, &trip_cool_thr0);
850 if (rc) {
851 pr_err("adc-tm_tm high_thr_lsb err\n");
852 return rc;
853 }
854
855 rc = qpnp_adc_tm_read_reg(reg_high_thr_msb, &trip_cool_thr1);
856 if (rc) {
857 pr_err("adc-tm_tm high_thr_lsb err\n");
858 return rc;
859 }
860 reg = (trip_cool_thr1 << 8) | trip_cool_thr0;
861 break;
862 default:
863 return -EINVAL;
864 }
865
866 rc = qpnp_adc_tm_scale_voltage_therm_pu2(reg, &result);
867 if (rc < 0) {
868 pr_err("Failed to lookup the therm thresholds\n");
869 return rc;
870 }
871
872 *temp = result;
873
874 return 0;
875}
876
877static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
878 int trip, long temp)
879{
880 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
881 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
882 struct qpnp_adc_tm_config tm_config;
883 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
884 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
885 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
886 int rc = 0, btm_channel_num;
887
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800888 if (!adc_tm || qpnp_adc_tm_check_revision(
889 adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800890 return -EINVAL;
891
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800892 tm_config.channel = adc_tm_sensor->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800893 switch (trip) {
894 case ADC_TM_TRIP_HIGH_WARM:
895 tm_config.high_thr_temp = temp;
896 break;
897 case ADC_TM_TRIP_LOW_COOL:
898 tm_config.low_thr_temp = temp;
899 break;
900 default:
901 return -EINVAL;
902 }
903
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800904 pr_debug("requested a high - %d and low - %d with trip - %d\n",
905 tm_config.high_thr_temp, tm_config.low_thr_temp, trip);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800906 rc = qpnp_adc_tm_scale_therm_voltage_pu2(&tm_config);
907 if (rc < 0) {
908 pr_err("Failed to lookup the adc-tm thresholds\n");
909 return rc;
910 }
911
912 trip_warm_thr0 = ((tm_config.low_thr_voltage << 24) >> 24);
913 trip_warm_thr1 = ((tm_config.low_thr_voltage << 16) >> 24);
914 trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
915 trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
916
917 btm_channel_num = adc_tm_sensor->btm_channel_num;
918 reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
919 reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
920 reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
921 reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
922
923 switch (trip) {
924 case ADC_TM_TRIP_HIGH_WARM:
925 rc = qpnp_adc_tm_write_reg(reg_low_thr_lsb, trip_cool_thr0);
926 if (rc) {
927 pr_err("adc-tm_tm read threshold err\n");
928 return rc;
929 }
930
931 rc = qpnp_adc_tm_write_reg(reg_low_thr_msb, trip_cool_thr1);
932 if (rc) {
933 pr_err("adc-tm_tm read threshold err\n");
934 return rc;
935 }
936 adc_tm_sensor->low_thr = tm_config.high_thr_voltage;
937 break;
938 case ADC_TM_TRIP_LOW_COOL:
939 rc = qpnp_adc_tm_write_reg(reg_high_thr_lsb, trip_warm_thr0);
940 if (rc) {
941 pr_err("adc-tm_tm read threshold err\n");
942 return rc;
943 }
944
945 rc = qpnp_adc_tm_write_reg(reg_high_thr_msb, trip_warm_thr1);
946 if (rc) {
947 pr_err("adc-tm_tm read threshold err\n");
948 return rc;
949 }
950 adc_tm_sensor->high_thr = tm_config.low_thr_voltage;
951 break;
952 default:
953 return -EINVAL;
954 }
955
956 return 0;
957}
958
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700959static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
960{
961 /* Battery therm's warm temperature translates to low voltage */
962 if (adc_tm->low_thr_notify) {
963 /* HIGH_STATE = WARM_TEMP for battery client */
964 adc_tm->btm_param->threshold_notification(
965 ADC_TM_WARM_STATE, adc_tm->btm_param->btm_ctx);
966 adc_tm->low_thr_notify = false;
967 }
968
969 /* Battery therm's cool temperature translates to high voltage */
970 if (adc_tm->high_thr_notify) {
971 /* LOW_STATE = COOL_TEMP for battery client */
972 adc_tm->btm_param->threshold_notification(
973 ADC_TM_COOL_STATE, adc_tm->btm_param->btm_ctx);
974 adc_tm->high_thr_notify = false;
975 }
976
977 return;
978}
979
980static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
981{
982 /* For non batt therm clients */
983 if (adc_tm->low_thr_notify) {
984 pr_debug("notify kernel with low state\n");
985 adc_tm->btm_param->threshold_notification(
986 ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
987 adc_tm->low_thr_notify = false;
988 }
989
990 if (adc_tm->high_thr_notify) {
991 pr_debug("notify kernel with high state\n");
992 adc_tm->btm_param->threshold_notification(
993 ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
994 adc_tm->high_thr_notify = false;
995 }
996
997 return;
998}
999
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001000static void notify_adc_tm_fn(struct work_struct *work)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001001{
1002 struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
1003 struct qpnp_adc_tm_sensor, work);
1004
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001005 if (adc_tm->thermal_node) {
1006 sysfs_notify(&adc_tm->tz_dev->device.kobj,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001007 NULL, "btm");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001008 pr_debug("notifying uspace client\n");
1009 } else {
1010 if (adc_tm->btm_param->threshold_notification != NULL) {
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001011 if (adc_tm->scale_type == SCALE_RBATT_THERM)
1012 notify_battery_therm(adc_tm);
1013 else
1014 notify_clients(adc_tm);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001015 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001016 }
1017
1018 return;
1019}
1020
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001021static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
1022 int trip, enum thermal_trip_activation_mode mode)
1023{
1024 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001025 int rc = 0, sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001026 u8 thr_int_en = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001027 bool state = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001028
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001029 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001030 return -EINVAL;
1031
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001032 if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
1033 state = true;
1034
1035 sensor_mask = 1 << adc_tm->sensor_num;
1036
1037 pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
1038
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001039 switch (trip) {
1040 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001041 /* low_thr (lower voltage) for higher temp */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001042 thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
1043 low_thr_int_chan_en;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001044 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001045 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001046 if (rc)
1047 pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
1048 break;
1049 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001050 /* high_thr (higher voltage) for cooler temp */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001051 thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
1052 high_thr_int_chan_en;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001053 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001054 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001055 if (rc)
1056 pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
1057 break;
1058 default:
1059 return -EINVAL;
1060 }
1061
1062 return rc;
1063}
1064
1065static int qpnp_adc_tm_read_status(void)
1066{
1067 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1068 u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
1069 u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001070 u8 sensor_mask = 0;
1071 int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0, btm_chan_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001072
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001073 if (!adc_tm || !adc_tm->adc_tm_initialized)
1074 return -ENODEV;
1075
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001076 mutex_lock(&adc_tm->adc->adc_lock);
1077
1078 rc = qpnp_adc_tm_req_sts_check();
1079 if (rc) {
1080 pr_err("adc-tm-tm req sts check failed with %d\n", rc);
1081 goto fail;
1082 }
1083
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001084 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW, &status_low);
1085 if (rc) {
1086 pr_err("adc-tm-tm read status low failed with %d\n", rc);
1087 goto fail;
1088 }
1089
1090 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH, &status_high);
1091 if (rc) {
1092 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1093 goto fail;
1094 }
1095
1096 /* Check which interrupt threshold is lower and measure against the
1097 * enabled channel */
1098 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
1099 &qpnp_adc_tm_meas_en);
1100 if (rc) {
1101 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1102 goto fail;
1103 }
1104
1105 adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
1106 adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
1107
1108 if (adc_tm_high_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001109 sensor_notify_num = adc_tm_high_enable;
1110 while (i < adc_tm->max_channels_available) {
1111 if ((sensor_notify_num & 0x1) == 1)
1112 sensor_num = i;
1113 sensor_notify_num >>= 1;
1114 i++;
1115 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001116
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001117 btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
1118 pr_debug("high:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1119 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1120 qpnp_adc_tm_meas_en);
1121 if (!adc_tm->sensor[sensor_num].thermal_node) {
1122 /* For non thermal registered clients
1123 such as usb_id, vbatt, pmic_therm */
1124 sensor_mask = 1 << sensor_num;
1125 pr_debug("non thermal node - mask:%x\n", sensor_mask);
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001126 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001127 QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001128 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001129 if (rc < 0) {
1130 pr_err("high threshold int read failed\n");
1131 goto fail;
1132 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001133 adc_tm->sensor[sensor_num].high_thr_notify = true;
1134 } else {
1135 /* Uses the thermal sysfs registered device to disable
1136 the corresponding high voltage threshold which
1137 is triggered by low temp */
1138 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001139 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001140 adc_tm->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001141 ADC_TM_TRIP_LOW_COOL,
1142 THERMAL_TRIP_ACTIVATION_DISABLED);
1143 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001144 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001145 goto fail;
1146 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001147 }
1148 }
1149
1150 if (adc_tm_low_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001151 sensor_notify_num = adc_tm_low_enable;
1152 i = 0;
1153 while (i < adc_tm->max_channels_available) {
1154 if ((sensor_notify_num & 0x1) == 1)
1155 sensor_num = i;
1156 sensor_notify_num >>= 1;
1157 i++;
1158 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001159
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001160 btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
1161 pr_debug("low:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1162 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1163 qpnp_adc_tm_meas_en);
1164 if (!adc_tm->sensor[sensor_num].thermal_node) {
1165 /* For non thermal registered clients
1166 such as usb_id, vbatt, pmic_therm */
1167 pr_debug("non thermal node - mask:%x\n", sensor_mask);
1168 sensor_mask = 1 << sensor_num;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001169 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001170 QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001171 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001172 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001173 pr_err("low threshold int read failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001174 goto fail;
1175 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001176 adc_tm->sensor[sensor_num].low_thr_notify = true;
1177 } else {
1178 /* Uses the thermal sysfs registered device to disable
1179 the corresponding low voltage threshold which
1180 is triggered by high temp */
1181 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001182 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001183 adc_tm->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001184 ADC_TM_TRIP_HIGH_WARM,
1185 THERMAL_TRIP_ACTIVATION_DISABLED);
1186 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001187 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001188 goto fail;
1189 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001190 }
1191 }
1192
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001193 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
1194 sensor_mask, false);
1195 if (rc < 0) {
1196 pr_err("multi meas disable for channel failed\n");
1197 goto fail;
1198 }
1199
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001200 rc = qpnp_adc_tm_enable_if_channel_meas();
1201 if (rc < 0) {
1202 pr_err("re-enabling measurement failed\n");
1203 return rc;
1204 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001205fail:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001206 mutex_unlock(&adc_tm->adc->adc_lock);
1207
1208 schedule_work(&adc_tm->sensor[sensor_num].work);
1209
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001210 return rc;
1211}
1212
1213static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
1214{
1215 int rc;
1216
1217 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001218 if (rc < 0)
1219 pr_err("adc-tm high thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001220
1221 return;
1222}
1223DECLARE_WORK(trigger_completion_adc_tm_high_thr_work,
1224 qpnp_adc_tm_high_thr_work);
1225
1226static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
1227{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001228 qpnp_adc_tm_disable();
1229
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001230 schedule_work(&trigger_completion_adc_tm_high_thr_work);
1231
1232 return IRQ_HANDLED;
1233}
1234
1235static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
1236{
1237 int rc;
1238
1239 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001240 if (rc < 0)
1241 pr_err("adc-tm low thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001242
1243 return;
1244}
1245DECLARE_WORK(trigger_completion_adc_tm_low_thr_work, qpnp_adc_tm_low_thr_work);
1246
1247static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
1248{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001249 qpnp_adc_tm_disable();
1250
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001251 schedule_work(&trigger_completion_adc_tm_low_thr_work);
1252
1253 return IRQ_HANDLED;
1254}
1255
1256static irqreturn_t qpnp_adc_tm_isr(int irq, void *dev_id)
1257{
1258 struct qpnp_adc_tm_drv *adc_tm = dev_id;
1259
1260 complete(&adc_tm->adc->adc_rslt_completion);
1261
1262 return IRQ_HANDLED;
1263}
1264
1265static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
1266 unsigned long *temp)
1267{
1268 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
1269 struct qpnp_vadc_result result;
1270 int rc = 0;
1271
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001272 rc = qpnp_vadc_read(adc_tm_sensor->vadc_channel_num, &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001273 if (rc)
1274 return rc;
1275
1276 *temp = result.physical;
1277
1278 return rc;
1279}
1280
1281static struct thermal_zone_device_ops qpnp_adc_tm_thermal_ops = {
1282 .get_temp = qpnp_adc_read_temp,
1283 .get_mode = qpnp_adc_tm_get_mode,
1284 .set_mode = qpnp_adc_tm_set_mode,
1285 .get_trip_type = qpnp_adc_tm_get_trip_type,
1286 .activate_trip_type = qpnp_adc_tm_activate_trip_type,
1287 .get_trip_temp = qpnp_adc_tm_get_trip_temp,
1288 .set_trip_temp = qpnp_adc_tm_set_trip_temp,
1289};
1290
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001291int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001292{
1293 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001294 uint32_t channel, dt_index = 0, scale_type = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001295 int rc = 0;
1296
1297 if (!adc_tm || !adc_tm->adc_tm_initialized)
1298 return -ENODEV;
1299
1300 if (param->threshold_notification == NULL) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001301 pr_err("No notification for high/low temp??\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001302 return -EINVAL;
1303 }
1304
1305 mutex_lock(&adc_tm->adc->adc_lock);
1306
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001307 channel = param->channel;
1308 while ((adc_tm->adc->adc_channels[dt_index].channel_num
1309 != channel) && (dt_index < adc_tm->max_channels_available))
1310 dt_index++;
1311
1312 if (dt_index >= adc_tm->max_channels_available) {
1313 pr_err("not a valid ADC_TM channel\n");
1314 rc = -EINVAL;
1315 goto fail_unlock;
1316 }
1317
1318 rc = qpnp_adc_tm_check_revision(
1319 adc_tm->sensor[dt_index].btm_channel_num);
1320 if (rc < 0)
1321 goto fail_unlock;
1322
1323 scale_type = adc_tm->adc->adc_channels[dt_index].adc_scale_fn;
1324 if (scale_type >= SCALE_RSCALE_NONE) {
1325 rc = -EBADF;
1326 goto fail_unlock;
1327 }
1328
1329 pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
1330 channel, scale_type, dt_index);
1331 adc_tm->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001332 adc_tm->adc->amux_prop->decimation =
1333 adc_tm->adc->adc_channels[channel].adc_decimation;
1334 adc_tm->adc->amux_prop->hw_settle_time =
1335 adc_tm->adc->adc_channels[channel].hw_settle_time;
1336 adc_tm->adc->amux_prop->fast_avg_setup =
1337 adc_tm->adc->adc_channels[channel].fast_avg_setup;
1338 adc_tm->adc->amux_prop->mode_sel =
1339 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
1340 adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
1341 ADC_MEAS1_INTERVAL_1S;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001342 adc_tm_rscale_fn[scale_type].chan(param,
1343 &adc_tm->adc->amux_prop->chan_prop->low_thr,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001344 &adc_tm->adc->amux_prop->chan_prop->high_thr);
1345 adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001346 adc_tm->sensor[dt_index].btm_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001347 adc_tm->adc->amux_prop->chan_prop->timer_select =
1348 ADC_MEAS_TIMER_SELECT1;
1349 adc_tm->adc->amux_prop->chan_prop->state_request =
1350 param->state_request;
1351 rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
1352 if (rc) {
1353 pr_err("adc-tm configure failed with %d\n", rc);
1354 goto fail_unlock;
1355 }
1356
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001357 adc_tm->sensor[dt_index].btm_param = param;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001358 adc_tm->sensor[dt_index].scale_type = scale_type;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001359
1360fail_unlock:
1361 mutex_unlock(&adc_tm->adc->adc_lock);
1362
1363 return rc;
1364}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001365EXPORT_SYMBOL(qpnp_adc_tm_channel_measure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001366
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001367int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001368{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001369 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1370 uint32_t channel, dt_index = 0, btm_chan_num;
1371 u8 sensor_mask = 0;
1372 int rc = 0;
1373
1374 if (!adc_tm || !adc_tm->adc_tm_initialized)
1375 return -ENODEV;
1376
1377 mutex_lock(&adc_tm->adc->adc_lock);
1378
1379 /* Disable bank */
1380 rc = qpnp_adc_tm_disable();
1381 if (rc < 0) {
1382 pr_err("adc-tm disable failed\n");
1383 goto fail;
1384 }
1385
1386 /* Check if a conversion is in progress */
1387 rc = qpnp_adc_tm_req_sts_check();
1388 if (rc < 0) {
1389 pr_err("adc-tm req_sts check failed\n");
1390 goto fail;
1391 }
1392
1393 channel = param->channel;
1394 while ((adc_tm->adc->adc_channels[dt_index].channel_num
1395 != channel) && (dt_index < adc_tm->max_channels_available))
1396 dt_index++;
1397
1398 if (dt_index >= adc_tm->max_channels_available) {
1399 pr_err("not a valid ADC_TMN channel\n");
1400 rc = -EINVAL;
1401 goto fail;
1402 }
1403
1404 btm_chan_num = adc_tm->sensor[dt_index].btm_channel_num;
1405 sensor_mask = 1 << adc_tm->sensor[dt_index].sensor_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001406
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001407 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001408 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001409 if (rc < 0) {
1410 pr_err("low threshold int write failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001411 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001412 }
1413
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001414 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001415 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001416 if (rc < 0) {
1417 pr_err("high threshold int enable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001418 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001419 }
1420
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001421 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001422 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001423 if (rc < 0) {
1424 pr_err("multi measurement en failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001425 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001426 }
1427
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001428 rc = qpnp_adc_tm_enable_if_channel_meas();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001429 if (rc < 0)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001430 pr_err("re-enabling measurement failed\n");
1431
1432fail:
1433 mutex_unlock(&adc_tm->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001434
1435 return rc;
1436}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001437EXPORT_SYMBOL(qpnp_adc_tm_disable_chan_meas);
1438
1439int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_btm_param *param)
1440{
1441 param->channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
1442 return qpnp_adc_tm_channel_measure(param);
1443}
1444EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001445
1446int32_t qpnp_adc_tm_usbid_end(void)
1447{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001448 struct qpnp_adc_tm_btm_param param;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001449
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001450 return qpnp_adc_tm_disable_chan_meas(&param);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001451}
1452EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
1453
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001454int32_t qpnp_adc_tm_is_ready(void)
1455{
1456 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1457
1458 if (!adc_tm || !adc_tm->adc_tm_initialized)
1459 return -EPROBE_DEFER;
1460 else
1461 return 0;
1462}
1463EXPORT_SYMBOL(qpnp_adc_tm_is_ready);
1464
1465static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
1466{
1467 struct device_node *node = spmi->dev.of_node, *child;
1468 struct qpnp_adc_tm_drv *adc_tm;
1469 struct qpnp_adc_drv *adc_qpnp;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001470 int32_t count_adc_channel_list = 0, rc, sen_idx = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001471 u8 thr_init = 0;
1472
1473 if (!node)
1474 return -EINVAL;
1475
1476 if (qpnp_adc_tm) {
1477 pr_err("adc-tm already in use\n");
1478 return -EBUSY;
1479 }
1480
1481 for_each_child_of_node(node, child)
1482 count_adc_channel_list++;
1483
1484 if (!count_adc_channel_list) {
1485 pr_err("No channel listing\n");
1486 return -EINVAL;
1487 }
1488
1489 adc_tm = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_drv) +
1490 (count_adc_channel_list *
1491 sizeof(struct qpnp_adc_tm_sensor)),
1492 GFP_KERNEL);
1493 if (!adc_tm) {
1494 dev_err(&spmi->dev, "Unable to allocate memory\n");
1495 return -ENOMEM;
1496 }
1497
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001498 qpnp_adc_tm = adc_tm;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001499 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1500 GFP_KERNEL);
1501 if (!adc_qpnp) {
1502 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001503 rc = -ENOMEM;
1504 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001505 }
1506
1507 adc_tm->adc = adc_qpnp;
1508
1509 rc = qpnp_adc_get_devicetree_data(spmi, adc_tm->adc);
1510 if (rc) {
1511 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001512 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001513 }
1514
1515 /* Register the ADC peripheral interrupt */
1516 adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
1517 NULL, "high-thr-en-set");
1518 if (adc_tm->adc->adc_high_thr_irq < 0) {
1519 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001520 rc = -ENXIO;
1521 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001522 }
1523
1524 adc_tm->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
1525 NULL, "low-thr-en-set");
1526 if (adc_tm->adc->adc_low_thr_irq < 0) {
1527 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001528 rc = -ENXIO;
1529 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001530 }
1531
1532 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_irq_eoc,
1533 qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
1534 "qpnp_adc_tm_interrupt", adc_tm);
1535 if (rc) {
1536 dev_err(&spmi->dev,
1537 "failed to request adc irq with error %d\n", rc);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001538 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001539 } else {
1540 enable_irq_wake(adc_tm->adc->adc_irq_eoc);
1541 }
1542
1543 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_high_thr_irq,
1544 qpnp_adc_tm_high_thr_isr,
1545 IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", adc_tm);
1546 if (rc) {
1547 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001548 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001549 } else {
1550 enable_irq_wake(adc_tm->adc->adc_high_thr_irq);
1551 }
1552
1553 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
1554 qpnp_adc_tm_low_thr_isr,
1555 IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
1556 if (rc) {
1557 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001558 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001559 } else {
1560 enable_irq_wake(adc_tm->adc->adc_low_thr_irq);
1561 }
1562
1563 for_each_child_of_node(node, child) {
1564 char name[25];
1565 int btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001566 bool thermal_node = false;
1567
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001568 rc = of_property_read_u32(child,
1569 "qcom,btm-channel-number", &btm_channel_num);
1570 if (rc) {
1571 pr_err("Invalid btm channel number\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001572 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001573 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001574 adc_tm->sensor[sen_idx].btm_channel_num = btm_channel_num;
1575 adc_tm->sensor[sen_idx].vadc_channel_num =
1576 adc_tm->adc->adc_channels[sen_idx].channel_num;
1577 adc_tm->sensor[sen_idx].sensor_num = sen_idx;
Siddartha Mohanadossb2795e42013-03-22 09:00:28 -07001578 pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
1579 adc_tm->adc->adc_channels[sen_idx].channel_num);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001580 if (thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001581 /* Register with the thermal zone */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001582 pr_debug("thermal node%x\n", btm_channel_num);
1583 adc_tm->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
1584 adc_tm->sensor[sen_idx].thermal_node = true;
1585 snprintf(name, sizeof(name),
1586 adc_tm->adc->adc_channels[sen_idx].name);
1587 adc_tm->sensor[sen_idx].meas_interval =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001588 QPNP_ADC_TM_MEAS_INTERVAL;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001589 adc_tm->sensor[sen_idx].low_thr =
1590 QPNP_ADC_TM_M0_LOW_THR;
1591 adc_tm->sensor[sen_idx].high_thr =
1592 QPNP_ADC_TM_M0_HIGH_THR;
1593 adc_tm->sensor[sen_idx].tz_dev =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001594 thermal_zone_device_register(name,
1595 ADC_TM_TRIP_NUM,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001596 &adc_tm->sensor[sen_idx],
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001597 &qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001598 if (IS_ERR(adc_tm->sensor[sen_idx].tz_dev))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001599 pr_err("thermal device register failed.\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001600 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001601 INIT_WORK(&adc_tm->sensor[sen_idx].work, notify_adc_tm_fn);
1602 sen_idx++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001603 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001604 adc_tm->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001605 dev_set_drvdata(&spmi->dev, adc_tm);
1606 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_HIGH_THR_INT_EN, thr_init);
1607 if (rc < 0) {
1608 pr_err("high thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001609 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001610 }
1611
1612 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_LOW_THR_INT_EN, thr_init);
1613 if (rc < 0) {
1614 pr_err("low thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001615 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001616 }
1617
1618 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MULTI_MEAS_EN, thr_init);
1619 if (rc < 0) {
1620 pr_err("multi meas en failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001621 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001622 }
1623
1624 adc_tm->adc_tm_initialized = true;
1625
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001626 pr_debug("OK\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001627 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001628fail:
Siddartha Mohanadoss32019b52012-12-23 17:05:45 -08001629 qpnp_adc_tm = NULL;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001630 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001631}
1632
1633static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
1634{
1635 struct qpnp_adc_tm_drv *adc_tm = dev_get_drvdata(&spmi->dev);
1636 struct device_node *node = spmi->dev.of_node;
1637 struct device_node *child;
1638 int i = 0;
1639
1640 for_each_child_of_node(node, child) {
1641 thermal_zone_device_unregister(adc_tm->sensor[i].tz_dev);
1642 i++;
1643 }
1644
1645 adc_tm->adc_tm_initialized = false;
1646 dev_set_drvdata(&spmi->dev, NULL);
1647
1648 return 0;
1649}
1650
1651static const struct of_device_id qpnp_adc_tm_match_table[] = {
1652 { .compatible = "qcom,qpnp-adc-tm" },
1653 {}
1654};
1655
1656static struct spmi_driver qpnp_adc_tm_driver = {
1657 .driver = {
1658 .name = "qcom,qpnp-adc-tm",
1659 .of_match_table = qpnp_adc_tm_match_table,
1660 },
1661 .probe = qpnp_adc_tm_probe,
1662 .remove = qpnp_adc_tm_remove,
1663};
1664
1665static int __init qpnp_adc_tm_init(void)
1666{
1667 return spmi_driver_register(&qpnp_adc_tm_driver);
1668}
1669module_init(qpnp_adc_tm_init);
1670
1671static void __exit qpnp_adc_tm_exit(void)
1672{
1673 spmi_driver_unregister(&qpnp_adc_tm_driver);
1674}
1675module_exit(qpnp_adc_tm_exit);
1676
1677MODULE_DESCRIPTION("QPNP PMIC ADC Threshold Monitoring driver");
1678MODULE_LICENSE("GPL v2");