blob: eae5cc8be20c58195fe5f25162f9d7453d97ce60 [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 Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700194 struct qpnp_vadc_chip *vadc_dev;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800195 struct qpnp_adc_tm_sensor sensor[0];
196};
197
198struct qpnp_adc_tm_drv *qpnp_adc_tm;
199
200struct qpnp_adc_tm_trip_reg_type {
201 uint16_t low_thr_lsb_addr;
202 uint16_t low_thr_msb_addr;
203 uint16_t high_thr_lsb_addr;
204 uint16_t high_thr_msb_addr;
205 u8 multi_meas_en;
206 u8 low_thr_int_chan_en;
207 u8 high_thr_int_chan_en;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800208 u8 meas_interval_ctl;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800209};
210
211static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
212 [QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
213 QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
214 QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800215 QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
216 QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800217 [QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
218 QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
219 QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800220 QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
221 QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800222 [QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
223 QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
224 QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800225 QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
226 QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800227 [QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
228 QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
229 QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800230 QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
231 QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800232 [QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
233 QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
234 QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800235 QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
236 QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
237 [QPNP_ADC_TM_M5_ADC_CH_SEL_CTL] = {QPNP_M5_LOW_THR_LSB,
238 QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
239 QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
240 QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
241 QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
242 [QPNP_ADC_TM_M6_ADC_CH_SEL_CTL] = {QPNP_M6_LOW_THR_LSB,
243 QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
244 QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
245 QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
246 QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
247 [QPNP_ADC_TM_M7_ADC_CH_SEL_CTL] = {QPNP_M7_LOW_THR_LSB,
248 QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
249 QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
250 QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
251 QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL},
252};
253
254static struct qpnp_adc_tm_reverse_scale_fn adc_tm_rscale_fn[] = {
255 [SCALE_R_VBATT] = {qpnp_adc_vbatt_rscaler},
256 [SCALE_RBATT_THERM] = {qpnp_adc_btm_scaler},
257 [SCALE_R_USB_ID] = {qpnp_adc_usb_scaler},
258 [SCALE_RPMIC_THERM] = {qpnp_adc_scale_millidegc_pmic_voltage_thr},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800259};
260
261static int32_t qpnp_adc_tm_read_reg(int16_t reg, u8 *data)
262{
263 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
264 int rc = 0;
265
266 rc = spmi_ext_register_readl(adc_tm->adc->spmi->ctrl,
267 adc_tm->adc->slave, (adc_tm->adc->offset + reg), data, 1);
268 if (rc < 0)
269 pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
270
271 return rc;
272}
273
274static int32_t qpnp_adc_tm_write_reg(int16_t reg, u8 data)
275{
276 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
277 int rc = 0;
278 u8 *buf;
279
280 buf = &data;
281
282 rc = spmi_ext_register_writel(adc_tm->adc->spmi->ctrl,
283 adc_tm->adc->slave, (adc_tm->adc->offset + reg), buf, 1);
284 if (rc < 0)
285 pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
286
287 return rc;
288}
289
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800290static int32_t qpnp_adc_tm_enable(void)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800291{
292 int rc = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800293 u8 data = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800294
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800295 data = QPNP_ADC_TM_EN;
296 rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
297 if (rc < 0)
298 pr_err("adc-tm enable failed\n");
299
300 return rc;
301}
302
303static int32_t qpnp_adc_tm_disable(void)
304{
305 u8 data = 0;
306 int rc = 0;
307
308 rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
309 if (rc < 0)
310 pr_err("adc-tm disable failed\n");
311
312 return rc;
313}
314
315static int32_t qpnp_adc_tm_enable_if_channel_meas(void)
316{
317 u8 adc_tm_meas_en = 0;
318 int rc = 0;
319
320 /* Check if a measurement request is still required */
321 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
322 &adc_tm_meas_en);
323 if (rc) {
324 pr_err("adc-tm-tm read status high failed with %d\n", rc);
325 return rc;
326 }
327
328 /* Enable only if there are pending measurement requests */
329 if (adc_tm_meas_en) {
330 qpnp_adc_tm_enable();
331
332 /* Request conversion */
333 rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800334 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800335 pr_err("adc-tm request conversion failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800336 return rc;
337 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800338 }
339
340 return rc;
341}
342
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800343static int32_t qpnp_adc_tm_req_sts_check(void)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800344{
345 u8 status1;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800346 int rc, count = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800347
348 /* The VADC_TM bank needs to be disabled for new conversion request */
349 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
350 if (rc) {
351 pr_err("adc-tm read status1 failed\n");
352 return rc;
353 }
354
355 /* Disable the bank if a conversion is occuring */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800356 while ((status1 & QPNP_STATUS1_REQ_STS) && (count < 5)) {
357 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800358 if (rc < 0)
359 pr_err("adc-tm disable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800360 /* Wait time is based on the optimum sampling rate
361 * and adding enough time buffer to account for ADC conversions
362 * occuring on different peripheral banks */
363 usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
364 count++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800365 }
366
367 return rc;
368}
369
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800370static int32_t qpnp_adc_tm_check_revision(uint32_t btm_chan_num)
371{
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -0700372 u8 rev, perph_subtype;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800373 int rc = 0;
374
375 rc = qpnp_adc_tm_read_reg(QPNP_REVISION3, &rev);
376 if (rc) {
377 pr_err("adc-tm revision read failed\n");
378 return rc;
379 }
380
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -0700381 rc = qpnp_adc_tm_read_reg(QPNP_PERPH_SUBTYPE, &perph_subtype);
382 if (rc) {
383 pr_err("adc-tm perph_subtype read failed\n");
384 return rc;
385 }
386
387 if (perph_subtype == QPNP_PERPH_TYPE2) {
388 if ((rev < QPNP_REVISION_EIGHT_CHANNEL_SUPPORT) &&
389 (btm_chan_num > QPNP_ADC_TM_M4_ADC_CH_SEL_CTL)) {
390 pr_debug("Version does not support more than 5 channels\n");
391 return -EINVAL;
392 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800393 }
394
395 return rc;
396}
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800397static int32_t qpnp_adc_tm_mode_select(u8 mode_ctl)
398{
399 int rc;
400
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800401 mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
402
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800403 /* VADC_BTM current sets mode to recurring measurements */
404 rc = qpnp_adc_tm_write_reg(QPNP_MODE_CTL, mode_ctl);
405 if (rc < 0)
406 pr_err("adc-tm write mode selection err\n");
407
408 return rc;
409}
410
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800411static int32_t qpnp_adc_tm_timer_interval_select(uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800412 struct qpnp_vadc_chan_properties *chan_prop)
413{
414 int rc;
415 u8 meas_interval_timer2 = 0;
416
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800417 /* Configure kernel clients to timer1 */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800418 switch (chan_prop->timer_select) {
419 case ADC_MEAS_TIMER_SELECT1:
420 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL,
421 chan_prop->meas_interval1);
422 if (rc < 0) {
423 pr_err("timer1 configure failed\n");
424 return rc;
425 }
426 break;
427 case ADC_MEAS_TIMER_SELECT2:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800428 /* Thermal channels uses timer2, default to 1 second */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800429 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
430 &meas_interval_timer2);
431 if (rc < 0) {
432 pr_err("timer2 configure read failed\n");
433 return rc;
434 }
435 meas_interval_timer2 |=
436 (chan_prop->meas_interval2 <<
437 QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
438 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
439 meas_interval_timer2);
440 if (rc < 0) {
441 pr_err("timer2 configure failed\n");
442 return rc;
443 }
444 break;
445 case ADC_MEAS_TIMER_SELECT3:
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800446 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
447 &meas_interval_timer2);
448 if (rc < 0) {
449 pr_err("timer3 read failed\n");
450 return rc;
451 }
452 chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
453 meas_interval_timer2 |= chan_prop->meas_interval2;
454 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
455 meas_interval_timer2);
456 if (rc < 0) {
457 pr_err("timer3 configure failed\n");
458 return rc;
459 }
460 break;
461 default:
462 pr_err("Invalid timer selection\n");
463 return -EINVAL;
464 }
465
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800466 /* Select the timer to use for the corresponding channel */
467 adc_tm_data[btm_chan].meas_interval_ctl = chan_prop->timer_select;
468
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800469 return rc;
470}
471
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700472static int32_t qpnp_adc_tm_reg_update(uint16_t addr,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800473 u8 mask, bool state)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800474{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800475 u8 reg_value = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800476 int rc = 0;
477
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800478 rc = qpnp_adc_tm_read_reg(addr, &reg_value);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800479 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800480 pr_err("read failed for addr:0x%x\n", addr);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800481 return rc;
482 }
483
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800484 reg_value = reg_value & ~mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800485 if (state)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800486 reg_value |= mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800487
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800488 pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n",
489 state, addr, reg_value, ~mask);
490 rc = qpnp_adc_tm_write_reg(addr, reg_value);
491 if (rc < 0) {
492 pr_err("write failed for addr:%x\n", addr);
493 return rc;
494 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800495
496 return rc;
497}
498
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700499static int32_t qpnp_adc_tm_thr_update(uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800500 struct qpnp_vadc_chan_properties *chan_prop)
501{
502 int rc = 0;
503
504 rc = qpnp_adc_tm_write_reg(
505 adc_tm_data[btm_chan].low_thr_lsb_addr,
506 QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
507 if (rc < 0) {
508 pr_err("low threshold lsb setting failed\n");
509 return rc;
510 }
511
512 rc = qpnp_adc_tm_write_reg(
513 adc_tm_data[btm_chan].low_thr_msb_addr,
514 QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
515 if (rc < 0) {
516 pr_err("low threshold msb setting failed\n");
517 return rc;
518 }
519
520 rc = qpnp_adc_tm_write_reg(
521 adc_tm_data[btm_chan].high_thr_lsb_addr,
522 QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
523 if (rc < 0) {
524 pr_err("high threshold lsb setting failed\n");
525 return rc;
526 }
527
528 rc = qpnp_adc_tm_write_reg(
529 adc_tm_data[btm_chan].high_thr_msb_addr,
530 QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
531 if (rc < 0)
532 pr_err("high threshold msb setting failed\n");
533
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700534 pr_debug("client requested low:%d and high:%d\n",
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800535 chan_prop->low_thr, chan_prop->high_thr);
536
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800537 return rc;
538}
539
540static int32_t qpnp_adc_tm_channel_configure(uint32_t btm_chan,
541 struct qpnp_vadc_chan_properties *chan_prop,
542 uint32_t amux_channel)
543{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800544 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
545 int rc = 0, i = 0, chan_idx = 0;
546 bool chan_found = false;
547 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800548
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800549 while (i < adc_tm->max_channels_available) {
550 if (adc_tm->sensor[i].btm_channel_num == btm_chan) {
551 chan_idx = i;
552 chan_found = true;
553 i++;
554 } else
555 i++;
556 }
557
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -0700558 if (!chan_found) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800559 pr_err("Channel not found\n");
560 return -EINVAL;
561 }
562
563 sensor_mask = 1 << chan_idx;
564 if (!adc_tm->sensor[chan_idx].thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800565 /* Update low and high notification thresholds */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700566 rc = qpnp_adc_tm_thr_update(btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800567 chan_prop);
568 if (rc < 0) {
569 pr_err("setting chan:%d threshold failed\n", btm_chan);
570 return rc;
571 }
572
573 if ((chan_prop->state_request ==
574 ADC_TM_LOW_THR_ENABLE) ||
575 (chan_prop->state_request ==
576 ADC_TM_HIGH_LOW_THR_ENABLE)) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800577 pr_debug("low sensor mask:%x with state:%d\n",
578 sensor_mask, chan_prop->state_request);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800579 /* Enable low threshold's interrupt */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700580 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800581 QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800582 if (rc < 0) {
583 pr_err("low thr enable err:%d\n", btm_chan);
584 return rc;
585 }
586 }
587
588 if ((chan_prop->state_request ==
589 ADC_TM_HIGH_THR_ENABLE) ||
590 (chan_prop->state_request ==
591 ADC_TM_HIGH_LOW_THR_ENABLE)) {
592 /* Enable high threshold's interrupt */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800593 pr_debug("high sensor mask:%x\n", sensor_mask);
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700594 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800595 QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800596 if (rc < 0) {
597 pr_err("high thr enable err:%d\n", btm_chan);
598 return rc;
599 }
600 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800601 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800602
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800603 /* Enable corresponding BTM channel measurement */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700604 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800605 QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
606 if (rc < 0) {
607 pr_err("multi measurement en failed\n");
608 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800609 }
610
611 return rc;
612}
613
614static int32_t qpnp_adc_tm_configure(
615 struct qpnp_adc_amux_properties *chan_prop)
616{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800617 u8 decimation = 0, op_cntrl = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800618 int rc = 0;
619 uint32_t btm_chan = 0;
620
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800621 /* Disable bank */
622 rc = qpnp_adc_tm_disable();
623 if (rc)
624 return rc;
625
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800626 /* Check if a conversion is in progress */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800627 rc = qpnp_adc_tm_req_sts_check();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800628 if (rc < 0) {
629 pr_err("adc-tm req_sts check failed\n");
630 return rc;
631 }
632
633 /* Set measurement in recurring mode */
634 rc = qpnp_adc_tm_mode_select(chan_prop->mode_sel);
635 if (rc < 0) {
636 pr_err("adc-tm mode select failed\n");
637 return rc;
638 }
639
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800640 /* Configure AMUX channel select for the corresponding BTM channel*/
641 btm_chan = chan_prop->chan_prop->tm_channel_select;
642 rc = qpnp_adc_tm_write_reg(btm_chan, chan_prop->amux_channel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800643 if (rc < 0) {
644 pr_err("adc-tm channel selection err\n");
645 return rc;
646 }
647
648 /* Digital paramater setup */
649 decimation |= chan_prop->decimation <<
650 QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
651 rc = qpnp_adc_tm_write_reg(QPNP_ADC_DIG_PARAM, decimation);
652 if (rc < 0) {
653 pr_err("adc-tm digital parameter setup err\n");
654 return rc;
655 }
656
657 /* Hardware setting time */
658 rc = qpnp_adc_tm_write_reg(QPNP_HW_SETTLE_DELAY,
659 chan_prop->hw_settle_time);
660 if (rc < 0) {
661 pr_err("adc-tm hw settling time setup err\n");
662 return rc;
663 }
664
665 /* Fast averaging setup */
666 rc = qpnp_adc_tm_write_reg(QPNP_FAST_AVG_CTL,
667 chan_prop->fast_avg_setup);
668 if (rc < 0) {
669 pr_err("adc-tm fast-avg setup err\n");
670 return rc;
671 }
672
673 /* Measurement interval setup */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800674 rc = qpnp_adc_tm_timer_interval_select(btm_chan,
675 chan_prop->chan_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800676 if (rc < 0) {
677 pr_err("adc-tm timer select failed\n");
678 return rc;
679 }
680
681 /* Channel configuration setup */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800682 rc = qpnp_adc_tm_channel_configure(btm_chan, chan_prop->chan_prop,
683 chan_prop->amux_channel);
684 if (rc < 0) {
685 pr_err("adc-tm channel configure failed\n");
686 return rc;
687 }
688
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800689 /* Recurring interval measurement enable */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800690 rc = qpnp_adc_tm_read_reg(QPNP_ADC_MEAS_INTERVAL_OP_CTL, &op_cntrl);
691 op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700692 rc = qpnp_adc_tm_reg_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800693 op_cntrl, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800694 if (rc < 0) {
695 pr_err("adc-tm meas interval op configure failed\n");
696 return rc;
697 }
698
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800699 /* Enable bank */
700 rc = qpnp_adc_tm_enable();
701 if (rc)
702 return rc;
703
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800704 /* Request conversion */
705 rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
706 if (rc < 0) {
707 pr_err("adc-tm request conversion failed\n");
708 return rc;
709 }
710
711 return 0;
712}
713
714static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
715 enum thermal_device_mode *mode)
716{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800717 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800718
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800719 if (!adc_tm_sensor || qpnp_adc_tm_check_revision(
720 adc_tm_sensor->btm_channel_num) || !mode)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800721 return -EINVAL;
722
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800723 *mode = adc_tm_sensor->mode;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800724
725 return 0;
726}
727
728static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
729 enum thermal_device_mode mode)
730{
731 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
732 struct qpnp_adc_tm_drv *adc_drv = qpnp_adc_tm;
733 int rc = 0, channel;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800734 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800735
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800736 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800737 return -EINVAL;
738
739 if (mode == THERMAL_DEVICE_ENABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800740 adc_drv->adc->amux_prop->amux_channel =
741 adc_tm->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800742 channel = adc_tm->sensor_num;
743 adc_drv->adc->amux_prop->decimation =
744 adc_drv->adc->adc_channels[channel].adc_decimation;
745 adc_drv->adc->amux_prop->hw_settle_time =
746 adc_drv->adc->adc_channels[channel].hw_settle_time;
747 adc_drv->adc->amux_prop->fast_avg_setup =
748 adc_drv->adc->adc_channels[channel].fast_avg_setup;
749 adc_drv->adc->amux_prop->mode_sel =
750 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
751 adc_drv->adc->amux_prop->chan_prop->timer_select =
752 ADC_MEAS_TIMER_SELECT1;
753 adc_drv->adc->amux_prop->chan_prop->meas_interval1 =
754 ADC_MEAS1_INTERVAL_1S;
755 adc_drv->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
756 adc_drv->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
757 adc_drv->adc->amux_prop->chan_prop->tm_channel_select =
758 adc_tm->btm_channel_num;
759
760 rc = qpnp_adc_tm_configure(adc_drv->adc->amux_prop);
761 if (rc) {
762 pr_err("adc-tm tm configure failed with %d\n", rc);
763 return -EINVAL;
764 }
765 } else if (mode == THERMAL_DEVICE_DISABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800766 sensor_mask = 1 << adc_tm->sensor_num;
767 /* Disable bank */
768 rc = qpnp_adc_tm_disable();
769 if (rc < 0) {
770 pr_err("adc-tm disable failed\n");
771 return rc;
772 }
773
774 /* Check if a conversion is in progress */
775 rc = qpnp_adc_tm_req_sts_check();
776 if (rc < 0) {
777 pr_err("adc-tm req_sts check failed\n");
778 return rc;
779 }
780
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700781 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800782 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800783 if (rc < 0) {
784 pr_err("multi measurement update failed\n");
785 return rc;
786 }
787
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800788 rc = qpnp_adc_tm_enable_if_channel_meas();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800789 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800790 pr_err("re-enabling measurement failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800791 return rc;
792 }
793 }
794
795 adc_tm->mode = mode;
796
797 return 0;
798}
799
800static int qpnp_adc_tm_get_trip_type(struct thermal_zone_device *thermal,
801 int trip, enum thermal_trip_type *type)
802{
803 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
804
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800805 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num)
806 || !type || type < 0)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800807 return -EINVAL;
808
809 switch (trip) {
810 case ADC_TM_TRIP_HIGH_WARM:
811 *type = THERMAL_TRIP_CONFIGURABLE_HI;
812 break;
813 case ADC_TM_TRIP_LOW_COOL:
814 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
815 break;
816 default:
817 return -EINVAL;
818 }
819
820 return 0;
821}
822
823static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
824 int trip, unsigned long *temp)
825{
826 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
827 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
828 int64_t result = 0;
829 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
830 unsigned int reg, rc = 0, btm_channel_num;
831 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
832 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
833
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800834 if (!adc_tm || qpnp_adc_tm_check_revision(
835 adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800836 return -EINVAL;
837
838 btm_channel_num = adc_tm_sensor->btm_channel_num;
839 reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
840 reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
841 reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
842 reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
843
844 switch (trip) {
845 case ADC_TM_TRIP_HIGH_WARM:
846 rc = qpnp_adc_tm_read_reg(reg_low_thr_lsb, &trip_warm_thr0);
847 if (rc) {
848 pr_err("adc-tm low_thr_lsb err\n");
849 return rc;
850 }
851
852 rc = qpnp_adc_tm_read_reg(reg_low_thr_msb, &trip_warm_thr1);
853 if (rc) {
854 pr_err("adc-tm low_thr_msb err\n");
855 return rc;
856 }
857 reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
858 break;
859 case ADC_TM_TRIP_LOW_COOL:
860 rc = qpnp_adc_tm_read_reg(reg_high_thr_lsb, &trip_cool_thr0);
861 if (rc) {
862 pr_err("adc-tm_tm high_thr_lsb err\n");
863 return rc;
864 }
865
866 rc = qpnp_adc_tm_read_reg(reg_high_thr_msb, &trip_cool_thr1);
867 if (rc) {
868 pr_err("adc-tm_tm high_thr_lsb err\n");
869 return rc;
870 }
871 reg = (trip_cool_thr1 << 8) | trip_cool_thr0;
872 break;
873 default:
874 return -EINVAL;
875 }
876
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700877 rc = qpnp_adc_tm_scale_voltage_therm_pu2(adc_tm->vadc_dev, reg,
878 &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800879 if (rc < 0) {
880 pr_err("Failed to lookup the therm thresholds\n");
881 return rc;
882 }
883
884 *temp = result;
885
886 return 0;
887}
888
889static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
890 int trip, long temp)
891{
892 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
893 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
894 struct qpnp_adc_tm_config tm_config;
895 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
896 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
897 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
898 int rc = 0, btm_channel_num;
899
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800900 if (!adc_tm || qpnp_adc_tm_check_revision(
901 adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800902 return -EINVAL;
903
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800904 tm_config.channel = adc_tm_sensor->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800905 switch (trip) {
906 case ADC_TM_TRIP_HIGH_WARM:
907 tm_config.high_thr_temp = temp;
908 break;
909 case ADC_TM_TRIP_LOW_COOL:
910 tm_config.low_thr_temp = temp;
911 break;
912 default:
913 return -EINVAL;
914 }
915
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800916 pr_debug("requested a high - %d and low - %d with trip - %d\n",
917 tm_config.high_thr_temp, tm_config.low_thr_temp, trip);
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700918 rc = qpnp_adc_tm_scale_therm_voltage_pu2(adc_tm->vadc_dev, &tm_config);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800919 if (rc < 0) {
920 pr_err("Failed to lookup the adc-tm thresholds\n");
921 return rc;
922 }
923
924 trip_warm_thr0 = ((tm_config.low_thr_voltage << 24) >> 24);
925 trip_warm_thr1 = ((tm_config.low_thr_voltage << 16) >> 24);
926 trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
927 trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
928
929 btm_channel_num = adc_tm_sensor->btm_channel_num;
930 reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
931 reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
932 reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
933 reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
934
935 switch (trip) {
936 case ADC_TM_TRIP_HIGH_WARM:
937 rc = qpnp_adc_tm_write_reg(reg_low_thr_lsb, trip_cool_thr0);
938 if (rc) {
939 pr_err("adc-tm_tm read threshold err\n");
940 return rc;
941 }
942
943 rc = qpnp_adc_tm_write_reg(reg_low_thr_msb, trip_cool_thr1);
944 if (rc) {
945 pr_err("adc-tm_tm read threshold err\n");
946 return rc;
947 }
948 adc_tm_sensor->low_thr = tm_config.high_thr_voltage;
949 break;
950 case ADC_TM_TRIP_LOW_COOL:
951 rc = qpnp_adc_tm_write_reg(reg_high_thr_lsb, trip_warm_thr0);
952 if (rc) {
953 pr_err("adc-tm_tm read threshold err\n");
954 return rc;
955 }
956
957 rc = qpnp_adc_tm_write_reg(reg_high_thr_msb, trip_warm_thr1);
958 if (rc) {
959 pr_err("adc-tm_tm read threshold err\n");
960 return rc;
961 }
962 adc_tm_sensor->high_thr = tm_config.low_thr_voltage;
963 break;
964 default:
965 return -EINVAL;
966 }
967
968 return 0;
969}
970
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700971static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
972{
973 /* Battery therm's warm temperature translates to low voltage */
974 if (adc_tm->low_thr_notify) {
975 /* HIGH_STATE = WARM_TEMP for battery client */
976 adc_tm->btm_param->threshold_notification(
977 ADC_TM_WARM_STATE, adc_tm->btm_param->btm_ctx);
978 adc_tm->low_thr_notify = false;
979 }
980
981 /* Battery therm's cool temperature translates to high voltage */
982 if (adc_tm->high_thr_notify) {
983 /* LOW_STATE = COOL_TEMP for battery client */
984 adc_tm->btm_param->threshold_notification(
985 ADC_TM_COOL_STATE, adc_tm->btm_param->btm_ctx);
986 adc_tm->high_thr_notify = false;
987 }
988
989 return;
990}
991
992static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
993{
994 /* For non batt therm clients */
995 if (adc_tm->low_thr_notify) {
996 pr_debug("notify kernel with low state\n");
997 adc_tm->btm_param->threshold_notification(
998 ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
999 adc_tm->low_thr_notify = false;
1000 }
1001
1002 if (adc_tm->high_thr_notify) {
1003 pr_debug("notify kernel with high state\n");
1004 adc_tm->btm_param->threshold_notification(
1005 ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
1006 adc_tm->high_thr_notify = false;
1007 }
1008
1009 return;
1010}
1011
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001012static void notify_adc_tm_fn(struct work_struct *work)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001013{
1014 struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
1015 struct qpnp_adc_tm_sensor, work);
1016
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001017 if (adc_tm->thermal_node) {
1018 sysfs_notify(&adc_tm->tz_dev->device.kobj,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001019 NULL, "btm");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001020 pr_debug("notifying uspace client\n");
1021 } else {
1022 if (adc_tm->btm_param->threshold_notification != NULL) {
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001023 if (adc_tm->scale_type == SCALE_RBATT_THERM)
1024 notify_battery_therm(adc_tm);
1025 else
1026 notify_clients(adc_tm);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001027 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001028 }
1029
1030 return;
1031}
1032
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001033static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
1034 int trip, enum thermal_trip_activation_mode mode)
1035{
1036 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001037 int rc = 0, sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001038 u8 thr_int_en = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001039 bool state = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001040
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001041 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001042 return -EINVAL;
1043
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001044 if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
1045 state = true;
1046
1047 sensor_mask = 1 << adc_tm->sensor_num;
1048
1049 pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
1050
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001051 switch (trip) {
1052 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001053 /* low_thr (lower voltage) for higher temp */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001054 thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
1055 low_thr_int_chan_en;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001056 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001057 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001058 if (rc)
1059 pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
1060 break;
1061 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001062 /* high_thr (higher voltage) for cooler temp */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001063 thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
1064 high_thr_int_chan_en;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001065 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001066 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001067 if (rc)
1068 pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
1069 break;
1070 default:
1071 return -EINVAL;
1072 }
1073
1074 return rc;
1075}
1076
1077static int qpnp_adc_tm_read_status(void)
1078{
1079 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1080 u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
1081 u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001082 u8 sensor_mask = 0;
1083 int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0, btm_chan_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001084
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001085 if (!adc_tm || !adc_tm->adc_tm_initialized)
1086 return -ENODEV;
1087
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001088 mutex_lock(&adc_tm->adc->adc_lock);
1089
1090 rc = qpnp_adc_tm_req_sts_check();
1091 if (rc) {
1092 pr_err("adc-tm-tm req sts check failed with %d\n", rc);
1093 goto fail;
1094 }
1095
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001096 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW, &status_low);
1097 if (rc) {
1098 pr_err("adc-tm-tm read status low failed with %d\n", rc);
1099 goto fail;
1100 }
1101
1102 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH, &status_high);
1103 if (rc) {
1104 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1105 goto fail;
1106 }
1107
1108 /* Check which interrupt threshold is lower and measure against the
1109 * enabled channel */
1110 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
1111 &qpnp_adc_tm_meas_en);
1112 if (rc) {
1113 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1114 goto fail;
1115 }
1116
1117 adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
1118 adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
1119
1120 if (adc_tm_high_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001121 sensor_notify_num = adc_tm_high_enable;
1122 while (i < adc_tm->max_channels_available) {
1123 if ((sensor_notify_num & 0x1) == 1)
1124 sensor_num = i;
1125 sensor_notify_num >>= 1;
1126 i++;
1127 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001128
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001129 btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
1130 pr_debug("high:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1131 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1132 qpnp_adc_tm_meas_en);
1133 if (!adc_tm->sensor[sensor_num].thermal_node) {
1134 /* For non thermal registered clients
1135 such as usb_id, vbatt, pmic_therm */
1136 sensor_mask = 1 << sensor_num;
1137 pr_debug("non thermal node - mask:%x\n", sensor_mask);
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001138 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001139 QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001140 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001141 if (rc < 0) {
1142 pr_err("high threshold int read failed\n");
1143 goto fail;
1144 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001145 adc_tm->sensor[sensor_num].high_thr_notify = true;
1146 } else {
1147 /* Uses the thermal sysfs registered device to disable
1148 the corresponding high voltage threshold which
1149 is triggered by low temp */
1150 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001151 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001152 adc_tm->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001153 ADC_TM_TRIP_LOW_COOL,
1154 THERMAL_TRIP_ACTIVATION_DISABLED);
1155 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001156 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001157 goto fail;
1158 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001159 }
1160 }
1161
1162 if (adc_tm_low_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001163 sensor_notify_num = adc_tm_low_enable;
1164 i = 0;
1165 while (i < adc_tm->max_channels_available) {
1166 if ((sensor_notify_num & 0x1) == 1)
1167 sensor_num = i;
1168 sensor_notify_num >>= 1;
1169 i++;
1170 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001171
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001172 btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
1173 pr_debug("low:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1174 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1175 qpnp_adc_tm_meas_en);
1176 if (!adc_tm->sensor[sensor_num].thermal_node) {
1177 /* For non thermal registered clients
1178 such as usb_id, vbatt, pmic_therm */
1179 pr_debug("non thermal node - mask:%x\n", sensor_mask);
1180 sensor_mask = 1 << sensor_num;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001181 rc = qpnp_adc_tm_reg_update(
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001182 QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001183 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001184 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001185 pr_err("low threshold int read failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001186 goto fail;
1187 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001188 adc_tm->sensor[sensor_num].low_thr_notify = true;
1189 } else {
1190 /* Uses the thermal sysfs registered device to disable
1191 the corresponding low voltage threshold which
1192 is triggered by high temp */
1193 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001194 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001195 adc_tm->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001196 ADC_TM_TRIP_HIGH_WARM,
1197 THERMAL_TRIP_ACTIVATION_DISABLED);
1198 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001199 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001200 goto fail;
1201 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001202 }
1203 }
1204
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001205 if (adc_tm_high_enable || adc_tm_low_enable) {
1206 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
1207 sensor_mask, false);
1208 if (rc < 0) {
1209 pr_err("multi meas disable for channel failed\n");
1210 goto fail;
1211 }
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001212
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001213 rc = qpnp_adc_tm_enable_if_channel_meas();
1214 if (rc < 0) {
1215 pr_err("re-enabling measurement failed\n");
1216 return rc;
1217 }
1218 } else
1219 pr_debug("No threshold status enable %d for high/low??\n",
1220 sensor_mask);
1221
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001222fail:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001223 mutex_unlock(&adc_tm->adc->adc_lock);
1224
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001225 if (adc_tm_high_enable || adc_tm_low_enable)
1226 schedule_work(&adc_tm->sensor[sensor_num].work);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001227
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001228 return rc;
1229}
1230
1231static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
1232{
1233 int rc;
1234
1235 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001236 if (rc < 0)
1237 pr_err("adc-tm high thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001238
1239 return;
1240}
1241DECLARE_WORK(trigger_completion_adc_tm_high_thr_work,
1242 qpnp_adc_tm_high_thr_work);
1243
1244static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
1245{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001246 qpnp_adc_tm_disable();
1247
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001248 schedule_work(&trigger_completion_adc_tm_high_thr_work);
1249
1250 return IRQ_HANDLED;
1251}
1252
1253static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
1254{
1255 int rc;
1256
1257 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001258 if (rc < 0)
1259 pr_err("adc-tm low thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001260
1261 return;
1262}
1263DECLARE_WORK(trigger_completion_adc_tm_low_thr_work, qpnp_adc_tm_low_thr_work);
1264
1265static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
1266{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001267 qpnp_adc_tm_disable();
1268
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001269 schedule_work(&trigger_completion_adc_tm_low_thr_work);
1270
1271 return IRQ_HANDLED;
1272}
1273
1274static irqreturn_t qpnp_adc_tm_isr(int irq, void *dev_id)
1275{
1276 struct qpnp_adc_tm_drv *adc_tm = dev_id;
1277
1278 complete(&adc_tm->adc->adc_rslt_completion);
1279
1280 return IRQ_HANDLED;
1281}
1282
1283static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
1284 unsigned long *temp)
1285{
1286 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001287 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001288 struct qpnp_vadc_result result;
1289 int rc = 0;
1290
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001291 rc = qpnp_vadc_read(adc_tm->vadc_dev,
1292 adc_tm_sensor->vadc_channel_num, &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001293 if (rc)
1294 return rc;
1295
1296 *temp = result.physical;
1297
1298 return rc;
1299}
1300
1301static struct thermal_zone_device_ops qpnp_adc_tm_thermal_ops = {
1302 .get_temp = qpnp_adc_read_temp,
1303 .get_mode = qpnp_adc_tm_get_mode,
1304 .set_mode = qpnp_adc_tm_set_mode,
1305 .get_trip_type = qpnp_adc_tm_get_trip_type,
1306 .activate_trip_type = qpnp_adc_tm_activate_trip_type,
1307 .get_trip_temp = qpnp_adc_tm_get_trip_temp,
1308 .set_trip_temp = qpnp_adc_tm_set_trip_temp,
1309};
1310
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001311int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001312{
1313 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001314 uint32_t channel, dt_index = 0, scale_type = 0;
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001315 int rc = 0, i = 0;
1316 bool chan_found = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001317
1318 if (!adc_tm || !adc_tm->adc_tm_initialized)
1319 return -ENODEV;
1320
1321 if (param->threshold_notification == NULL) {
Siddartha Mohanadoss8707b512013-07-16 18:43:41 -07001322 pr_debug("No notification for high/low temp??\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001323 return -EINVAL;
1324 }
1325
1326 mutex_lock(&adc_tm->adc->adc_lock);
1327
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001328 channel = param->channel;
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001329 while (i < adc_tm->max_channels_available) {
1330 if (adc_tm->adc->adc_channels[i].channel_num ==
1331 channel) {
1332 dt_index = i;
1333 chan_found = true;
1334 i++;
1335 } else
1336 i++;
1337 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001338
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001339 if (!chan_found) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001340 pr_err("not a valid ADC_TM channel\n");
1341 rc = -EINVAL;
1342 goto fail_unlock;
1343 }
1344
1345 rc = qpnp_adc_tm_check_revision(
1346 adc_tm->sensor[dt_index].btm_channel_num);
1347 if (rc < 0)
1348 goto fail_unlock;
1349
1350 scale_type = adc_tm->adc->adc_channels[dt_index].adc_scale_fn;
1351 if (scale_type >= SCALE_RSCALE_NONE) {
1352 rc = -EBADF;
1353 goto fail_unlock;
1354 }
1355
1356 pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
1357 channel, scale_type, dt_index);
1358 adc_tm->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001359 adc_tm->adc->amux_prop->decimation =
Siddartha Mohanadossf4cdd132013-03-27 19:38:34 -07001360 adc_tm->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001361 adc_tm->adc->amux_prop->hw_settle_time =
Siddartha Mohanadossf4cdd132013-03-27 19:38:34 -07001362 adc_tm->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001363 adc_tm->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadossf4cdd132013-03-27 19:38:34 -07001364 adc_tm->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001365 adc_tm->adc->amux_prop->mode_sel =
1366 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
1367 adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
1368 ADC_MEAS1_INTERVAL_1S;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001369 adc_tm_rscale_fn[scale_type].chan(adc_tm->vadc_dev, param,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001370 &adc_tm->adc->amux_prop->chan_prop->low_thr,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001371 &adc_tm->adc->amux_prop->chan_prop->high_thr);
1372 adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001373 adc_tm->sensor[dt_index].btm_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001374 adc_tm->adc->amux_prop->chan_prop->timer_select =
1375 ADC_MEAS_TIMER_SELECT1;
1376 adc_tm->adc->amux_prop->chan_prop->state_request =
1377 param->state_request;
1378 rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
1379 if (rc) {
1380 pr_err("adc-tm configure failed with %d\n", rc);
1381 goto fail_unlock;
1382 }
1383
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001384 adc_tm->sensor[dt_index].btm_param = param;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001385 adc_tm->sensor[dt_index].scale_type = scale_type;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001386
1387fail_unlock:
1388 mutex_unlock(&adc_tm->adc->adc_lock);
1389
1390 return rc;
1391}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001392EXPORT_SYMBOL(qpnp_adc_tm_channel_measure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001393
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001394int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001395{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001396 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1397 uint32_t channel, dt_index = 0, btm_chan_num;
1398 u8 sensor_mask = 0;
1399 int rc = 0;
1400
1401 if (!adc_tm || !adc_tm->adc_tm_initialized)
1402 return -ENODEV;
1403
1404 mutex_lock(&adc_tm->adc->adc_lock);
1405
1406 /* Disable bank */
1407 rc = qpnp_adc_tm_disable();
1408 if (rc < 0) {
1409 pr_err("adc-tm disable failed\n");
1410 goto fail;
1411 }
1412
1413 /* Check if a conversion is in progress */
1414 rc = qpnp_adc_tm_req_sts_check();
1415 if (rc < 0) {
1416 pr_err("adc-tm req_sts check failed\n");
1417 goto fail;
1418 }
1419
1420 channel = param->channel;
1421 while ((adc_tm->adc->adc_channels[dt_index].channel_num
1422 != channel) && (dt_index < adc_tm->max_channels_available))
1423 dt_index++;
1424
1425 if (dt_index >= adc_tm->max_channels_available) {
1426 pr_err("not a valid ADC_TMN channel\n");
1427 rc = -EINVAL;
1428 goto fail;
1429 }
1430
1431 btm_chan_num = adc_tm->sensor[dt_index].btm_channel_num;
1432 sensor_mask = 1 << adc_tm->sensor[dt_index].sensor_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001433
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001434 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001435 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001436 if (rc < 0) {
1437 pr_err("low threshold int write failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001438 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001439 }
1440
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001441 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001442 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001443 if (rc < 0) {
1444 pr_err("high threshold int enable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001445 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001446 }
1447
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001448 rc = qpnp_adc_tm_reg_update(QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001449 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001450 if (rc < 0) {
1451 pr_err("multi measurement en failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001452 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001453 }
1454
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001455 rc = qpnp_adc_tm_enable_if_channel_meas();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001456 if (rc < 0)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001457 pr_err("re-enabling measurement failed\n");
1458
1459fail:
1460 mutex_unlock(&adc_tm->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001461
1462 return rc;
1463}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001464EXPORT_SYMBOL(qpnp_adc_tm_disable_chan_meas);
1465
1466int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_btm_param *param)
1467{
1468 param->channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
1469 return qpnp_adc_tm_channel_measure(param);
1470}
1471EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001472
1473int32_t qpnp_adc_tm_usbid_end(void)
1474{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001475 struct qpnp_adc_tm_btm_param param;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001476
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001477 return qpnp_adc_tm_disable_chan_meas(&param);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001478}
1479EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
1480
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001481int32_t qpnp_adc_tm_is_ready(void)
1482{
1483 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1484
1485 if (!adc_tm || !adc_tm->adc_tm_initialized)
1486 return -EPROBE_DEFER;
1487 else
1488 return 0;
1489}
1490EXPORT_SYMBOL(qpnp_adc_tm_is_ready);
1491
1492static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
1493{
1494 struct device_node *node = spmi->dev.of_node, *child;
1495 struct qpnp_adc_tm_drv *adc_tm;
1496 struct qpnp_adc_drv *adc_qpnp;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001497 int32_t count_adc_channel_list = 0, rc, sen_idx = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001498 u8 thr_init = 0;
1499
1500 if (!node)
1501 return -EINVAL;
1502
1503 if (qpnp_adc_tm) {
1504 pr_err("adc-tm already in use\n");
1505 return -EBUSY;
1506 }
1507
1508 for_each_child_of_node(node, child)
1509 count_adc_channel_list++;
1510
1511 if (!count_adc_channel_list) {
1512 pr_err("No channel listing\n");
1513 return -EINVAL;
1514 }
1515
1516 adc_tm = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_drv) +
1517 (count_adc_channel_list *
1518 sizeof(struct qpnp_adc_tm_sensor)),
1519 GFP_KERNEL);
1520 if (!adc_tm) {
1521 dev_err(&spmi->dev, "Unable to allocate memory\n");
1522 return -ENOMEM;
1523 }
1524
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001525 qpnp_adc_tm = adc_tm;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001526 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1527 GFP_KERNEL);
1528 if (!adc_qpnp) {
1529 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001530 rc = -ENOMEM;
1531 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001532 }
1533
1534 adc_tm->adc = adc_qpnp;
1535
1536 rc = qpnp_adc_get_devicetree_data(spmi, adc_tm->adc);
1537 if (rc) {
1538 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001539 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001540 }
Stephen Boydbeab4502013-04-25 10:18:17 -07001541 mutex_init(&adc_tm->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001542
1543 /* Register the ADC peripheral interrupt */
1544 adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
1545 NULL, "high-thr-en-set");
1546 if (adc_tm->adc->adc_high_thr_irq < 0) {
1547 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001548 rc = -ENXIO;
1549 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001550 }
1551
1552 adc_tm->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
1553 NULL, "low-thr-en-set");
1554 if (adc_tm->adc->adc_low_thr_irq < 0) {
1555 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001556 rc = -ENXIO;
1557 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001558 }
1559
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001560 adc_tm->vadc_dev = qpnp_get_vadc(&spmi->dev, "adc_tm");
1561 if (IS_ERR(adc_tm->vadc_dev)) {
1562 rc = PTR_ERR(adc_tm->vadc_dev);
1563 if (rc != -EPROBE_DEFER)
1564 pr_err("vadc property missing, rc=%d\n", rc);
1565 goto fail;
1566 }
1567
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001568 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_irq_eoc,
1569 qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
1570 "qpnp_adc_tm_interrupt", adc_tm);
1571 if (rc) {
1572 dev_err(&spmi->dev,
1573 "failed to request adc irq with error %d\n", rc);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001574 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001575 } else {
1576 enable_irq_wake(adc_tm->adc->adc_irq_eoc);
1577 }
1578
1579 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_high_thr_irq,
1580 qpnp_adc_tm_high_thr_isr,
1581 IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", adc_tm);
1582 if (rc) {
1583 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001584 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001585 } else {
1586 enable_irq_wake(adc_tm->adc->adc_high_thr_irq);
1587 }
1588
1589 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
1590 qpnp_adc_tm_low_thr_isr,
1591 IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
1592 if (rc) {
1593 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001594 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001595 } else {
1596 enable_irq_wake(adc_tm->adc->adc_low_thr_irq);
1597 }
1598
1599 for_each_child_of_node(node, child) {
1600 char name[25];
1601 int btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001602 bool thermal_node = false;
1603
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001604 rc = of_property_read_u32(child,
1605 "qcom,btm-channel-number", &btm_channel_num);
1606 if (rc) {
1607 pr_err("Invalid btm channel number\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001608 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001609 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001610 adc_tm->sensor[sen_idx].btm_channel_num = btm_channel_num;
1611 adc_tm->sensor[sen_idx].vadc_channel_num =
1612 adc_tm->adc->adc_channels[sen_idx].channel_num;
1613 adc_tm->sensor[sen_idx].sensor_num = sen_idx;
Siddartha Mohanadossb2795e42013-03-22 09:00:28 -07001614 pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
1615 adc_tm->adc->adc_channels[sen_idx].channel_num);
Siddartha Mohanadossea65d9e2013-04-16 18:26:39 -07001616 thermal_node = of_property_read_bool(child,
1617 "qcom,thermal-node");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001618 if (thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001619 /* Register with the thermal zone */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001620 pr_debug("thermal node%x\n", btm_channel_num);
1621 adc_tm->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
1622 adc_tm->sensor[sen_idx].thermal_node = true;
1623 snprintf(name, sizeof(name),
1624 adc_tm->adc->adc_channels[sen_idx].name);
1625 adc_tm->sensor[sen_idx].meas_interval =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001626 QPNP_ADC_TM_MEAS_INTERVAL;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001627 adc_tm->sensor[sen_idx].low_thr =
1628 QPNP_ADC_TM_M0_LOW_THR;
1629 adc_tm->sensor[sen_idx].high_thr =
1630 QPNP_ADC_TM_M0_HIGH_THR;
1631 adc_tm->sensor[sen_idx].tz_dev =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001632 thermal_zone_device_register(name,
1633 ADC_TM_TRIP_NUM,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001634 &adc_tm->sensor[sen_idx],
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001635 &qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001636 if (IS_ERR(adc_tm->sensor[sen_idx].tz_dev))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001637 pr_err("thermal device register failed.\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001638 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001639 INIT_WORK(&adc_tm->sensor[sen_idx].work, notify_adc_tm_fn);
1640 sen_idx++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001641 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001642 adc_tm->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001643 dev_set_drvdata(&spmi->dev, adc_tm);
1644 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_HIGH_THR_INT_EN, thr_init);
1645 if (rc < 0) {
1646 pr_err("high thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001647 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001648 }
1649
1650 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_LOW_THR_INT_EN, thr_init);
1651 if (rc < 0) {
1652 pr_err("low thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001653 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001654 }
1655
1656 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MULTI_MEAS_EN, thr_init);
1657 if (rc < 0) {
1658 pr_err("multi meas en failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001659 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001660 }
1661
1662 adc_tm->adc_tm_initialized = true;
1663
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001664 pr_debug("OK\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001665 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001666fail:
Siddartha Mohanadoss32019b52012-12-23 17:05:45 -08001667 qpnp_adc_tm = NULL;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001668 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001669}
1670
1671static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
1672{
1673 struct qpnp_adc_tm_drv *adc_tm = dev_get_drvdata(&spmi->dev);
1674 struct device_node *node = spmi->dev.of_node;
1675 struct device_node *child;
1676 int i = 0;
1677
1678 for_each_child_of_node(node, child) {
1679 thermal_zone_device_unregister(adc_tm->sensor[i].tz_dev);
1680 i++;
1681 }
1682
1683 adc_tm->adc_tm_initialized = false;
1684 dev_set_drvdata(&spmi->dev, NULL);
1685
1686 return 0;
1687}
1688
1689static const struct of_device_id qpnp_adc_tm_match_table[] = {
1690 { .compatible = "qcom,qpnp-adc-tm" },
1691 {}
1692};
1693
1694static struct spmi_driver qpnp_adc_tm_driver = {
1695 .driver = {
1696 .name = "qcom,qpnp-adc-tm",
1697 .of_match_table = qpnp_adc_tm_match_table,
1698 },
1699 .probe = qpnp_adc_tm_probe,
1700 .remove = qpnp_adc_tm_remove,
1701};
1702
1703static int __init qpnp_adc_tm_init(void)
1704{
1705 return spmi_driver_register(&qpnp_adc_tm_driver);
1706}
1707module_init(qpnp_adc_tm_init);
1708
1709static void __exit qpnp_adc_tm_exit(void)
1710{
1711 spmi_driver_unregister(&qpnp_adc_tm_driver);
1712}
1713module_exit(qpnp_adc_tm_exit);
1714
1715MODULE_DESCRIPTION("QPNP PMIC ADC Threshold Monitoring driver");
1716MODULE_LICENSE("GPL v2");