blob: f3b29c9550fe4a4d4dfc35ea532a228bdb185a17 [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
Xiaozhe Shi2a503db2013-05-10 17:27:52 -070094#define QPNP_M2_HIGH_THR_LSB 0x73
95#define QPNP_M2_HIGH_THR_MSB 0x74
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080096#define QPNP_M3_ADC_CH_SEL_CTL 0x78
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080097#define QPNP_M3_LOW_THR_LSB 0x79
98#define QPNP_M3_LOW_THR_MSB 0x7a
99#define QPNP_M3_HIGH_THR_LSB 0x7b
100#define QPNP_M3_HIGH_THR_MSB 0x7c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800101#define QPNP_M4_ADC_CH_SEL_CTL 0x80
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800102#define QPNP_M4_LOW_THR_LSB 0x81
103#define QPNP_M4_LOW_THR_MSB 0x82
104#define QPNP_M4_HIGH_THR_LSB 0x83
105#define QPNP_M4_HIGH_THR_MSB 0x84
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800106#define QPNP_M5_ADC_CH_SEL_CTL 0x88
107#define QPNP_M5_LOW_THR_LSB 0x89
108#define QPNP_M5_LOW_THR_MSB 0x8a
109#define QPNP_M5_HIGH_THR_LSB 0x8b
110#define QPNP_M5_HIGH_THR_MSB 0x8c
111#define QPNP_M6_ADC_CH_SEL_CTL 0x90
112#define QPNP_M6_LOW_THR_LSB 0x91
113#define QPNP_M6_LOW_THR_MSB 0x92
114#define QPNP_M6_HIGH_THR_LSB 0x93
115#define QPNP_M6_HIGH_THR_MSB 0x94
116#define QPNP_M7_ADC_CH_SEL_CTL 0x98
117#define QPNP_M7_LOW_THR_LSB 0x99
118#define QPNP_M7_LOW_THR_MSB 0x9a
119#define QPNP_M7_HIGH_THR_LSB 0x9b
120#define QPNP_M7_HIGH_THR_MSB 0x9c
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800121
122#define QPNP_ADC_TM_MULTI_MEAS_EN 0x41
123#define QPNP_ADC_TM_MULTI_MEAS_EN_M0 BIT(0)
124#define QPNP_ADC_TM_MULTI_MEAS_EN_M1 BIT(1)
125#define QPNP_ADC_TM_MULTI_MEAS_EN_M2 BIT(2)
126#define QPNP_ADC_TM_MULTI_MEAS_EN_M3 BIT(3)
127#define QPNP_ADC_TM_MULTI_MEAS_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800128#define QPNP_ADC_TM_MULTI_MEAS_EN_M5 BIT(5)
129#define QPNP_ADC_TM_MULTI_MEAS_EN_M6 BIT(6)
130#define QPNP_ADC_TM_MULTI_MEAS_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800131#define QPNP_ADC_TM_LOW_THR_INT_EN 0x42
132#define QPNP_ADC_TM_LOW_THR_INT_EN_M0 BIT(0)
133#define QPNP_ADC_TM_LOW_THR_INT_EN_M1 BIT(1)
134#define QPNP_ADC_TM_LOW_THR_INT_EN_M2 BIT(2)
135#define QPNP_ADC_TM_LOW_THR_INT_EN_M3 BIT(3)
136#define QPNP_ADC_TM_LOW_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800137#define QPNP_ADC_TM_LOW_THR_INT_EN_M5 BIT(5)
138#define QPNP_ADC_TM_LOW_THR_INT_EN_M6 BIT(6)
139#define QPNP_ADC_TM_LOW_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800140#define QPNP_ADC_TM_HIGH_THR_INT_EN 0x43
141#define QPNP_ADC_TM_HIGH_THR_INT_EN_M0 BIT(0)
142#define QPNP_ADC_TM_HIGH_THR_INT_EN_M1 BIT(1)
143#define QPNP_ADC_TM_HIGH_THR_INT_EN_M2 BIT(2)
144#define QPNP_ADC_TM_HIGH_THR_INT_EN_M3 BIT(3)
145#define QPNP_ADC_TM_HIGH_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800146#define QPNP_ADC_TM_HIGH_THR_INT_EN_M5 BIT(5)
147#define QPNP_ADC_TM_HIGH_THR_INT_EN_M6 BIT(6)
148#define QPNP_ADC_TM_HIGH_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800149
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800150#define QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL 0x59
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800151#define QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL 0x6d
152#define QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL 0x75
153#define QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL 0x7d
154#define QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL 0x85
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800155#define QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL 0x8d
156#define QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL 0x95
157#define QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL 0x9d
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800158#define QPNP_ADC_TM_STATUS1 0x8
159#define QPNP_ADC_TM_STATUS_LOW 0xa
160#define QPNP_ADC_TM_STATUS_HIGH 0xb
161
162#define QPNP_ADC_TM_M0_LOW_THR 0x5d5c
163#define QPNP_ADC_TM_M0_HIGH_THR 0x5f5e
164#define QPNP_ADC_TM_MEAS_INTERVAL 0x0
165
166#define QPNP_ADC_TM_THR_LSB_MASK(val) (val & 0xff)
167#define QPNP_ADC_TM_THR_MSB_MASK(val) ((val & 0xff00) >> 8)
168
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800169#define QPNP_MIN_TIME 2000
170#define QPNP_MAX_TIME 2100
171
Siddartha 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 Mohanadoss71218f22013-04-23 16:24:14 -07001203 if (adc_tm_high_enable || adc_tm_low_enable) {
1204 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
1205 sensor_mask, false);
1206 if (rc < 0) {
1207 pr_err("multi meas disable for channel failed\n");
1208 goto fail;
1209 }
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001210
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001211 rc = qpnp_adc_tm_enable_if_channel_meas();
1212 if (rc < 0) {
1213 pr_err("re-enabling measurement failed\n");
1214 return rc;
1215 }
1216 } else
1217 pr_debug("No threshold status enable %d for high/low??\n",
1218 sensor_mask);
1219
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001220fail:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001221 mutex_unlock(&adc_tm->adc->adc_lock);
1222
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001223 if (adc_tm_high_enable || adc_tm_low_enable)
1224 schedule_work(&adc_tm->sensor[sensor_num].work);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001225
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001226 return rc;
1227}
1228
1229static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
1230{
1231 int rc;
1232
1233 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001234 if (rc < 0)
1235 pr_err("adc-tm high thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001236
1237 return;
1238}
1239DECLARE_WORK(trigger_completion_adc_tm_high_thr_work,
1240 qpnp_adc_tm_high_thr_work);
1241
1242static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
1243{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001244 qpnp_adc_tm_disable();
1245
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001246 schedule_work(&trigger_completion_adc_tm_high_thr_work);
1247
1248 return IRQ_HANDLED;
1249}
1250
1251static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
1252{
1253 int rc;
1254
1255 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001256 if (rc < 0)
1257 pr_err("adc-tm low thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001258
1259 return;
1260}
1261DECLARE_WORK(trigger_completion_adc_tm_low_thr_work, qpnp_adc_tm_low_thr_work);
1262
1263static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
1264{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001265 qpnp_adc_tm_disable();
1266
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001267 schedule_work(&trigger_completion_adc_tm_low_thr_work);
1268
1269 return IRQ_HANDLED;
1270}
1271
1272static irqreturn_t qpnp_adc_tm_isr(int irq, void *dev_id)
1273{
1274 struct qpnp_adc_tm_drv *adc_tm = dev_id;
1275
1276 complete(&adc_tm->adc->adc_rslt_completion);
1277
1278 return IRQ_HANDLED;
1279}
1280
1281static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
1282 unsigned long *temp)
1283{
1284 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
1285 struct qpnp_vadc_result result;
1286 int rc = 0;
1287
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001288 rc = qpnp_vadc_read(adc_tm_sensor->vadc_channel_num, &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001289 if (rc)
1290 return rc;
1291
1292 *temp = result.physical;
1293
1294 return rc;
1295}
1296
1297static struct thermal_zone_device_ops qpnp_adc_tm_thermal_ops = {
1298 .get_temp = qpnp_adc_read_temp,
1299 .get_mode = qpnp_adc_tm_get_mode,
1300 .set_mode = qpnp_adc_tm_set_mode,
1301 .get_trip_type = qpnp_adc_tm_get_trip_type,
1302 .activate_trip_type = qpnp_adc_tm_activate_trip_type,
1303 .get_trip_temp = qpnp_adc_tm_get_trip_temp,
1304 .set_trip_temp = qpnp_adc_tm_set_trip_temp,
1305};
1306
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001307int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001308{
1309 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001310 uint32_t channel, dt_index = 0, scale_type = 0;
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001311 int rc = 0, i = 0;
1312 bool chan_found = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001313
1314 if (!adc_tm || !adc_tm->adc_tm_initialized)
1315 return -ENODEV;
1316
1317 if (param->threshold_notification == NULL) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001318 pr_err("No notification for high/low temp??\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001319 return -EINVAL;
1320 }
1321
1322 mutex_lock(&adc_tm->adc->adc_lock);
1323
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001324 channel = param->channel;
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001325 while (i < adc_tm->max_channels_available) {
1326 if (adc_tm->adc->adc_channels[i].channel_num ==
1327 channel) {
1328 dt_index = i;
1329 chan_found = true;
1330 i++;
1331 } else
1332 i++;
1333 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001334
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001335 if (!chan_found) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001336 pr_err("not a valid ADC_TM channel\n");
1337 rc = -EINVAL;
1338 goto fail_unlock;
1339 }
1340
1341 rc = qpnp_adc_tm_check_revision(
1342 adc_tm->sensor[dt_index].btm_channel_num);
1343 if (rc < 0)
1344 goto fail_unlock;
1345
1346 scale_type = adc_tm->adc->adc_channels[dt_index].adc_scale_fn;
1347 if (scale_type >= SCALE_RSCALE_NONE) {
1348 rc = -EBADF;
1349 goto fail_unlock;
1350 }
1351
1352 pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
1353 channel, scale_type, dt_index);
1354 adc_tm->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001355 adc_tm->adc->amux_prop->decimation =
Siddartha Mohanadossf4cdd132013-03-27 19:38:34 -07001356 adc_tm->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001357 adc_tm->adc->amux_prop->hw_settle_time =
Siddartha Mohanadossf4cdd132013-03-27 19:38:34 -07001358 adc_tm->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001359 adc_tm->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadossf4cdd132013-03-27 19:38:34 -07001360 adc_tm->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001361 adc_tm->adc->amux_prop->mode_sel =
1362 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
1363 adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
1364 ADC_MEAS1_INTERVAL_1S;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001365 adc_tm_rscale_fn[scale_type].chan(param,
1366 &adc_tm->adc->amux_prop->chan_prop->low_thr,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001367 &adc_tm->adc->amux_prop->chan_prop->high_thr);
1368 adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001369 adc_tm->sensor[dt_index].btm_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001370 adc_tm->adc->amux_prop->chan_prop->timer_select =
1371 ADC_MEAS_TIMER_SELECT1;
1372 adc_tm->adc->amux_prop->chan_prop->state_request =
1373 param->state_request;
1374 rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
1375 if (rc) {
1376 pr_err("adc-tm configure failed with %d\n", rc);
1377 goto fail_unlock;
1378 }
1379
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001380 adc_tm->sensor[dt_index].btm_param = param;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001381 adc_tm->sensor[dt_index].scale_type = scale_type;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001382
1383fail_unlock:
1384 mutex_unlock(&adc_tm->adc->adc_lock);
1385
1386 return rc;
1387}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001388EXPORT_SYMBOL(qpnp_adc_tm_channel_measure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001389
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001390int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001391{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001392 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1393 uint32_t channel, dt_index = 0, btm_chan_num;
1394 u8 sensor_mask = 0;
1395 int rc = 0;
1396
1397 if (!adc_tm || !adc_tm->adc_tm_initialized)
1398 return -ENODEV;
1399
1400 mutex_lock(&adc_tm->adc->adc_lock);
1401
1402 /* Disable bank */
1403 rc = qpnp_adc_tm_disable();
1404 if (rc < 0) {
1405 pr_err("adc-tm disable failed\n");
1406 goto fail;
1407 }
1408
1409 /* Check if a conversion is in progress */
1410 rc = qpnp_adc_tm_req_sts_check();
1411 if (rc < 0) {
1412 pr_err("adc-tm req_sts check failed\n");
1413 goto fail;
1414 }
1415
1416 channel = param->channel;
1417 while ((adc_tm->adc->adc_channels[dt_index].channel_num
1418 != channel) && (dt_index < adc_tm->max_channels_available))
1419 dt_index++;
1420
1421 if (dt_index >= adc_tm->max_channels_available) {
1422 pr_err("not a valid ADC_TMN channel\n");
1423 rc = -EINVAL;
1424 goto fail;
1425 }
1426
1427 btm_chan_num = adc_tm->sensor[dt_index].btm_channel_num;
1428 sensor_mask = 1 << adc_tm->sensor[dt_index].sensor_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001429
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001430 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001431 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001432 if (rc < 0) {
1433 pr_err("low threshold int write failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001434 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001435 }
1436
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001437 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001438 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001439 if (rc < 0) {
1440 pr_err("high threshold int enable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001441 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001442 }
1443
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001444 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001445 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001446 if (rc < 0) {
1447 pr_err("multi measurement en failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001448 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001449 }
1450
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001451 rc = qpnp_adc_tm_enable_if_channel_meas();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001452 if (rc < 0)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001453 pr_err("re-enabling measurement failed\n");
1454
1455fail:
1456 mutex_unlock(&adc_tm->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001457
1458 return rc;
1459}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001460EXPORT_SYMBOL(qpnp_adc_tm_disable_chan_meas);
1461
1462int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_btm_param *param)
1463{
1464 param->channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
1465 return qpnp_adc_tm_channel_measure(param);
1466}
1467EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001468
1469int32_t qpnp_adc_tm_usbid_end(void)
1470{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001471 struct qpnp_adc_tm_btm_param param;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001472
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001473 return qpnp_adc_tm_disable_chan_meas(&param);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001474}
1475EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
1476
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001477int32_t qpnp_adc_tm_is_ready(void)
1478{
1479 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1480
1481 if (!adc_tm || !adc_tm->adc_tm_initialized)
1482 return -EPROBE_DEFER;
1483 else
1484 return 0;
1485}
1486EXPORT_SYMBOL(qpnp_adc_tm_is_ready);
1487
1488static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
1489{
1490 struct device_node *node = spmi->dev.of_node, *child;
1491 struct qpnp_adc_tm_drv *adc_tm;
1492 struct qpnp_adc_drv *adc_qpnp;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001493 int32_t count_adc_channel_list = 0, rc, sen_idx = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001494 u8 thr_init = 0;
1495
1496 if (!node)
1497 return -EINVAL;
1498
1499 if (qpnp_adc_tm) {
1500 pr_err("adc-tm already in use\n");
1501 return -EBUSY;
1502 }
1503
1504 for_each_child_of_node(node, child)
1505 count_adc_channel_list++;
1506
1507 if (!count_adc_channel_list) {
1508 pr_err("No channel listing\n");
1509 return -EINVAL;
1510 }
1511
1512 adc_tm = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_drv) +
1513 (count_adc_channel_list *
1514 sizeof(struct qpnp_adc_tm_sensor)),
1515 GFP_KERNEL);
1516 if (!adc_tm) {
1517 dev_err(&spmi->dev, "Unable to allocate memory\n");
1518 return -ENOMEM;
1519 }
1520
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001521 qpnp_adc_tm = adc_tm;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001522 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1523 GFP_KERNEL);
1524 if (!adc_qpnp) {
1525 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001526 rc = -ENOMEM;
1527 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001528 }
1529
1530 adc_tm->adc = adc_qpnp;
1531
1532 rc = qpnp_adc_get_devicetree_data(spmi, adc_tm->adc);
1533 if (rc) {
1534 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001535 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001536 }
Stephen Boydbeab4502013-04-25 10:18:17 -07001537 mutex_init(&adc_tm->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001538
1539 /* Register the ADC peripheral interrupt */
1540 adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
1541 NULL, "high-thr-en-set");
1542 if (adc_tm->adc->adc_high_thr_irq < 0) {
1543 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001544 rc = -ENXIO;
1545 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001546 }
1547
1548 adc_tm->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
1549 NULL, "low-thr-en-set");
1550 if (adc_tm->adc->adc_low_thr_irq < 0) {
1551 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001552 rc = -ENXIO;
1553 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001554 }
1555
1556 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_irq_eoc,
1557 qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
1558 "qpnp_adc_tm_interrupt", adc_tm);
1559 if (rc) {
1560 dev_err(&spmi->dev,
1561 "failed to request adc irq with error %d\n", rc);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001562 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001563 } else {
1564 enable_irq_wake(adc_tm->adc->adc_irq_eoc);
1565 }
1566
1567 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_high_thr_irq,
1568 qpnp_adc_tm_high_thr_isr,
1569 IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", adc_tm);
1570 if (rc) {
1571 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001572 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001573 } else {
1574 enable_irq_wake(adc_tm->adc->adc_high_thr_irq);
1575 }
1576
1577 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
1578 qpnp_adc_tm_low_thr_isr,
1579 IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
1580 if (rc) {
1581 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001582 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001583 } else {
1584 enable_irq_wake(adc_tm->adc->adc_low_thr_irq);
1585 }
1586
1587 for_each_child_of_node(node, child) {
1588 char name[25];
1589 int btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001590 bool thermal_node = false;
1591
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001592 rc = of_property_read_u32(child,
1593 "qcom,btm-channel-number", &btm_channel_num);
1594 if (rc) {
1595 pr_err("Invalid btm channel number\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001596 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001597 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001598 adc_tm->sensor[sen_idx].btm_channel_num = btm_channel_num;
1599 adc_tm->sensor[sen_idx].vadc_channel_num =
1600 adc_tm->adc->adc_channels[sen_idx].channel_num;
1601 adc_tm->sensor[sen_idx].sensor_num = sen_idx;
Siddartha Mohanadossb2795e42013-03-22 09:00:28 -07001602 pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
1603 adc_tm->adc->adc_channels[sen_idx].channel_num);
Siddartha Mohanadossea65d9e2013-04-16 18:26:39 -07001604 thermal_node = of_property_read_bool(child,
1605 "qcom,thermal-node");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001606 if (thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001607 /* Register with the thermal zone */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001608 pr_debug("thermal node%x\n", btm_channel_num);
1609 adc_tm->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
1610 adc_tm->sensor[sen_idx].thermal_node = true;
1611 snprintf(name, sizeof(name),
1612 adc_tm->adc->adc_channels[sen_idx].name);
1613 adc_tm->sensor[sen_idx].meas_interval =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001614 QPNP_ADC_TM_MEAS_INTERVAL;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001615 adc_tm->sensor[sen_idx].low_thr =
1616 QPNP_ADC_TM_M0_LOW_THR;
1617 adc_tm->sensor[sen_idx].high_thr =
1618 QPNP_ADC_TM_M0_HIGH_THR;
1619 adc_tm->sensor[sen_idx].tz_dev =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001620 thermal_zone_device_register(name,
1621 ADC_TM_TRIP_NUM,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001622 &adc_tm->sensor[sen_idx],
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001623 &qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001624 if (IS_ERR(adc_tm->sensor[sen_idx].tz_dev))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001625 pr_err("thermal device register failed.\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001626 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001627 INIT_WORK(&adc_tm->sensor[sen_idx].work, notify_adc_tm_fn);
1628 sen_idx++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001629 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001630 adc_tm->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001631 dev_set_drvdata(&spmi->dev, adc_tm);
1632 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_HIGH_THR_INT_EN, thr_init);
1633 if (rc < 0) {
1634 pr_err("high thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001635 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001636 }
1637
1638 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_LOW_THR_INT_EN, thr_init);
1639 if (rc < 0) {
1640 pr_err("low thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001641 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001642 }
1643
1644 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MULTI_MEAS_EN, thr_init);
1645 if (rc < 0) {
1646 pr_err("multi meas en failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001647 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001648 }
1649
1650 adc_tm->adc_tm_initialized = true;
1651
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001652 pr_debug("OK\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001653 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001654fail:
Siddartha Mohanadoss32019b52012-12-23 17:05:45 -08001655 qpnp_adc_tm = NULL;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001656 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001657}
1658
1659static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
1660{
1661 struct qpnp_adc_tm_drv *adc_tm = dev_get_drvdata(&spmi->dev);
1662 struct device_node *node = spmi->dev.of_node;
1663 struct device_node *child;
1664 int i = 0;
1665
1666 for_each_child_of_node(node, child) {
1667 thermal_zone_device_unregister(adc_tm->sensor[i].tz_dev);
1668 i++;
1669 }
1670
1671 adc_tm->adc_tm_initialized = false;
1672 dev_set_drvdata(&spmi->dev, NULL);
1673
1674 return 0;
1675}
1676
1677static const struct of_device_id qpnp_adc_tm_match_table[] = {
1678 { .compatible = "qcom,qpnp-adc-tm" },
1679 {}
1680};
1681
1682static struct spmi_driver qpnp_adc_tm_driver = {
1683 .driver = {
1684 .name = "qcom,qpnp-adc-tm",
1685 .of_match_table = qpnp_adc_tm_match_table,
1686 },
1687 .probe = qpnp_adc_tm_probe,
1688 .remove = qpnp_adc_tm_remove,
1689};
1690
1691static int __init qpnp_adc_tm_init(void)
1692{
1693 return spmi_driver_register(&qpnp_adc_tm_driver);
1694}
1695module_init(qpnp_adc_tm_init);
1696
1697static void __exit qpnp_adc_tm_exit(void)
1698{
1699 spmi_driver_unregister(&qpnp_adc_tm_driver);
1700}
1701module_exit(qpnp_adc_tm_exit);
1702
1703MODULE_DESCRIPTION("QPNP PMIC ADC Threshold Monitoring driver");
1704MODULE_LICENSE("GPL v2");