blob: d848a186cc41eac630b33fd9d483ec1432a9eebc [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 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
94#define QPNP_M2_HIGH_THR_LSB 0x7b
95#define QPNP_M2_HIGH_THR_MSB 0x7c
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 Mohanadoss31f60962012-11-27 14:11:02 -0800172struct qpnp_adc_tm_sensor {
173 struct thermal_zone_device *tz_dev;
174 enum thermal_device_mode mode;
175 uint32_t sensor_num;
176 enum qpnp_adc_meas_timer_select timer_select;
177 uint32_t meas_interval;
178 uint32_t low_thr;
179 uint32_t high_thr;
180 uint32_t btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800181 uint32_t vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800182 struct work_struct work;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800183 struct qpnp_adc_tm_btm_param *btm_param;
184 bool thermal_node;
185 bool low_thr_notify;
186 bool high_thr_notify;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700187 uint32_t scale_type;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800188};
189
190struct qpnp_adc_tm_drv {
191 struct qpnp_adc_drv *adc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800192 bool adc_tm_initialized;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800193 int max_channels_available;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800194 struct qpnp_adc_tm_sensor sensor[0];
195};
196
197struct qpnp_adc_tm_drv *qpnp_adc_tm;
198
199struct qpnp_adc_tm_trip_reg_type {
200 uint16_t low_thr_lsb_addr;
201 uint16_t low_thr_msb_addr;
202 uint16_t high_thr_lsb_addr;
203 uint16_t high_thr_msb_addr;
204 u8 multi_meas_en;
205 u8 low_thr_int_chan_en;
206 u8 high_thr_int_chan_en;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800207 u8 meas_interval_ctl;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800208};
209
210static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
211 [QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
212 QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
213 QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800214 QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
215 QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800216 [QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
217 QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
218 QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800219 QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
220 QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800221 [QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
222 QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
223 QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800224 QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
225 QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800226 [QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
227 QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
228 QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800229 QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
230 QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800231 [QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
232 QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
233 QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800234 QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
235 QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
236 [QPNP_ADC_TM_M5_ADC_CH_SEL_CTL] = {QPNP_M5_LOW_THR_LSB,
237 QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
238 QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
239 QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
240 QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
241 [QPNP_ADC_TM_M6_ADC_CH_SEL_CTL] = {QPNP_M6_LOW_THR_LSB,
242 QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
243 QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
244 QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
245 QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
246 [QPNP_ADC_TM_M7_ADC_CH_SEL_CTL] = {QPNP_M7_LOW_THR_LSB,
247 QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
248 QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
249 QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
250 QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL},
251};
252
253static struct qpnp_adc_tm_reverse_scale_fn adc_tm_rscale_fn[] = {
254 [SCALE_R_VBATT] = {qpnp_adc_vbatt_rscaler},
255 [SCALE_RBATT_THERM] = {qpnp_adc_btm_scaler},
256 [SCALE_R_USB_ID] = {qpnp_adc_usb_scaler},
257 [SCALE_RPMIC_THERM] = {qpnp_adc_scale_millidegc_pmic_voltage_thr},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800258};
259
260static int32_t qpnp_adc_tm_read_reg(int16_t reg, u8 *data)
261{
262 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
263 int rc = 0;
264
265 rc = spmi_ext_register_readl(adc_tm->adc->spmi->ctrl,
266 adc_tm->adc->slave, (adc_tm->adc->offset + reg), data, 1);
267 if (rc < 0)
268 pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
269
270 return rc;
271}
272
273static int32_t qpnp_adc_tm_write_reg(int16_t reg, u8 data)
274{
275 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
276 int rc = 0;
277 u8 *buf;
278
279 buf = &data;
280
281 rc = spmi_ext_register_writel(adc_tm->adc->spmi->ctrl,
282 adc_tm->adc->slave, (adc_tm->adc->offset + reg), buf, 1);
283 if (rc < 0)
284 pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
285
286 return rc;
287}
288
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800289static int32_t qpnp_adc_tm_enable(void)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800290{
291 int rc = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800292 u8 data = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800293
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800294 data = QPNP_ADC_TM_EN;
295 rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
296 if (rc < 0)
297 pr_err("adc-tm enable failed\n");
298
299 return rc;
300}
301
302static int32_t qpnp_adc_tm_disable(void)
303{
304 u8 data = 0;
305 int rc = 0;
306
307 rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
308 if (rc < 0)
309 pr_err("adc-tm disable failed\n");
310
311 return rc;
312}
313
314static int32_t qpnp_adc_tm_enable_if_channel_meas(void)
315{
316 u8 adc_tm_meas_en = 0;
317 int rc = 0;
318
319 /* Check if a measurement request is still required */
320 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
321 &adc_tm_meas_en);
322 if (rc) {
323 pr_err("adc-tm-tm read status high failed with %d\n", rc);
324 return rc;
325 }
326
327 /* Enable only if there are pending measurement requests */
328 if (adc_tm_meas_en) {
329 qpnp_adc_tm_enable();
330
331 /* Request conversion */
332 rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800333 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800334 pr_err("adc-tm request conversion failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800335 return rc;
336 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800337 }
338
339 return rc;
340}
341
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800342static int32_t qpnp_adc_tm_req_sts_check(void)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800343{
344 u8 status1;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800345 int rc, count = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800346
347 /* The VADC_TM bank needs to be disabled for new conversion request */
348 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
349 if (rc) {
350 pr_err("adc-tm read status1 failed\n");
351 return rc;
352 }
353
354 /* Disable the bank if a conversion is occuring */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800355 while ((status1 & QPNP_STATUS1_REQ_STS) && (count < 5)) {
356 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800357 if (rc < 0)
358 pr_err("adc-tm disable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800359 /* Wait time is based on the optimum sampling rate
360 * and adding enough time buffer to account for ADC conversions
361 * occuring on different peripheral banks */
362 usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
363 count++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800364 }
365
366 return rc;
367}
368
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800369static int32_t qpnp_adc_tm_check_revision(uint32_t btm_chan_num)
370{
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -0700371 u8 rev, perph_subtype;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800372 int rc = 0;
373
374 rc = qpnp_adc_tm_read_reg(QPNP_REVISION3, &rev);
375 if (rc) {
376 pr_err("adc-tm revision read failed\n");
377 return rc;
378 }
379
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -0700380 rc = qpnp_adc_tm_read_reg(QPNP_PERPH_SUBTYPE, &perph_subtype);
381 if (rc) {
382 pr_err("adc-tm perph_subtype read failed\n");
383 return rc;
384 }
385
386 if (perph_subtype == QPNP_PERPH_TYPE2) {
387 if ((rev < QPNP_REVISION_EIGHT_CHANNEL_SUPPORT) &&
388 (btm_chan_num > QPNP_ADC_TM_M4_ADC_CH_SEL_CTL)) {
389 pr_debug("Version does not support more than 5 channels\n");
390 return -EINVAL;
391 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800392 }
393
394 return rc;
395}
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800396static int32_t qpnp_adc_tm_mode_select(u8 mode_ctl)
397{
398 int rc;
399
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800400 mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
401
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800402 /* VADC_BTM current sets mode to recurring measurements */
403 rc = qpnp_adc_tm_write_reg(QPNP_MODE_CTL, mode_ctl);
404 if (rc < 0)
405 pr_err("adc-tm write mode selection err\n");
406
407 return rc;
408}
409
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800410static int32_t qpnp_adc_tm_timer_interval_select(uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800411 struct qpnp_vadc_chan_properties *chan_prop)
412{
413 int rc;
414 u8 meas_interval_timer2 = 0;
415
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800416 /* Configure kernel clients to timer1 */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800417 switch (chan_prop->timer_select) {
418 case ADC_MEAS_TIMER_SELECT1:
419 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL,
420 chan_prop->meas_interval1);
421 if (rc < 0) {
422 pr_err("timer1 configure failed\n");
423 return rc;
424 }
425 break;
426 case ADC_MEAS_TIMER_SELECT2:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800427 /* Thermal channels uses timer2, default to 1 second */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800428 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
429 &meas_interval_timer2);
430 if (rc < 0) {
431 pr_err("timer2 configure read failed\n");
432 return rc;
433 }
434 meas_interval_timer2 |=
435 (chan_prop->meas_interval2 <<
436 QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
437 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
438 meas_interval_timer2);
439 if (rc < 0) {
440 pr_err("timer2 configure failed\n");
441 return rc;
442 }
443 break;
444 case ADC_MEAS_TIMER_SELECT3:
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800445 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
446 &meas_interval_timer2);
447 if (rc < 0) {
448 pr_err("timer3 read failed\n");
449 return rc;
450 }
451 chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
452 meas_interval_timer2 |= chan_prop->meas_interval2;
453 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
454 meas_interval_timer2);
455 if (rc < 0) {
456 pr_err("timer3 configure failed\n");
457 return rc;
458 }
459 break;
460 default:
461 pr_err("Invalid timer selection\n");
462 return -EINVAL;
463 }
464
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800465 /* Select the timer to use for the corresponding channel */
466 adc_tm_data[btm_chan].meas_interval_ctl = chan_prop->timer_select;
467
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800468 return rc;
469}
470
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700471static int32_t qpnp_adc_tm_reg_update(uint16_t addr,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800472 u8 mask, bool state)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800473{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800474 u8 reg_value = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800475 int rc = 0;
476
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800477 rc = qpnp_adc_tm_read_reg(addr, &reg_value);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800478 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800479 pr_err("read failed for addr:0x%x\n", addr);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800480 return rc;
481 }
482
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800483 reg_value = reg_value & ~mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800484 if (state)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800485 reg_value |= mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800486
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800487 pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n",
488 state, addr, reg_value, ~mask);
489 rc = qpnp_adc_tm_write_reg(addr, reg_value);
490 if (rc < 0) {
491 pr_err("write failed for addr:%x\n", addr);
492 return rc;
493 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800494
495 return rc;
496}
497
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700498static int32_t qpnp_adc_tm_thr_update(uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800499 struct qpnp_vadc_chan_properties *chan_prop)
500{
501 int rc = 0;
502
503 rc = qpnp_adc_tm_write_reg(
504 adc_tm_data[btm_chan].low_thr_lsb_addr,
505 QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
506 if (rc < 0) {
507 pr_err("low threshold lsb setting failed\n");
508 return rc;
509 }
510
511 rc = qpnp_adc_tm_write_reg(
512 adc_tm_data[btm_chan].low_thr_msb_addr,
513 QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
514 if (rc < 0) {
515 pr_err("low threshold msb setting failed\n");
516 return rc;
517 }
518
519 rc = qpnp_adc_tm_write_reg(
520 adc_tm_data[btm_chan].high_thr_lsb_addr,
521 QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
522 if (rc < 0) {
523 pr_err("high threshold lsb setting failed\n");
524 return rc;
525 }
526
527 rc = qpnp_adc_tm_write_reg(
528 adc_tm_data[btm_chan].high_thr_msb_addr,
529 QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
530 if (rc < 0)
531 pr_err("high threshold msb setting failed\n");
532
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700533 pr_debug("client requested low:%d and high:%d\n",
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800534 chan_prop->low_thr, chan_prop->high_thr);
535
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800536 return rc;
537}
538
539static int32_t qpnp_adc_tm_channel_configure(uint32_t btm_chan,
540 struct qpnp_vadc_chan_properties *chan_prop,
541 uint32_t amux_channel)
542{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800543 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
544 int rc = 0, i = 0, chan_idx = 0;
545 bool chan_found = false;
546 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800547
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800548 while (i < adc_tm->max_channels_available) {
549 if (adc_tm->sensor[i].btm_channel_num == btm_chan) {
550 chan_idx = i;
551 chan_found = true;
552 i++;
553 } else
554 i++;
555 }
556
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -0700557 if (!chan_found) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800558 pr_err("Channel not found\n");
559 return -EINVAL;
560 }
561
562 sensor_mask = 1 << chan_idx;
563 if (!adc_tm->sensor[chan_idx].thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800564 /* Update low and high notification thresholds */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700565 rc = qpnp_adc_tm_thr_update(btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800566 chan_prop);
567 if (rc < 0) {
568 pr_err("setting chan:%d threshold failed\n", btm_chan);
569 return rc;
570 }
571
572 if ((chan_prop->state_request ==
573 ADC_TM_LOW_THR_ENABLE) ||
574 (chan_prop->state_request ==
575 ADC_TM_HIGH_LOW_THR_ENABLE)) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800576 pr_debug("low sensor mask:%x with state:%d\n",
577 sensor_mask, chan_prop->state_request);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800578 /* Enable low threshold's interrupt */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700579 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800580 QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800581 if (rc < 0) {
582 pr_err("low thr enable err:%d\n", btm_chan);
583 return rc;
584 }
585 }
586
587 if ((chan_prop->state_request ==
588 ADC_TM_HIGH_THR_ENABLE) ||
589 (chan_prop->state_request ==
590 ADC_TM_HIGH_LOW_THR_ENABLE)) {
591 /* Enable high threshold's interrupt */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800592 pr_debug("high sensor mask:%x\n", sensor_mask);
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_HIGH_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800595 if (rc < 0) {
596 pr_err("high thr enable err:%d\n", btm_chan);
597 return rc;
598 }
599 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800600 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800601
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800602 /* Enable corresponding BTM channel measurement */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700603 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800604 QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
605 if (rc < 0) {
606 pr_err("multi measurement en failed\n");
607 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800608 }
609
610 return rc;
611}
612
613static int32_t qpnp_adc_tm_configure(
614 struct qpnp_adc_amux_properties *chan_prop)
615{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800616 u8 decimation = 0, op_cntrl = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800617 int rc = 0;
618 uint32_t btm_chan = 0;
619
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800620 /* Disable bank */
621 rc = qpnp_adc_tm_disable();
622 if (rc)
623 return rc;
624
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800625 /* Check if a conversion is in progress */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800626 rc = qpnp_adc_tm_req_sts_check();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800627 if (rc < 0) {
628 pr_err("adc-tm req_sts check failed\n");
629 return rc;
630 }
631
632 /* Set measurement in recurring mode */
633 rc = qpnp_adc_tm_mode_select(chan_prop->mode_sel);
634 if (rc < 0) {
635 pr_err("adc-tm mode select failed\n");
636 return rc;
637 }
638
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800639 /* Configure AMUX channel select for the corresponding BTM channel*/
640 btm_chan = chan_prop->chan_prop->tm_channel_select;
641 rc = qpnp_adc_tm_write_reg(btm_chan, chan_prop->amux_channel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800642 if (rc < 0) {
643 pr_err("adc-tm channel selection err\n");
644 return rc;
645 }
646
647 /* Digital paramater setup */
648 decimation |= chan_prop->decimation <<
649 QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
650 rc = qpnp_adc_tm_write_reg(QPNP_ADC_DIG_PARAM, decimation);
651 if (rc < 0) {
652 pr_err("adc-tm digital parameter setup err\n");
653 return rc;
654 }
655
656 /* Hardware setting time */
657 rc = qpnp_adc_tm_write_reg(QPNP_HW_SETTLE_DELAY,
658 chan_prop->hw_settle_time);
659 if (rc < 0) {
660 pr_err("adc-tm hw settling time setup err\n");
661 return rc;
662 }
663
664 /* Fast averaging setup */
665 rc = qpnp_adc_tm_write_reg(QPNP_FAST_AVG_CTL,
666 chan_prop->fast_avg_setup);
667 if (rc < 0) {
668 pr_err("adc-tm fast-avg setup err\n");
669 return rc;
670 }
671
672 /* Measurement interval setup */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800673 rc = qpnp_adc_tm_timer_interval_select(btm_chan,
674 chan_prop->chan_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800675 if (rc < 0) {
676 pr_err("adc-tm timer select failed\n");
677 return rc;
678 }
679
680 /* Channel configuration setup */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800681 rc = qpnp_adc_tm_channel_configure(btm_chan, chan_prop->chan_prop,
682 chan_prop->amux_channel);
683 if (rc < 0) {
684 pr_err("adc-tm channel configure failed\n");
685 return rc;
686 }
687
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800688 /* Recurring interval measurement enable */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800689 rc = qpnp_adc_tm_read_reg(QPNP_ADC_MEAS_INTERVAL_OP_CTL, &op_cntrl);
690 op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700691 rc = qpnp_adc_tm_reg_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800692 op_cntrl, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800693 if (rc < 0) {
694 pr_err("adc-tm meas interval op configure failed\n");
695 return rc;
696 }
697
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800698 /* Enable bank */
699 rc = qpnp_adc_tm_enable();
700 if (rc)
701 return rc;
702
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800703 /* Request conversion */
704 rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
705 if (rc < 0) {
706 pr_err("adc-tm request conversion failed\n");
707 return rc;
708 }
709
710 return 0;
711}
712
713static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
714 enum thermal_device_mode *mode)
715{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800716 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800717
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800718 if (!adc_tm_sensor || qpnp_adc_tm_check_revision(
719 adc_tm_sensor->btm_channel_num) || !mode)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800720 return -EINVAL;
721
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800722 *mode = adc_tm_sensor->mode;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800723
724 return 0;
725}
726
727static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
728 enum thermal_device_mode mode)
729{
730 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
731 struct qpnp_adc_tm_drv *adc_drv = qpnp_adc_tm;
732 int rc = 0, channel;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800733 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800734
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800735 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800736 return -EINVAL;
737
738 if (mode == THERMAL_DEVICE_ENABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800739 adc_drv->adc->amux_prop->amux_channel =
740 adc_tm->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800741 channel = adc_tm->sensor_num;
742 adc_drv->adc->amux_prop->decimation =
743 adc_drv->adc->adc_channels[channel].adc_decimation;
744 adc_drv->adc->amux_prop->hw_settle_time =
745 adc_drv->adc->adc_channels[channel].hw_settle_time;
746 adc_drv->adc->amux_prop->fast_avg_setup =
747 adc_drv->adc->adc_channels[channel].fast_avg_setup;
748 adc_drv->adc->amux_prop->mode_sel =
749 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
750 adc_drv->adc->amux_prop->chan_prop->timer_select =
751 ADC_MEAS_TIMER_SELECT1;
752 adc_drv->adc->amux_prop->chan_prop->meas_interval1 =
753 ADC_MEAS1_INTERVAL_1S;
754 adc_drv->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
755 adc_drv->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
756 adc_drv->adc->amux_prop->chan_prop->tm_channel_select =
757 adc_tm->btm_channel_num;
758
759 rc = qpnp_adc_tm_configure(adc_drv->adc->amux_prop);
760 if (rc) {
761 pr_err("adc-tm tm configure failed with %d\n", rc);
762 return -EINVAL;
763 }
764 } else if (mode == THERMAL_DEVICE_DISABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800765 sensor_mask = 1 << adc_tm->sensor_num;
766 /* Disable bank */
767 rc = qpnp_adc_tm_disable();
768 if (rc < 0) {
769 pr_err("adc-tm disable failed\n");
770 return rc;
771 }
772
773 /* Check if a conversion is in progress */
774 rc = qpnp_adc_tm_req_sts_check();
775 if (rc < 0) {
776 pr_err("adc-tm req_sts check failed\n");
777 return rc;
778 }
779
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700780 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800781 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800782 if (rc < 0) {
783 pr_err("multi measurement update failed\n");
784 return rc;
785 }
786
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800787 rc = qpnp_adc_tm_enable_if_channel_meas();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800788 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800789 pr_err("re-enabling measurement failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800790 return rc;
791 }
792 }
793
794 adc_tm->mode = mode;
795
796 return 0;
797}
798
799static int qpnp_adc_tm_get_trip_type(struct thermal_zone_device *thermal,
800 int trip, enum thermal_trip_type *type)
801{
802 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
803
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800804 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num)
805 || !type || type < 0)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800806 return -EINVAL;
807
808 switch (trip) {
809 case ADC_TM_TRIP_HIGH_WARM:
810 *type = THERMAL_TRIP_CONFIGURABLE_HI;
811 break;
812 case ADC_TM_TRIP_LOW_COOL:
813 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
814 break;
815 default:
816 return -EINVAL;
817 }
818
819 return 0;
820}
821
822static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
823 int trip, unsigned long *temp)
824{
825 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
826 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
827 int64_t result = 0;
828 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
829 unsigned int reg, rc = 0, btm_channel_num;
830 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
831 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
832
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800833 if (!adc_tm || qpnp_adc_tm_check_revision(
834 adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800835 return -EINVAL;
836
837 btm_channel_num = adc_tm_sensor->btm_channel_num;
838 reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
839 reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
840 reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
841 reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
842
843 switch (trip) {
844 case ADC_TM_TRIP_HIGH_WARM:
845 rc = qpnp_adc_tm_read_reg(reg_low_thr_lsb, &trip_warm_thr0);
846 if (rc) {
847 pr_err("adc-tm low_thr_lsb err\n");
848 return rc;
849 }
850
851 rc = qpnp_adc_tm_read_reg(reg_low_thr_msb, &trip_warm_thr1);
852 if (rc) {
853 pr_err("adc-tm low_thr_msb err\n");
854 return rc;
855 }
856 reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
857 break;
858 case ADC_TM_TRIP_LOW_COOL:
859 rc = qpnp_adc_tm_read_reg(reg_high_thr_lsb, &trip_cool_thr0);
860 if (rc) {
861 pr_err("adc-tm_tm high_thr_lsb err\n");
862 return rc;
863 }
864
865 rc = qpnp_adc_tm_read_reg(reg_high_thr_msb, &trip_cool_thr1);
866 if (rc) {
867 pr_err("adc-tm_tm high_thr_lsb err\n");
868 return rc;
869 }
870 reg = (trip_cool_thr1 << 8) | trip_cool_thr0;
871 break;
872 default:
873 return -EINVAL;
874 }
875
876 rc = qpnp_adc_tm_scale_voltage_therm_pu2(reg, &result);
877 if (rc < 0) {
878 pr_err("Failed to lookup the therm thresholds\n");
879 return rc;
880 }
881
882 *temp = result;
883
884 return 0;
885}
886
887static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
888 int trip, long temp)
889{
890 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
891 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
892 struct qpnp_adc_tm_config tm_config;
893 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
894 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
895 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
896 int rc = 0, btm_channel_num;
897
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800898 if (!adc_tm || qpnp_adc_tm_check_revision(
899 adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800900 return -EINVAL;
901
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800902 tm_config.channel = adc_tm_sensor->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800903 switch (trip) {
904 case ADC_TM_TRIP_HIGH_WARM:
905 tm_config.high_thr_temp = temp;
906 break;
907 case ADC_TM_TRIP_LOW_COOL:
908 tm_config.low_thr_temp = temp;
909 break;
910 default:
911 return -EINVAL;
912 }
913
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800914 pr_debug("requested a high - %d and low - %d with trip - %d\n",
915 tm_config.high_thr_temp, tm_config.low_thr_temp, trip);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800916 rc = qpnp_adc_tm_scale_therm_voltage_pu2(&tm_config);
917 if (rc < 0) {
918 pr_err("Failed to lookup the adc-tm thresholds\n");
919 return rc;
920 }
921
922 trip_warm_thr0 = ((tm_config.low_thr_voltage << 24) >> 24);
923 trip_warm_thr1 = ((tm_config.low_thr_voltage << 16) >> 24);
924 trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
925 trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
926
927 btm_channel_num = adc_tm_sensor->btm_channel_num;
928 reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
929 reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
930 reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
931 reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
932
933 switch (trip) {
934 case ADC_TM_TRIP_HIGH_WARM:
935 rc = qpnp_adc_tm_write_reg(reg_low_thr_lsb, trip_cool_thr0);
936 if (rc) {
937 pr_err("adc-tm_tm read threshold err\n");
938 return rc;
939 }
940
941 rc = qpnp_adc_tm_write_reg(reg_low_thr_msb, trip_cool_thr1);
942 if (rc) {
943 pr_err("adc-tm_tm read threshold err\n");
944 return rc;
945 }
946 adc_tm_sensor->low_thr = tm_config.high_thr_voltage;
947 break;
948 case ADC_TM_TRIP_LOW_COOL:
949 rc = qpnp_adc_tm_write_reg(reg_high_thr_lsb, trip_warm_thr0);
950 if (rc) {
951 pr_err("adc-tm_tm read threshold err\n");
952 return rc;
953 }
954
955 rc = qpnp_adc_tm_write_reg(reg_high_thr_msb, trip_warm_thr1);
956 if (rc) {
957 pr_err("adc-tm_tm read threshold err\n");
958 return rc;
959 }
960 adc_tm_sensor->high_thr = tm_config.low_thr_voltage;
961 break;
962 default:
963 return -EINVAL;
964 }
965
966 return 0;
967}
968
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700969static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
970{
971 /* Battery therm's warm temperature translates to low voltage */
972 if (adc_tm->low_thr_notify) {
973 /* HIGH_STATE = WARM_TEMP for battery client */
974 adc_tm->btm_param->threshold_notification(
975 ADC_TM_WARM_STATE, adc_tm->btm_param->btm_ctx);
976 adc_tm->low_thr_notify = false;
977 }
978
979 /* Battery therm's cool temperature translates to high voltage */
980 if (adc_tm->high_thr_notify) {
981 /* LOW_STATE = COOL_TEMP for battery client */
982 adc_tm->btm_param->threshold_notification(
983 ADC_TM_COOL_STATE, adc_tm->btm_param->btm_ctx);
984 adc_tm->high_thr_notify = false;
985 }
986
987 return;
988}
989
990static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
991{
992 /* For non batt therm clients */
993 if (adc_tm->low_thr_notify) {
994 pr_debug("notify kernel with low state\n");
995 adc_tm->btm_param->threshold_notification(
996 ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
997 adc_tm->low_thr_notify = false;
998 }
999
1000 if (adc_tm->high_thr_notify) {
1001 pr_debug("notify kernel with high state\n");
1002 adc_tm->btm_param->threshold_notification(
1003 ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
1004 adc_tm->high_thr_notify = false;
1005 }
1006
1007 return;
1008}
1009
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001010static void notify_adc_tm_fn(struct work_struct *work)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001011{
1012 struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
1013 struct qpnp_adc_tm_sensor, work);
1014
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001015 if (adc_tm->thermal_node) {
1016 sysfs_notify(&adc_tm->tz_dev->device.kobj,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001017 NULL, "btm");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001018 pr_debug("notifying uspace client\n");
1019 } else {
1020 if (adc_tm->btm_param->threshold_notification != NULL) {
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001021 if (adc_tm->scale_type == SCALE_RBATT_THERM)
1022 notify_battery_therm(adc_tm);
1023 else
1024 notify_clients(adc_tm);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001025 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001026 }
1027
1028 return;
1029}
1030
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001031static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
1032 int trip, enum thermal_trip_activation_mode mode)
1033{
1034 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001035 int rc = 0, sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001036 u8 thr_int_en = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001037 bool state = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001038
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001039 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001040 return -EINVAL;
1041
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001042 if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
1043 state = true;
1044
1045 sensor_mask = 1 << adc_tm->sensor_num;
1046
1047 pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
1048
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001049 switch (trip) {
1050 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001051 /* low_thr (lower voltage) for higher temp */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001052 thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
1053 low_thr_int_chan_en;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001054 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001055 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001056 if (rc)
1057 pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
1058 break;
1059 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001060 /* high_thr (higher voltage) for cooler temp */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001061 thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
1062 high_thr_int_chan_en;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001063 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001064 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001065 if (rc)
1066 pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
1067 break;
1068 default:
1069 return -EINVAL;
1070 }
1071
1072 return rc;
1073}
1074
1075static int qpnp_adc_tm_read_status(void)
1076{
1077 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1078 u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
1079 u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001080 u8 sensor_mask = 0;
1081 int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0, btm_chan_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001082
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001083 if (!adc_tm || !adc_tm->adc_tm_initialized)
1084 return -ENODEV;
1085
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001086 mutex_lock(&adc_tm->adc->adc_lock);
1087
1088 rc = qpnp_adc_tm_req_sts_check();
1089 if (rc) {
1090 pr_err("adc-tm-tm req sts check failed with %d\n", rc);
1091 goto fail;
1092 }
1093
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001094 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW, &status_low);
1095 if (rc) {
1096 pr_err("adc-tm-tm read status low failed with %d\n", rc);
1097 goto fail;
1098 }
1099
1100 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH, &status_high);
1101 if (rc) {
1102 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1103 goto fail;
1104 }
1105
1106 /* Check which interrupt threshold is lower and measure against the
1107 * enabled channel */
1108 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
1109 &qpnp_adc_tm_meas_en);
1110 if (rc) {
1111 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1112 goto fail;
1113 }
1114
1115 adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
1116 adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
1117
1118 if (adc_tm_high_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001119 sensor_notify_num = adc_tm_high_enable;
1120 while (i < adc_tm->max_channels_available) {
1121 if ((sensor_notify_num & 0x1) == 1)
1122 sensor_num = i;
1123 sensor_notify_num >>= 1;
1124 i++;
1125 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001126
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001127 btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
1128 pr_debug("high:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1129 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1130 qpnp_adc_tm_meas_en);
1131 if (!adc_tm->sensor[sensor_num].thermal_node) {
1132 /* For non thermal registered clients
1133 such as usb_id, vbatt, pmic_therm */
1134 sensor_mask = 1 << sensor_num;
1135 pr_debug("non thermal node - mask:%x\n", sensor_mask);
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001136 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001137 QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001138 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001139 if (rc < 0) {
1140 pr_err("high threshold int read failed\n");
1141 goto fail;
1142 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001143 adc_tm->sensor[sensor_num].high_thr_notify = true;
1144 } else {
1145 /* Uses the thermal sysfs registered device to disable
1146 the corresponding high voltage threshold which
1147 is triggered by low temp */
1148 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001149 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001150 adc_tm->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001151 ADC_TM_TRIP_LOW_COOL,
1152 THERMAL_TRIP_ACTIVATION_DISABLED);
1153 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001154 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001155 goto fail;
1156 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001157 }
1158 }
1159
1160 if (adc_tm_low_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001161 sensor_notify_num = adc_tm_low_enable;
1162 i = 0;
1163 while (i < adc_tm->max_channels_available) {
1164 if ((sensor_notify_num & 0x1) == 1)
1165 sensor_num = i;
1166 sensor_notify_num >>= 1;
1167 i++;
1168 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001169
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001170 btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
1171 pr_debug("low:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1172 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1173 qpnp_adc_tm_meas_en);
1174 if (!adc_tm->sensor[sensor_num].thermal_node) {
1175 /* For non thermal registered clients
1176 such as usb_id, vbatt, pmic_therm */
1177 pr_debug("non thermal node - mask:%x\n", sensor_mask);
1178 sensor_mask = 1 << sensor_num;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001179 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001180 QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001181 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001182 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001183 pr_err("low threshold int read failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001184 goto fail;
1185 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001186 adc_tm->sensor[sensor_num].low_thr_notify = true;
1187 } else {
1188 /* Uses the thermal sysfs registered device to disable
1189 the corresponding low voltage threshold which
1190 is triggered by high temp */
1191 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001192 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001193 adc_tm->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001194 ADC_TM_TRIP_HIGH_WARM,
1195 THERMAL_TRIP_ACTIVATION_DISABLED);
1196 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001197 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001198 goto fail;
1199 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001200 }
1201 }
1202
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001203 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
1204 sensor_mask, false);
1205 if (rc < 0) {
1206 pr_err("multi meas disable for channel failed\n");
1207 goto fail;
1208 }
1209
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001210 rc = qpnp_adc_tm_enable_if_channel_meas();
1211 if (rc < 0) {
1212 pr_err("re-enabling measurement failed\n");
1213 return rc;
1214 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001215fail:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001216 mutex_unlock(&adc_tm->adc->adc_lock);
1217
1218 schedule_work(&adc_tm->sensor[sensor_num].work);
1219
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001220 return rc;
1221}
1222
1223static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
1224{
1225 int rc;
1226
1227 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001228 if (rc < 0)
1229 pr_err("adc-tm high thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001230
1231 return;
1232}
1233DECLARE_WORK(trigger_completion_adc_tm_high_thr_work,
1234 qpnp_adc_tm_high_thr_work);
1235
1236static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
1237{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001238 qpnp_adc_tm_disable();
1239
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001240 schedule_work(&trigger_completion_adc_tm_high_thr_work);
1241
1242 return IRQ_HANDLED;
1243}
1244
1245static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
1246{
1247 int rc;
1248
1249 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001250 if (rc < 0)
1251 pr_err("adc-tm low thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001252
1253 return;
1254}
1255DECLARE_WORK(trigger_completion_adc_tm_low_thr_work, qpnp_adc_tm_low_thr_work);
1256
1257static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
1258{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001259 qpnp_adc_tm_disable();
1260
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001261 schedule_work(&trigger_completion_adc_tm_low_thr_work);
1262
1263 return IRQ_HANDLED;
1264}
1265
1266static irqreturn_t qpnp_adc_tm_isr(int irq, void *dev_id)
1267{
1268 struct qpnp_adc_tm_drv *adc_tm = dev_id;
1269
1270 complete(&adc_tm->adc->adc_rslt_completion);
1271
1272 return IRQ_HANDLED;
1273}
1274
1275static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
1276 unsigned long *temp)
1277{
1278 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
1279 struct qpnp_vadc_result result;
1280 int rc = 0;
1281
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001282 rc = qpnp_vadc_read(adc_tm_sensor->vadc_channel_num, &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001283 if (rc)
1284 return rc;
1285
1286 *temp = result.physical;
1287
1288 return rc;
1289}
1290
1291static struct thermal_zone_device_ops qpnp_adc_tm_thermal_ops = {
1292 .get_temp = qpnp_adc_read_temp,
1293 .get_mode = qpnp_adc_tm_get_mode,
1294 .set_mode = qpnp_adc_tm_set_mode,
1295 .get_trip_type = qpnp_adc_tm_get_trip_type,
1296 .activate_trip_type = qpnp_adc_tm_activate_trip_type,
1297 .get_trip_temp = qpnp_adc_tm_get_trip_temp,
1298 .set_trip_temp = qpnp_adc_tm_set_trip_temp,
1299};
1300
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001301int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001302{
1303 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001304 uint32_t channel, dt_index = 0, scale_type = 0;
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001305 int rc = 0, i = 0;
1306 bool chan_found = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001307
1308 if (!adc_tm || !adc_tm->adc_tm_initialized)
1309 return -ENODEV;
1310
1311 if (param->threshold_notification == NULL) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001312 pr_err("No notification for high/low temp??\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001313 return -EINVAL;
1314 }
1315
1316 mutex_lock(&adc_tm->adc->adc_lock);
1317
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001318 channel = param->channel;
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001319 while (i < adc_tm->max_channels_available) {
1320 if (adc_tm->adc->adc_channels[i].channel_num ==
1321 channel) {
1322 dt_index = i;
1323 chan_found = true;
1324 i++;
1325 } else
1326 i++;
1327 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001328
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001329 if (!chan_found) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001330 pr_err("not a valid ADC_TM channel\n");
1331 rc = -EINVAL;
1332 goto fail_unlock;
1333 }
1334
1335 rc = qpnp_adc_tm_check_revision(
1336 adc_tm->sensor[dt_index].btm_channel_num);
1337 if (rc < 0)
1338 goto fail_unlock;
1339
1340 scale_type = adc_tm->adc->adc_channels[dt_index].adc_scale_fn;
1341 if (scale_type >= SCALE_RSCALE_NONE) {
1342 rc = -EBADF;
1343 goto fail_unlock;
1344 }
1345
1346 pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
1347 channel, scale_type, dt_index);
1348 adc_tm->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001349 adc_tm->adc->amux_prop->decimation =
Siddartha Mohanadossf4cdd132013-03-27 19:38:34 -07001350 adc_tm->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001351 adc_tm->adc->amux_prop->hw_settle_time =
Siddartha Mohanadossf4cdd132013-03-27 19:38:34 -07001352 adc_tm->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001353 adc_tm->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadossf4cdd132013-03-27 19:38:34 -07001354 adc_tm->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001355 adc_tm->adc->amux_prop->mode_sel =
1356 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
1357 adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
1358 ADC_MEAS1_INTERVAL_1S;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001359 adc_tm_rscale_fn[scale_type].chan(param,
1360 &adc_tm->adc->amux_prop->chan_prop->low_thr,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001361 &adc_tm->adc->amux_prop->chan_prop->high_thr);
1362 adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001363 adc_tm->sensor[dt_index].btm_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001364 adc_tm->adc->amux_prop->chan_prop->timer_select =
1365 ADC_MEAS_TIMER_SELECT1;
1366 adc_tm->adc->amux_prop->chan_prop->state_request =
1367 param->state_request;
1368 rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
1369 if (rc) {
1370 pr_err("adc-tm configure failed with %d\n", rc);
1371 goto fail_unlock;
1372 }
1373
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001374 adc_tm->sensor[dt_index].btm_param = param;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001375 adc_tm->sensor[dt_index].scale_type = scale_type;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001376
1377fail_unlock:
1378 mutex_unlock(&adc_tm->adc->adc_lock);
1379
1380 return rc;
1381}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001382EXPORT_SYMBOL(qpnp_adc_tm_channel_measure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001383
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001384int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001385{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001386 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1387 uint32_t channel, dt_index = 0, btm_chan_num;
1388 u8 sensor_mask = 0;
1389 int rc = 0;
1390
1391 if (!adc_tm || !adc_tm->adc_tm_initialized)
1392 return -ENODEV;
1393
1394 mutex_lock(&adc_tm->adc->adc_lock);
1395
1396 /* Disable bank */
1397 rc = qpnp_adc_tm_disable();
1398 if (rc < 0) {
1399 pr_err("adc-tm disable failed\n");
1400 goto fail;
1401 }
1402
1403 /* Check if a conversion is in progress */
1404 rc = qpnp_adc_tm_req_sts_check();
1405 if (rc < 0) {
1406 pr_err("adc-tm req_sts check failed\n");
1407 goto fail;
1408 }
1409
1410 channel = param->channel;
1411 while ((adc_tm->adc->adc_channels[dt_index].channel_num
1412 != channel) && (dt_index < adc_tm->max_channels_available))
1413 dt_index++;
1414
1415 if (dt_index >= adc_tm->max_channels_available) {
1416 pr_err("not a valid ADC_TMN channel\n");
1417 rc = -EINVAL;
1418 goto fail;
1419 }
1420
1421 btm_chan_num = adc_tm->sensor[dt_index].btm_channel_num;
1422 sensor_mask = 1 << adc_tm->sensor[dt_index].sensor_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001423
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001424 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001425 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001426 if (rc < 0) {
1427 pr_err("low threshold int write failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001428 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001429 }
1430
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001431 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001432 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001433 if (rc < 0) {
1434 pr_err("high threshold int enable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001435 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001436 }
1437
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001438 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001439 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001440 if (rc < 0) {
1441 pr_err("multi measurement en failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001442 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001443 }
1444
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001445 rc = qpnp_adc_tm_enable_if_channel_meas();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001446 if (rc < 0)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001447 pr_err("re-enabling measurement failed\n");
1448
1449fail:
1450 mutex_unlock(&adc_tm->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001451
1452 return rc;
1453}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001454EXPORT_SYMBOL(qpnp_adc_tm_disable_chan_meas);
1455
1456int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_btm_param *param)
1457{
1458 param->channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
1459 return qpnp_adc_tm_channel_measure(param);
1460}
1461EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001462
1463int32_t qpnp_adc_tm_usbid_end(void)
1464{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001465 struct qpnp_adc_tm_btm_param param;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001466
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001467 return qpnp_adc_tm_disable_chan_meas(&param);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001468}
1469EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
1470
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001471int32_t qpnp_adc_tm_is_ready(void)
1472{
1473 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1474
1475 if (!adc_tm || !adc_tm->adc_tm_initialized)
1476 return -EPROBE_DEFER;
1477 else
1478 return 0;
1479}
1480EXPORT_SYMBOL(qpnp_adc_tm_is_ready);
1481
1482static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
1483{
1484 struct device_node *node = spmi->dev.of_node, *child;
1485 struct qpnp_adc_tm_drv *adc_tm;
1486 struct qpnp_adc_drv *adc_qpnp;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001487 int32_t count_adc_channel_list = 0, rc, sen_idx = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001488 u8 thr_init = 0;
1489
1490 if (!node)
1491 return -EINVAL;
1492
1493 if (qpnp_adc_tm) {
1494 pr_err("adc-tm already in use\n");
1495 return -EBUSY;
1496 }
1497
1498 for_each_child_of_node(node, child)
1499 count_adc_channel_list++;
1500
1501 if (!count_adc_channel_list) {
1502 pr_err("No channel listing\n");
1503 return -EINVAL;
1504 }
1505
1506 adc_tm = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_drv) +
1507 (count_adc_channel_list *
1508 sizeof(struct qpnp_adc_tm_sensor)),
1509 GFP_KERNEL);
1510 if (!adc_tm) {
1511 dev_err(&spmi->dev, "Unable to allocate memory\n");
1512 return -ENOMEM;
1513 }
1514
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001515 qpnp_adc_tm = adc_tm;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001516 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1517 GFP_KERNEL);
1518 if (!adc_qpnp) {
1519 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001520 rc = -ENOMEM;
1521 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001522 }
1523
1524 adc_tm->adc = adc_qpnp;
1525
1526 rc = qpnp_adc_get_devicetree_data(spmi, adc_tm->adc);
1527 if (rc) {
1528 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001529 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001530 }
1531
1532 /* Register the ADC peripheral interrupt */
1533 adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
1534 NULL, "high-thr-en-set");
1535 if (adc_tm->adc->adc_high_thr_irq < 0) {
1536 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001537 rc = -ENXIO;
1538 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001539 }
1540
1541 adc_tm->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
1542 NULL, "low-thr-en-set");
1543 if (adc_tm->adc->adc_low_thr_irq < 0) {
1544 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001545 rc = -ENXIO;
1546 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001547 }
1548
1549 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_irq_eoc,
1550 qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
1551 "qpnp_adc_tm_interrupt", adc_tm);
1552 if (rc) {
1553 dev_err(&spmi->dev,
1554 "failed to request adc irq with error %d\n", rc);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001555 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001556 } else {
1557 enable_irq_wake(adc_tm->adc->adc_irq_eoc);
1558 }
1559
1560 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_high_thr_irq,
1561 qpnp_adc_tm_high_thr_isr,
1562 IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", adc_tm);
1563 if (rc) {
1564 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001565 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001566 } else {
1567 enable_irq_wake(adc_tm->adc->adc_high_thr_irq);
1568 }
1569
1570 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
1571 qpnp_adc_tm_low_thr_isr,
1572 IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
1573 if (rc) {
1574 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001575 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001576 } else {
1577 enable_irq_wake(adc_tm->adc->adc_low_thr_irq);
1578 }
1579
1580 for_each_child_of_node(node, child) {
1581 char name[25];
1582 int btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001583 bool thermal_node = false;
1584
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001585 rc = of_property_read_u32(child,
1586 "qcom,btm-channel-number", &btm_channel_num);
1587 if (rc) {
1588 pr_err("Invalid btm channel number\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001589 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001590 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001591 adc_tm->sensor[sen_idx].btm_channel_num = btm_channel_num;
1592 adc_tm->sensor[sen_idx].vadc_channel_num =
1593 adc_tm->adc->adc_channels[sen_idx].channel_num;
1594 adc_tm->sensor[sen_idx].sensor_num = sen_idx;
Siddartha Mohanadossb2795e42013-03-22 09:00:28 -07001595 pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
1596 adc_tm->adc->adc_channels[sen_idx].channel_num);
Siddartha Mohanadossea65d9e2013-04-16 18:26:39 -07001597 thermal_node = of_property_read_bool(child,
1598 "qcom,thermal-node");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001599 if (thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001600 /* Register with the thermal zone */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001601 pr_debug("thermal node%x\n", btm_channel_num);
1602 adc_tm->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
1603 adc_tm->sensor[sen_idx].thermal_node = true;
1604 snprintf(name, sizeof(name),
1605 adc_tm->adc->adc_channels[sen_idx].name);
1606 adc_tm->sensor[sen_idx].meas_interval =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001607 QPNP_ADC_TM_MEAS_INTERVAL;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001608 adc_tm->sensor[sen_idx].low_thr =
1609 QPNP_ADC_TM_M0_LOW_THR;
1610 adc_tm->sensor[sen_idx].high_thr =
1611 QPNP_ADC_TM_M0_HIGH_THR;
1612 adc_tm->sensor[sen_idx].tz_dev =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001613 thermal_zone_device_register(name,
1614 ADC_TM_TRIP_NUM,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001615 &adc_tm->sensor[sen_idx],
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001616 &qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001617 if (IS_ERR(adc_tm->sensor[sen_idx].tz_dev))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001618 pr_err("thermal device register failed.\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001619 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001620 INIT_WORK(&adc_tm->sensor[sen_idx].work, notify_adc_tm_fn);
1621 sen_idx++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001622 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001623 adc_tm->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001624 dev_set_drvdata(&spmi->dev, adc_tm);
1625 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_HIGH_THR_INT_EN, thr_init);
1626 if (rc < 0) {
1627 pr_err("high thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001628 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001629 }
1630
1631 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_LOW_THR_INT_EN, thr_init);
1632 if (rc < 0) {
1633 pr_err("low thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001634 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001635 }
1636
1637 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MULTI_MEAS_EN, thr_init);
1638 if (rc < 0) {
1639 pr_err("multi meas en failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001640 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001641 }
1642
1643 adc_tm->adc_tm_initialized = true;
1644
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001645 pr_debug("OK\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001646 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001647fail:
Siddartha Mohanadoss32019b52012-12-23 17:05:45 -08001648 qpnp_adc_tm = NULL;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001649 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001650}
1651
1652static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
1653{
1654 struct qpnp_adc_tm_drv *adc_tm = dev_get_drvdata(&spmi->dev);
1655 struct device_node *node = spmi->dev.of_node;
1656 struct device_node *child;
1657 int i = 0;
1658
1659 for_each_child_of_node(node, child) {
1660 thermal_zone_device_unregister(adc_tm->sensor[i].tz_dev);
1661 i++;
1662 }
1663
1664 adc_tm->adc_tm_initialized = false;
1665 dev_set_drvdata(&spmi->dev, NULL);
1666
1667 return 0;
1668}
1669
1670static const struct of_device_id qpnp_adc_tm_match_table[] = {
1671 { .compatible = "qcom,qpnp-adc-tm" },
1672 {}
1673};
1674
1675static struct spmi_driver qpnp_adc_tm_driver = {
1676 .driver = {
1677 .name = "qcom,qpnp-adc-tm",
1678 .of_match_table = qpnp_adc_tm_match_table,
1679 },
1680 .probe = qpnp_adc_tm_probe,
1681 .remove = qpnp_adc_tm_remove,
1682};
1683
1684static int __init qpnp_adc_tm_init(void)
1685{
1686 return spmi_driver_register(&qpnp_adc_tm_driver);
1687}
1688module_init(qpnp_adc_tm_init);
1689
1690static void __exit qpnp_adc_tm_exit(void)
1691{
1692 spmi_driver_unregister(&qpnp_adc_tm_driver);
1693}
1694module_exit(qpnp_adc_tm_exit);
1695
1696MODULE_DESCRIPTION("QPNP PMIC ADC Threshold Monitoring driver");
1697MODULE_LICENSE("GPL v2");