blob: e84220f1acc2b4c0a1b579bb8fd16b2d0412a96f [file] [log] [blame]
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/of.h>
18#include <linux/err.h>
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/delay.h>
22#include <linux/mutex.h>
23#include <linux/types.h>
24#include <linux/hwmon.h>
25#include <linux/module.h>
26#include <linux/debugfs.h>
27#include <linux/spmi.h>
28#include <linux/of_irq.h>
29#include <linux/wakelock.h>
30#include <linux/interrupt.h>
31#include <linux/completion.h>
32#include <linux/hwmon-sysfs.h>
33#include <linux/qpnp/qpnp-adc.h>
34#include <linux/thermal.h>
35#include <linux/platform_device.h>
36
37/* QPNP VADC TM register definition */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080038#define QPNP_REVISION3 0x3
39#define QPNP_REVISION_EIGHT_CHANNEL_SUPPORT 2
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080040#define QPNP_STATUS1 0x8
41#define QPNP_STATUS1_OP_MODE 4
42#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
43#define QPNP_STATUS1_REQ_STS BIT(1)
44#define QPNP_STATUS1_EOC BIT(0)
45#define QPNP_STATUS2 0x9
46#define QPNP_STATUS2_CONV_SEQ_STATE 6
47#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
48#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
49#define QPNP_CONV_TIMEOUT_ERR 2
50
51#define QPNP_MODE_CTL 0x40
52#define QPNP_OP_MODE_SHIFT 3
53#define QPNP_VREF_XO_THM_FORCE BIT(2)
54#define QPNP_AMUX_TRIM_EN BIT(1)
55#define QPNP_ADC_TRIM_EN BIT(0)
56#define QPNP_EN_CTL1 0x46
57#define QPNP_ADC_TM_EN BIT(7)
58#define QPNP_ADC_CH_SEL_CTL 0x48
59#define QPNP_ADC_DIG_PARAM 0x50
60#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 3
61#define QPNP_HW_SETTLE_DELAY 0x51
62#define QPNP_CONV_REQ 0x52
63#define QPNP_CONV_REQ_SET BIT(7)
64#define QPNP_CONV_SEQ_CTL 0x54
65#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
66#define QPNP_CONV_SEQ_TRIG_CTL 0x55
67#define QPNP_ADC_TM_MEAS_INTERVAL_CTL 0x57
68#define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT 0x3
69#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2 0x58
70#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT 0x4
71#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK 0xf0
72#define QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK 0xf
73
74#define QPNP_ADC_MEAS_INTERVAL_OP_CTL 0x59
75#define QPNP_ADC_MEAS_INTERVAL_OP BIT(7)
76
77#define QPNP_FAST_AVG_CTL 0x5a
78#define QPNP_FAST_AVG_EN 0x5b
79
80#define QPNP_M0_LOW_THR_LSB 0x5c
81#define QPNP_M0_LOW_THR_MSB 0x5d
82#define QPNP_M0_HIGH_THR_LSB 0x5e
83#define QPNP_M0_HIGH_THR_MSB 0x5f
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080084#define QPNP_M1_ADC_CH_SEL_CTL 0x68
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080085#define QPNP_M1_LOW_THR_LSB 0x69
86#define QPNP_M1_LOW_THR_MSB 0x6a
87#define QPNP_M1_HIGH_THR_LSB 0x6b
88#define QPNP_M1_HIGH_THR_MSB 0x6c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080089#define QPNP_M2_ADC_CH_SEL_CTL 0x70
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080090#define QPNP_M2_LOW_THR_LSB 0x71
91#define QPNP_M2_LOW_THR_MSB 0x72
92#define QPNP_M2_HIGH_THR_LSB 0x7b
93#define QPNP_M2_HIGH_THR_MSB 0x7c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080094#define QPNP_M3_ADC_CH_SEL_CTL 0x78
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080095#define QPNP_M3_LOW_THR_LSB 0x79
96#define QPNP_M3_LOW_THR_MSB 0x7a
97#define QPNP_M3_HIGH_THR_LSB 0x7b
98#define QPNP_M3_HIGH_THR_MSB 0x7c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080099#define QPNP_M4_ADC_CH_SEL_CTL 0x80
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800100#define QPNP_M4_LOW_THR_LSB 0x81
101#define QPNP_M4_LOW_THR_MSB 0x82
102#define QPNP_M4_HIGH_THR_LSB 0x83
103#define QPNP_M4_HIGH_THR_MSB 0x84
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800104#define QPNP_M5_ADC_CH_SEL_CTL 0x88
105#define QPNP_M5_LOW_THR_LSB 0x89
106#define QPNP_M5_LOW_THR_MSB 0x8a
107#define QPNP_M5_HIGH_THR_LSB 0x8b
108#define QPNP_M5_HIGH_THR_MSB 0x8c
109#define QPNP_M6_ADC_CH_SEL_CTL 0x90
110#define QPNP_M6_LOW_THR_LSB 0x91
111#define QPNP_M6_LOW_THR_MSB 0x92
112#define QPNP_M6_HIGH_THR_LSB 0x93
113#define QPNP_M6_HIGH_THR_MSB 0x94
114#define QPNP_M7_ADC_CH_SEL_CTL 0x98
115#define QPNP_M7_LOW_THR_LSB 0x99
116#define QPNP_M7_LOW_THR_MSB 0x9a
117#define QPNP_M7_HIGH_THR_LSB 0x9b
118#define QPNP_M7_HIGH_THR_MSB 0x9c
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800119
120#define QPNP_ADC_TM_MULTI_MEAS_EN 0x41
121#define QPNP_ADC_TM_MULTI_MEAS_EN_M0 BIT(0)
122#define QPNP_ADC_TM_MULTI_MEAS_EN_M1 BIT(1)
123#define QPNP_ADC_TM_MULTI_MEAS_EN_M2 BIT(2)
124#define QPNP_ADC_TM_MULTI_MEAS_EN_M3 BIT(3)
125#define QPNP_ADC_TM_MULTI_MEAS_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800126#define QPNP_ADC_TM_MULTI_MEAS_EN_M5 BIT(5)
127#define QPNP_ADC_TM_MULTI_MEAS_EN_M6 BIT(6)
128#define QPNP_ADC_TM_MULTI_MEAS_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800129#define QPNP_ADC_TM_LOW_THR_INT_EN 0x42
130#define QPNP_ADC_TM_LOW_THR_INT_EN_M0 BIT(0)
131#define QPNP_ADC_TM_LOW_THR_INT_EN_M1 BIT(1)
132#define QPNP_ADC_TM_LOW_THR_INT_EN_M2 BIT(2)
133#define QPNP_ADC_TM_LOW_THR_INT_EN_M3 BIT(3)
134#define QPNP_ADC_TM_LOW_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800135#define QPNP_ADC_TM_LOW_THR_INT_EN_M5 BIT(5)
136#define QPNP_ADC_TM_LOW_THR_INT_EN_M6 BIT(6)
137#define QPNP_ADC_TM_LOW_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800138#define QPNP_ADC_TM_HIGH_THR_INT_EN 0x43
139#define QPNP_ADC_TM_HIGH_THR_INT_EN_M0 BIT(0)
140#define QPNP_ADC_TM_HIGH_THR_INT_EN_M1 BIT(1)
141#define QPNP_ADC_TM_HIGH_THR_INT_EN_M2 BIT(2)
142#define QPNP_ADC_TM_HIGH_THR_INT_EN_M3 BIT(3)
143#define QPNP_ADC_TM_HIGH_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800144#define QPNP_ADC_TM_HIGH_THR_INT_EN_M5 BIT(5)
145#define QPNP_ADC_TM_HIGH_THR_INT_EN_M6 BIT(6)
146#define QPNP_ADC_TM_HIGH_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800147
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800148#define QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL 0x59
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800149#define QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL 0x6d
150#define QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL 0x75
151#define QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL 0x7d
152#define QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL 0x85
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800153#define QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL 0x8d
154#define QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL 0x95
155#define QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL 0x9d
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800156#define QPNP_ADC_TM_STATUS1 0x8
157#define QPNP_ADC_TM_STATUS_LOW 0xa
158#define QPNP_ADC_TM_STATUS_HIGH 0xb
159
160#define QPNP_ADC_TM_M0_LOW_THR 0x5d5c
161#define QPNP_ADC_TM_M0_HIGH_THR 0x5f5e
162#define QPNP_ADC_TM_MEAS_INTERVAL 0x0
163
164#define QPNP_ADC_TM_THR_LSB_MASK(val) (val & 0xff)
165#define QPNP_ADC_TM_THR_MSB_MASK(val) ((val & 0xff00) >> 8)
166
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800167#define QPNP_MIN_TIME 2000
168#define QPNP_MAX_TIME 2100
169
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800170struct qpnp_adc_tm_sensor {
171 struct thermal_zone_device *tz_dev;
172 enum thermal_device_mode mode;
173 uint32_t sensor_num;
174 enum qpnp_adc_meas_timer_select timer_select;
175 uint32_t meas_interval;
176 uint32_t low_thr;
177 uint32_t high_thr;
178 uint32_t btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800179 uint32_t vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800180 struct work_struct work;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800181 struct qpnp_adc_tm_btm_param *btm_param;
182 bool thermal_node;
183 bool low_thr_notify;
184 bool high_thr_notify;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800185};
186
187struct qpnp_adc_tm_drv {
188 struct qpnp_adc_drv *adc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800189 bool adc_tm_initialized;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800190 int max_channels_available;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800191 struct qpnp_adc_tm_sensor sensor[0];
192};
193
194struct qpnp_adc_tm_drv *qpnp_adc_tm;
195
196struct qpnp_adc_tm_trip_reg_type {
197 uint16_t low_thr_lsb_addr;
198 uint16_t low_thr_msb_addr;
199 uint16_t high_thr_lsb_addr;
200 uint16_t high_thr_msb_addr;
201 u8 multi_meas_en;
202 u8 low_thr_int_chan_en;
203 u8 high_thr_int_chan_en;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800204 u8 meas_interval_ctl;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800205};
206
207static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
208 [QPNP_ADC_TM_M0_ADC_CH_SEL_CTL] = {QPNP_M0_LOW_THR_LSB,
209 QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
210 QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800211 QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
212 QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800213 [QPNP_ADC_TM_M1_ADC_CH_SEL_CTL] = {QPNP_M1_LOW_THR_LSB,
214 QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
215 QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800216 QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
217 QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800218 [QPNP_ADC_TM_M2_ADC_CH_SEL_CTL] = {QPNP_M2_LOW_THR_LSB,
219 QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
220 QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800221 QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
222 QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800223 [QPNP_ADC_TM_M3_ADC_CH_SEL_CTL] = {QPNP_M3_LOW_THR_LSB,
224 QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
225 QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800226 QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
227 QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800228 [QPNP_ADC_TM_M4_ADC_CH_SEL_CTL] = {QPNP_M4_LOW_THR_LSB,
229 QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
230 QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800231 QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
232 QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
233 [QPNP_ADC_TM_M5_ADC_CH_SEL_CTL] = {QPNP_M5_LOW_THR_LSB,
234 QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
235 QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
236 QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
237 QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
238 [QPNP_ADC_TM_M6_ADC_CH_SEL_CTL] = {QPNP_M6_LOW_THR_LSB,
239 QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
240 QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
241 QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
242 QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
243 [QPNP_ADC_TM_M7_ADC_CH_SEL_CTL] = {QPNP_M7_LOW_THR_LSB,
244 QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
245 QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
246 QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
247 QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL},
248};
249
250static struct qpnp_adc_tm_reverse_scale_fn adc_tm_rscale_fn[] = {
251 [SCALE_R_VBATT] = {qpnp_adc_vbatt_rscaler},
252 [SCALE_RBATT_THERM] = {qpnp_adc_btm_scaler},
253 [SCALE_R_USB_ID] = {qpnp_adc_usb_scaler},
254 [SCALE_RPMIC_THERM] = {qpnp_adc_scale_millidegc_pmic_voltage_thr},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800255};
256
257static int32_t qpnp_adc_tm_read_reg(int16_t reg, u8 *data)
258{
259 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
260 int rc = 0;
261
262 rc = spmi_ext_register_readl(adc_tm->adc->spmi->ctrl,
263 adc_tm->adc->slave, (adc_tm->adc->offset + reg), data, 1);
264 if (rc < 0)
265 pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
266
267 return rc;
268}
269
270static int32_t qpnp_adc_tm_write_reg(int16_t reg, u8 data)
271{
272 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
273 int rc = 0;
274 u8 *buf;
275
276 buf = &data;
277
278 rc = spmi_ext_register_writel(adc_tm->adc->spmi->ctrl,
279 adc_tm->adc->slave, (adc_tm->adc->offset + reg), buf, 1);
280 if (rc < 0)
281 pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
282
283 return rc;
284}
285
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800286static int32_t qpnp_adc_tm_enable(void)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800287{
288 int rc = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800289 u8 data = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800290
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800291 data = QPNP_ADC_TM_EN;
292 rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
293 if (rc < 0)
294 pr_err("adc-tm enable failed\n");
295
296 return rc;
297}
298
299static int32_t qpnp_adc_tm_disable(void)
300{
301 u8 data = 0;
302 int rc = 0;
303
304 rc = qpnp_adc_tm_write_reg(QPNP_EN_CTL1, data);
305 if (rc < 0)
306 pr_err("adc-tm disable failed\n");
307
308 return rc;
309}
310
311static int32_t qpnp_adc_tm_enable_if_channel_meas(void)
312{
313 u8 adc_tm_meas_en = 0;
314 int rc = 0;
315
316 /* Check if a measurement request is still required */
317 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
318 &adc_tm_meas_en);
319 if (rc) {
320 pr_err("adc-tm-tm read status high failed with %d\n", rc);
321 return rc;
322 }
323
324 /* Enable only if there are pending measurement requests */
325 if (adc_tm_meas_en) {
326 qpnp_adc_tm_enable();
327
328 /* Request conversion */
329 rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800330 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800331 pr_err("adc-tm request conversion failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800332 return rc;
333 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800334 }
335
336 return rc;
337}
338
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800339static int32_t qpnp_adc_tm_req_sts_check(void)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800340{
341 u8 status1;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800342 int rc, count = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800343
344 /* The VADC_TM bank needs to be disabled for new conversion request */
345 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
346 if (rc) {
347 pr_err("adc-tm read status1 failed\n");
348 return rc;
349 }
350
351 /* Disable the bank if a conversion is occuring */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800352 while ((status1 & QPNP_STATUS1_REQ_STS) && (count < 5)) {
353 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS1, &status1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800354 if (rc < 0)
355 pr_err("adc-tm disable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800356 /* Wait time is based on the optimum sampling rate
357 * and adding enough time buffer to account for ADC conversions
358 * occuring on different peripheral banks */
359 usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
360 count++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800361 }
362
363 return rc;
364}
365
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800366static int32_t qpnp_adc_tm_check_revision(uint32_t btm_chan_num)
367{
368 u8 rev;
369 int rc = 0;
370
371 rc = qpnp_adc_tm_read_reg(QPNP_REVISION3, &rev);
372 if (rc) {
373 pr_err("adc-tm revision read failed\n");
374 return rc;
375 }
376
377 if ((rev < QPNP_REVISION_EIGHT_CHANNEL_SUPPORT) &&
378 (btm_chan_num > QPNP_ADC_TM_M4_ADC_CH_SEL_CTL)) {
379 pr_debug("Version does not support more than 5 channels\n");
380 return -EINVAL;
381 }
382
383 return rc;
384}
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800385static int32_t qpnp_adc_tm_mode_select(u8 mode_ctl)
386{
387 int rc;
388
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800389 mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
390
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800391 /* VADC_BTM current sets mode to recurring measurements */
392 rc = qpnp_adc_tm_write_reg(QPNP_MODE_CTL, mode_ctl);
393 if (rc < 0)
394 pr_err("adc-tm write mode selection err\n");
395
396 return rc;
397}
398
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800399static int32_t qpnp_adc_tm_timer_interval_select(uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800400 struct qpnp_vadc_chan_properties *chan_prop)
401{
402 int rc;
403 u8 meas_interval_timer2 = 0;
404
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800405 /* Configure kernel clients to timer1 */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800406 switch (chan_prop->timer_select) {
407 case ADC_MEAS_TIMER_SELECT1:
408 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL,
409 chan_prop->meas_interval1);
410 if (rc < 0) {
411 pr_err("timer1 configure failed\n");
412 return rc;
413 }
414 break;
415 case ADC_MEAS_TIMER_SELECT2:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800416 /* Thermal channels uses timer2, default to 1 second */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800417 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
418 &meas_interval_timer2);
419 if (rc < 0) {
420 pr_err("timer2 configure read failed\n");
421 return rc;
422 }
423 meas_interval_timer2 |=
424 (chan_prop->meas_interval2 <<
425 QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
426 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
427 meas_interval_timer2);
428 if (rc < 0) {
429 pr_err("timer2 configure failed\n");
430 return rc;
431 }
432 break;
433 case ADC_MEAS_TIMER_SELECT3:
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800434 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
435 &meas_interval_timer2);
436 if (rc < 0) {
437 pr_err("timer3 read failed\n");
438 return rc;
439 }
440 chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
441 meas_interval_timer2 |= chan_prop->meas_interval2;
442 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
443 meas_interval_timer2);
444 if (rc < 0) {
445 pr_err("timer3 configure failed\n");
446 return rc;
447 }
448 break;
449 default:
450 pr_err("Invalid timer selection\n");
451 return -EINVAL;
452 }
453
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800454 /* Select the timer to use for the corresponding channel */
455 adc_tm_data[btm_chan].meas_interval_ctl = chan_prop->timer_select;
456
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800457 return rc;
458}
459
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800460static int32_t qpnp_adc_tm_meas_int_update(uint16_t addr,
461 u8 mask, bool state)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800462{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800463 u8 reg_value = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800464 int rc = 0;
465
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800466 rc = qpnp_adc_tm_read_reg(addr, &reg_value);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800467 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800468 pr_err("read failed for addr:0x%x\n", addr);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800469 return rc;
470 }
471
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800472 reg_value = reg_value & ~mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800473 if (state)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800474 reg_value |= mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800475
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800476 pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n",
477 state, addr, reg_value, ~mask);
478 rc = qpnp_adc_tm_write_reg(addr, reg_value);
479 if (rc < 0) {
480 pr_err("write failed for addr:%x\n", addr);
481 return rc;
482 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800483
484 return rc;
485}
486
487static int32_t qpnp_adc_tm_usbid_btm_thr_en(uint32_t btm_chan,
488 struct qpnp_vadc_chan_properties *chan_prop)
489{
490 int rc = 0;
491
492 rc = qpnp_adc_tm_write_reg(
493 adc_tm_data[btm_chan].low_thr_lsb_addr,
494 QPNP_ADC_TM_THR_LSB_MASK(chan_prop->low_thr));
495 if (rc < 0) {
496 pr_err("low threshold lsb setting failed\n");
497 return rc;
498 }
499
500 rc = qpnp_adc_tm_write_reg(
501 adc_tm_data[btm_chan].low_thr_msb_addr,
502 QPNP_ADC_TM_THR_MSB_MASK(chan_prop->low_thr));
503 if (rc < 0) {
504 pr_err("low threshold msb setting failed\n");
505 return rc;
506 }
507
508 rc = qpnp_adc_tm_write_reg(
509 adc_tm_data[btm_chan].high_thr_lsb_addr,
510 QPNP_ADC_TM_THR_LSB_MASK(chan_prop->high_thr));
511 if (rc < 0) {
512 pr_err("high threshold lsb setting failed\n");
513 return rc;
514 }
515
516 rc = qpnp_adc_tm_write_reg(
517 adc_tm_data[btm_chan].high_thr_msb_addr,
518 QPNP_ADC_TM_THR_MSB_MASK(chan_prop->high_thr));
519 if (rc < 0)
520 pr_err("high threshold msb setting failed\n");
521
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800522 pr_debug("client requested high:%d and low:%d\n",
523 chan_prop->low_thr, chan_prop->high_thr);
524
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800525 return rc;
526}
527
528static int32_t qpnp_adc_tm_channel_configure(uint32_t btm_chan,
529 struct qpnp_vadc_chan_properties *chan_prop,
530 uint32_t amux_channel)
531{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800532 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
533 int rc = 0, i = 0, chan_idx = 0;
534 bool chan_found = false;
535 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800536
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800537 while (i < adc_tm->max_channels_available) {
538 if (adc_tm->sensor[i].btm_channel_num == btm_chan) {
539 chan_idx = i;
540 chan_found = true;
541 i++;
542 } else
543 i++;
544 }
545
546 if ((i == adc_tm->max_channels_available) && (!chan_found)) {
547 pr_err("Channel not found\n");
548 return -EINVAL;
549 }
550
551 sensor_mask = 1 << chan_idx;
552 if (!adc_tm->sensor[chan_idx].thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800553 /* Update low and high notification thresholds */
554 rc = qpnp_adc_tm_usbid_btm_thr_en(btm_chan,
555 chan_prop);
556 if (rc < 0) {
557 pr_err("setting chan:%d threshold failed\n", btm_chan);
558 return rc;
559 }
560
561 if ((chan_prop->state_request ==
562 ADC_TM_LOW_THR_ENABLE) ||
563 (chan_prop->state_request ==
564 ADC_TM_HIGH_LOW_THR_ENABLE)) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800565 pr_debug("low sensor mask:%x with state:%d\n",
566 sensor_mask, chan_prop->state_request);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800567 /* Enable low threshold's interrupt */
568 rc = qpnp_adc_tm_meas_int_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800569 QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800570 if (rc < 0) {
571 pr_err("low thr enable err:%d\n", btm_chan);
572 return rc;
573 }
574 }
575
576 if ((chan_prop->state_request ==
577 ADC_TM_HIGH_THR_ENABLE) ||
578 (chan_prop->state_request ==
579 ADC_TM_HIGH_LOW_THR_ENABLE)) {
580 /* Enable high threshold's interrupt */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800581 pr_debug("high sensor mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800582 rc = qpnp_adc_tm_meas_int_update(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800583 QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800584 if (rc < 0) {
585 pr_err("high thr enable err:%d\n", btm_chan);
586 return rc;
587 }
588 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800589 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800590
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800591 /* Enable corresponding BTM channel measurement */
592 rc = qpnp_adc_tm_meas_int_update(
593 QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
594 if (rc < 0) {
595 pr_err("multi measurement en failed\n");
596 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800597 }
598
599 return rc;
600}
601
602static int32_t qpnp_adc_tm_configure(
603 struct qpnp_adc_amux_properties *chan_prop)
604{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800605 u8 decimation = 0, op_cntrl = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800606 int rc = 0;
607 uint32_t btm_chan = 0;
608
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800609 /* Disable bank */
610 rc = qpnp_adc_tm_disable();
611 if (rc)
612 return rc;
613
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800614 /* Check if a conversion is in progress */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800615 rc = qpnp_adc_tm_req_sts_check();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800616 if (rc < 0) {
617 pr_err("adc-tm req_sts check failed\n");
618 return rc;
619 }
620
621 /* Set measurement in recurring mode */
622 rc = qpnp_adc_tm_mode_select(chan_prop->mode_sel);
623 if (rc < 0) {
624 pr_err("adc-tm mode select failed\n");
625 return rc;
626 }
627
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800628 /* Configure AMUX channel select for the corresponding BTM channel*/
629 btm_chan = chan_prop->chan_prop->tm_channel_select;
630 rc = qpnp_adc_tm_write_reg(btm_chan, chan_prop->amux_channel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800631 if (rc < 0) {
632 pr_err("adc-tm channel selection err\n");
633 return rc;
634 }
635
636 /* Digital paramater setup */
637 decimation |= chan_prop->decimation <<
638 QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
639 rc = qpnp_adc_tm_write_reg(QPNP_ADC_DIG_PARAM, decimation);
640 if (rc < 0) {
641 pr_err("adc-tm digital parameter setup err\n");
642 return rc;
643 }
644
645 /* Hardware setting time */
646 rc = qpnp_adc_tm_write_reg(QPNP_HW_SETTLE_DELAY,
647 chan_prop->hw_settle_time);
648 if (rc < 0) {
649 pr_err("adc-tm hw settling time setup err\n");
650 return rc;
651 }
652
653 /* Fast averaging setup */
654 rc = qpnp_adc_tm_write_reg(QPNP_FAST_AVG_CTL,
655 chan_prop->fast_avg_setup);
656 if (rc < 0) {
657 pr_err("adc-tm fast-avg setup err\n");
658 return rc;
659 }
660
661 /* Measurement interval setup */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800662 rc = qpnp_adc_tm_timer_interval_select(btm_chan,
663 chan_prop->chan_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800664 if (rc < 0) {
665 pr_err("adc-tm timer select failed\n");
666 return rc;
667 }
668
669 /* Channel configuration setup */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800670 rc = qpnp_adc_tm_channel_configure(btm_chan, chan_prop->chan_prop,
671 chan_prop->amux_channel);
672 if (rc < 0) {
673 pr_err("adc-tm channel configure failed\n");
674 return rc;
675 }
676
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800677 /* Recurring interval measurement enable */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800678 rc = qpnp_adc_tm_read_reg(QPNP_ADC_MEAS_INTERVAL_OP_CTL, &op_cntrl);
679 op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800680 rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_MEAS_INTERVAL_OP_CTL,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800681 op_cntrl, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800682 if (rc < 0) {
683 pr_err("adc-tm meas interval op configure failed\n");
684 return rc;
685 }
686
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800687 /* Enable bank */
688 rc = qpnp_adc_tm_enable();
689 if (rc)
690 return rc;
691
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800692 /* Request conversion */
693 rc = qpnp_adc_tm_write_reg(QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
694 if (rc < 0) {
695 pr_err("adc-tm request conversion failed\n");
696 return rc;
697 }
698
699 return 0;
700}
701
702static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
703 enum thermal_device_mode *mode)
704{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800705 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800706
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800707 if (!adc_tm_sensor || qpnp_adc_tm_check_revision(
708 adc_tm_sensor->btm_channel_num) || !mode)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800709 return -EINVAL;
710
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800711 *mode = adc_tm_sensor->mode;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800712
713 return 0;
714}
715
716static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
717 enum thermal_device_mode mode)
718{
719 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
720 struct qpnp_adc_tm_drv *adc_drv = qpnp_adc_tm;
721 int rc = 0, channel;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800722 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800723
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800724 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800725 return -EINVAL;
726
727 if (mode == THERMAL_DEVICE_ENABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800728 adc_drv->adc->amux_prop->amux_channel =
729 adc_tm->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800730 channel = adc_tm->sensor_num;
731 adc_drv->adc->amux_prop->decimation =
732 adc_drv->adc->adc_channels[channel].adc_decimation;
733 adc_drv->adc->amux_prop->hw_settle_time =
734 adc_drv->adc->adc_channels[channel].hw_settle_time;
735 adc_drv->adc->amux_prop->fast_avg_setup =
736 adc_drv->adc->adc_channels[channel].fast_avg_setup;
737 adc_drv->adc->amux_prop->mode_sel =
738 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
739 adc_drv->adc->amux_prop->chan_prop->timer_select =
740 ADC_MEAS_TIMER_SELECT1;
741 adc_drv->adc->amux_prop->chan_prop->meas_interval1 =
742 ADC_MEAS1_INTERVAL_1S;
743 adc_drv->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
744 adc_drv->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
745 adc_drv->adc->amux_prop->chan_prop->tm_channel_select =
746 adc_tm->btm_channel_num;
747
748 rc = qpnp_adc_tm_configure(adc_drv->adc->amux_prop);
749 if (rc) {
750 pr_err("adc-tm tm configure failed with %d\n", rc);
751 return -EINVAL;
752 }
753 } else if (mode == THERMAL_DEVICE_DISABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800754 sensor_mask = 1 << adc_tm->sensor_num;
755 /* Disable bank */
756 rc = qpnp_adc_tm_disable();
757 if (rc < 0) {
758 pr_err("adc-tm disable failed\n");
759 return rc;
760 }
761
762 /* Check if a conversion is in progress */
763 rc = qpnp_adc_tm_req_sts_check();
764 if (rc < 0) {
765 pr_err("adc-tm req_sts check failed\n");
766 return rc;
767 }
768
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800769 rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800770 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800771 if (rc < 0) {
772 pr_err("multi measurement update failed\n");
773 return rc;
774 }
775
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800776 rc = qpnp_adc_tm_enable_if_channel_meas();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800777 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800778 pr_err("re-enabling measurement failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800779 return rc;
780 }
781 }
782
783 adc_tm->mode = mode;
784
785 return 0;
786}
787
788static int qpnp_adc_tm_get_trip_type(struct thermal_zone_device *thermal,
789 int trip, enum thermal_trip_type *type)
790{
791 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
792
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800793 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num)
794 || !type || type < 0)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800795 return -EINVAL;
796
797 switch (trip) {
798 case ADC_TM_TRIP_HIGH_WARM:
799 *type = THERMAL_TRIP_CONFIGURABLE_HI;
800 break;
801 case ADC_TM_TRIP_LOW_COOL:
802 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
803 break;
804 default:
805 return -EINVAL;
806 }
807
808 return 0;
809}
810
811static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
812 int trip, unsigned long *temp)
813{
814 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
815 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
816 int64_t result = 0;
817 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
818 unsigned int reg, rc = 0, btm_channel_num;
819 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
820 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
821
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800822 if (!adc_tm || qpnp_adc_tm_check_revision(
823 adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800824 return -EINVAL;
825
826 btm_channel_num = adc_tm_sensor->btm_channel_num;
827 reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
828 reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
829 reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
830 reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
831
832 switch (trip) {
833 case ADC_TM_TRIP_HIGH_WARM:
834 rc = qpnp_adc_tm_read_reg(reg_low_thr_lsb, &trip_warm_thr0);
835 if (rc) {
836 pr_err("adc-tm low_thr_lsb err\n");
837 return rc;
838 }
839
840 rc = qpnp_adc_tm_read_reg(reg_low_thr_msb, &trip_warm_thr1);
841 if (rc) {
842 pr_err("adc-tm low_thr_msb err\n");
843 return rc;
844 }
845 reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
846 break;
847 case ADC_TM_TRIP_LOW_COOL:
848 rc = qpnp_adc_tm_read_reg(reg_high_thr_lsb, &trip_cool_thr0);
849 if (rc) {
850 pr_err("adc-tm_tm high_thr_lsb err\n");
851 return rc;
852 }
853
854 rc = qpnp_adc_tm_read_reg(reg_high_thr_msb, &trip_cool_thr1);
855 if (rc) {
856 pr_err("adc-tm_tm high_thr_lsb err\n");
857 return rc;
858 }
859 reg = (trip_cool_thr1 << 8) | trip_cool_thr0;
860 break;
861 default:
862 return -EINVAL;
863 }
864
865 rc = qpnp_adc_tm_scale_voltage_therm_pu2(reg, &result);
866 if (rc < 0) {
867 pr_err("Failed to lookup the therm thresholds\n");
868 return rc;
869 }
870
871 *temp = result;
872
873 return 0;
874}
875
876static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
877 int trip, long temp)
878{
879 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
880 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
881 struct qpnp_adc_tm_config tm_config;
882 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
883 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
884 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
885 int rc = 0, btm_channel_num;
886
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800887 if (!adc_tm || qpnp_adc_tm_check_revision(
888 adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800889 return -EINVAL;
890
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800891 tm_config.channel = adc_tm_sensor->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800892 switch (trip) {
893 case ADC_TM_TRIP_HIGH_WARM:
894 tm_config.high_thr_temp = temp;
895 break;
896 case ADC_TM_TRIP_LOW_COOL:
897 tm_config.low_thr_temp = temp;
898 break;
899 default:
900 return -EINVAL;
901 }
902
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800903 pr_debug("requested a high - %d and low - %d with trip - %d\n",
904 tm_config.high_thr_temp, tm_config.low_thr_temp, trip);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800905 rc = qpnp_adc_tm_scale_therm_voltage_pu2(&tm_config);
906 if (rc < 0) {
907 pr_err("Failed to lookup the adc-tm thresholds\n");
908 return rc;
909 }
910
911 trip_warm_thr0 = ((tm_config.low_thr_voltage << 24) >> 24);
912 trip_warm_thr1 = ((tm_config.low_thr_voltage << 16) >> 24);
913 trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
914 trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
915
916 btm_channel_num = adc_tm_sensor->btm_channel_num;
917 reg_low_thr_lsb = adc_tm_data[btm_channel_num].low_thr_lsb_addr;
918 reg_low_thr_msb = adc_tm_data[btm_channel_num].low_thr_msb_addr;
919 reg_high_thr_lsb = adc_tm_data[btm_channel_num].high_thr_lsb_addr;
920 reg_high_thr_msb = adc_tm_data[btm_channel_num].high_thr_msb_addr;
921
922 switch (trip) {
923 case ADC_TM_TRIP_HIGH_WARM:
924 rc = qpnp_adc_tm_write_reg(reg_low_thr_lsb, trip_cool_thr0);
925 if (rc) {
926 pr_err("adc-tm_tm read threshold err\n");
927 return rc;
928 }
929
930 rc = qpnp_adc_tm_write_reg(reg_low_thr_msb, trip_cool_thr1);
931 if (rc) {
932 pr_err("adc-tm_tm read threshold err\n");
933 return rc;
934 }
935 adc_tm_sensor->low_thr = tm_config.high_thr_voltage;
936 break;
937 case ADC_TM_TRIP_LOW_COOL:
938 rc = qpnp_adc_tm_write_reg(reg_high_thr_lsb, trip_warm_thr0);
939 if (rc) {
940 pr_err("adc-tm_tm read threshold err\n");
941 return rc;
942 }
943
944 rc = qpnp_adc_tm_write_reg(reg_high_thr_msb, trip_warm_thr1);
945 if (rc) {
946 pr_err("adc-tm_tm read threshold err\n");
947 return rc;
948 }
949 adc_tm_sensor->high_thr = tm_config.low_thr_voltage;
950 break;
951 default:
952 return -EINVAL;
953 }
954
955 return 0;
956}
957
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800958static void notify_adc_tm_fn(struct work_struct *work)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800959{
960 struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
961 struct qpnp_adc_tm_sensor, work);
962
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800963 if (adc_tm->thermal_node) {
964 sysfs_notify(&adc_tm->tz_dev->device.kobj,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800965 NULL, "btm");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800966 pr_debug("notifying uspace client\n");
967 } else {
968 if (adc_tm->btm_param->threshold_notification != NULL) {
969 if (adc_tm->low_thr_notify) {
970 pr_debug("notify kernel with low state\n");
971 adc_tm->btm_param->threshold_notification(
972 ADC_TM_LOW_STATE, adc_tm->btm_param->btm_ctx);
973 adc_tm->low_thr_notify = false;
974 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800975
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800976 if (adc_tm->high_thr_notify) {
977 pr_debug("notify kernel with high state\n");
978 adc_tm->btm_param->threshold_notification(
979 ADC_TM_HIGH_STATE, adc_tm->btm_param->btm_ctx);
980 adc_tm->high_thr_notify = false;
981 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800982 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800983 }
984
985 return;
986}
987
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800988static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
989 int trip, enum thermal_trip_activation_mode mode)
990{
991 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800992 int rc = 0, sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800993 u8 thr_int_en = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800994 bool state = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800995
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800996 if (!adc_tm || qpnp_adc_tm_check_revision(adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800997 return -EINVAL;
998
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800999 if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
1000 state = true;
1001
1002 sensor_mask = 1 << adc_tm->sensor_num;
1003
1004 pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
1005
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001006 switch (trip) {
1007 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001008 /* low_thr (lower voltage) for higher temp */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001009 thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
1010 low_thr_int_chan_en;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001011 rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_LOW_THR_INT_EN,
1012 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001013 if (rc)
1014 pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
1015 break;
1016 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001017 /* high_thr (higher voltage) for cooler temp */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001018 thr_int_en = adc_tm_data[adc_tm->btm_channel_num].
1019 high_thr_int_chan_en;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001020 rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
1021 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001022 if (rc)
1023 pr_err("channel:%x failed\n", adc_tm->btm_channel_num);
1024 break;
1025 default:
1026 return -EINVAL;
1027 }
1028
1029 return rc;
1030}
1031
1032static int qpnp_adc_tm_read_status(void)
1033{
1034 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1035 u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
1036 u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001037 u8 sensor_mask = 0;
1038 int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0, btm_chan_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001039
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001040 if (!adc_tm || !adc_tm->adc_tm_initialized)
1041 return -ENODEV;
1042
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001043 mutex_lock(&adc_tm->adc->adc_lock);
1044
1045 rc = qpnp_adc_tm_req_sts_check();
1046 if (rc) {
1047 pr_err("adc-tm-tm req sts check failed with %d\n", rc);
1048 goto fail;
1049 }
1050
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001051 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_LOW, &status_low);
1052 if (rc) {
1053 pr_err("adc-tm-tm read status low failed with %d\n", rc);
1054 goto fail;
1055 }
1056
1057 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_STATUS_HIGH, &status_high);
1058 if (rc) {
1059 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1060 goto fail;
1061 }
1062
1063 /* Check which interrupt threshold is lower and measure against the
1064 * enabled channel */
1065 rc = qpnp_adc_tm_read_reg(QPNP_ADC_TM_MULTI_MEAS_EN,
1066 &qpnp_adc_tm_meas_en);
1067 if (rc) {
1068 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1069 goto fail;
1070 }
1071
1072 adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
1073 adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
1074
1075 if (adc_tm_high_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001076 sensor_notify_num = adc_tm_high_enable;
1077 while (i < adc_tm->max_channels_available) {
1078 if ((sensor_notify_num & 0x1) == 1)
1079 sensor_num = i;
1080 sensor_notify_num >>= 1;
1081 i++;
1082 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001083
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001084 btm_chan_num = adc_tm->sensor[sensor_num].btm_channel_num;
1085 pr_debug("high:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1086 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1087 qpnp_adc_tm_meas_en);
1088 if (!adc_tm->sensor[sensor_num].thermal_node) {
1089 /* For non thermal registered clients
1090 such as usb_id, vbatt, pmic_therm */
1091 sensor_mask = 1 << sensor_num;
1092 pr_debug("non thermal node - mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001093 rc = qpnp_adc_tm_meas_int_update(
1094 QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001095 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001096 if (rc < 0) {
1097 pr_err("high threshold int read failed\n");
1098 goto fail;
1099 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001100 adc_tm->sensor[sensor_num].high_thr_notify = true;
1101 } else {
1102 /* Uses the thermal sysfs registered device to disable
1103 the corresponding high voltage threshold which
1104 is triggered by low temp */
1105 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001106 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001107 adc_tm->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001108 ADC_TM_TRIP_LOW_COOL,
1109 THERMAL_TRIP_ACTIVATION_DISABLED);
1110 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001111 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001112 goto fail;
1113 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001114 }
1115 }
1116
1117 if (adc_tm_low_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001118 sensor_notify_num = adc_tm_low_enable;
1119 i = 0;
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("low: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 pr_debug("non thermal node - mask:%x\n", sensor_mask);
1135 sensor_mask = 1 << sensor_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001136 rc = qpnp_adc_tm_meas_int_update(
1137 QPNP_ADC_TM_LOW_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) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001140 pr_err("low threshold int read failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001141 goto fail;
1142 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001143 adc_tm->sensor[sensor_num].low_thr_notify = true;
1144 } else {
1145 /* Uses the thermal sysfs registered device to disable
1146 the corresponding low voltage threshold which
1147 is triggered by high 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_HIGH_WARM,
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
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001160 rc = qpnp_adc_tm_enable_if_channel_meas();
1161 if (rc < 0) {
1162 pr_err("re-enabling measurement failed\n");
1163 return rc;
1164 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001165fail:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001166 mutex_unlock(&adc_tm->adc->adc_lock);
1167
1168 schedule_work(&adc_tm->sensor[sensor_num].work);
1169
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001170 return rc;
1171}
1172
1173static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
1174{
1175 int rc;
1176
1177 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001178 if (rc < 0)
1179 pr_err("adc-tm high thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001180
1181 return;
1182}
1183DECLARE_WORK(trigger_completion_adc_tm_high_thr_work,
1184 qpnp_adc_tm_high_thr_work);
1185
1186static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
1187{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001188 qpnp_adc_tm_disable();
1189
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001190 schedule_work(&trigger_completion_adc_tm_high_thr_work);
1191
1192 return IRQ_HANDLED;
1193}
1194
1195static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
1196{
1197 int rc;
1198
1199 rc = qpnp_adc_tm_read_status();
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001200 if (rc < 0)
1201 pr_err("adc-tm low thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001202
1203 return;
1204}
1205DECLARE_WORK(trigger_completion_adc_tm_low_thr_work, qpnp_adc_tm_low_thr_work);
1206
1207static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
1208{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001209 qpnp_adc_tm_disable();
1210
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001211 schedule_work(&trigger_completion_adc_tm_low_thr_work);
1212
1213 return IRQ_HANDLED;
1214}
1215
1216static irqreturn_t qpnp_adc_tm_isr(int irq, void *dev_id)
1217{
1218 struct qpnp_adc_tm_drv *adc_tm = dev_id;
1219
1220 complete(&adc_tm->adc->adc_rslt_completion);
1221
1222 return IRQ_HANDLED;
1223}
1224
1225static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
1226 unsigned long *temp)
1227{
1228 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
1229 struct qpnp_vadc_result result;
1230 int rc = 0;
1231
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001232 rc = qpnp_vadc_read(adc_tm_sensor->vadc_channel_num, &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001233 if (rc)
1234 return rc;
1235
1236 *temp = result.physical;
1237
1238 return rc;
1239}
1240
1241static struct thermal_zone_device_ops qpnp_adc_tm_thermal_ops = {
1242 .get_temp = qpnp_adc_read_temp,
1243 .get_mode = qpnp_adc_tm_get_mode,
1244 .set_mode = qpnp_adc_tm_set_mode,
1245 .get_trip_type = qpnp_adc_tm_get_trip_type,
1246 .activate_trip_type = qpnp_adc_tm_activate_trip_type,
1247 .get_trip_temp = qpnp_adc_tm_get_trip_temp,
1248 .set_trip_temp = qpnp_adc_tm_set_trip_temp,
1249};
1250
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001251int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001252{
1253 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001254 uint32_t channel, dt_index = 0, scale_type = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001255 int rc = 0;
1256
1257 if (!adc_tm || !adc_tm->adc_tm_initialized)
1258 return -ENODEV;
1259
1260 if (param->threshold_notification == NULL) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001261 pr_err("No notification for high/low temp??\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001262 return -EINVAL;
1263 }
1264
1265 mutex_lock(&adc_tm->adc->adc_lock);
1266
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001267 channel = param->channel;
1268 while ((adc_tm->adc->adc_channels[dt_index].channel_num
1269 != channel) && (dt_index < adc_tm->max_channels_available))
1270 dt_index++;
1271
1272 if (dt_index >= adc_tm->max_channels_available) {
1273 pr_err("not a valid ADC_TM channel\n");
1274 rc = -EINVAL;
1275 goto fail_unlock;
1276 }
1277
1278 rc = qpnp_adc_tm_check_revision(
1279 adc_tm->sensor[dt_index].btm_channel_num);
1280 if (rc < 0)
1281 goto fail_unlock;
1282
1283 scale_type = adc_tm->adc->adc_channels[dt_index].adc_scale_fn;
1284 if (scale_type >= SCALE_RSCALE_NONE) {
1285 rc = -EBADF;
1286 goto fail_unlock;
1287 }
1288
1289 pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
1290 channel, scale_type, dt_index);
1291 adc_tm->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001292 adc_tm->adc->amux_prop->decimation =
1293 adc_tm->adc->adc_channels[channel].adc_decimation;
1294 adc_tm->adc->amux_prop->hw_settle_time =
1295 adc_tm->adc->adc_channels[channel].hw_settle_time;
1296 adc_tm->adc->amux_prop->fast_avg_setup =
1297 adc_tm->adc->adc_channels[channel].fast_avg_setup;
1298 adc_tm->adc->amux_prop->mode_sel =
1299 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
1300 adc_tm->adc->amux_prop->chan_prop->meas_interval1 =
1301 ADC_MEAS1_INTERVAL_1S;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001302 adc_tm_rscale_fn[scale_type].chan(param,
1303 &adc_tm->adc->amux_prop->chan_prop->low_thr,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001304 &adc_tm->adc->amux_prop->chan_prop->high_thr);
1305 adc_tm->adc->amux_prop->chan_prop->tm_channel_select =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001306 adc_tm->sensor[dt_index].btm_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001307 adc_tm->adc->amux_prop->chan_prop->timer_select =
1308 ADC_MEAS_TIMER_SELECT1;
1309 adc_tm->adc->amux_prop->chan_prop->state_request =
1310 param->state_request;
1311 rc = qpnp_adc_tm_configure(adc_tm->adc->amux_prop);
1312 if (rc) {
1313 pr_err("adc-tm configure failed with %d\n", rc);
1314 goto fail_unlock;
1315 }
1316
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001317 adc_tm->sensor[dt_index].btm_param = param;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001318
1319fail_unlock:
1320 mutex_unlock(&adc_tm->adc->adc_lock);
1321
1322 return rc;
1323}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001324EXPORT_SYMBOL(qpnp_adc_tm_channel_measure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001325
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001326int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001327{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001328 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1329 uint32_t channel, dt_index = 0, btm_chan_num;
1330 u8 sensor_mask = 0;
1331 int rc = 0;
1332
1333 if (!adc_tm || !adc_tm->adc_tm_initialized)
1334 return -ENODEV;
1335
1336 mutex_lock(&adc_tm->adc->adc_lock);
1337
1338 /* Disable bank */
1339 rc = qpnp_adc_tm_disable();
1340 if (rc < 0) {
1341 pr_err("adc-tm disable failed\n");
1342 goto fail;
1343 }
1344
1345 /* Check if a conversion is in progress */
1346 rc = qpnp_adc_tm_req_sts_check();
1347 if (rc < 0) {
1348 pr_err("adc-tm req_sts check failed\n");
1349 goto fail;
1350 }
1351
1352 channel = param->channel;
1353 while ((adc_tm->adc->adc_channels[dt_index].channel_num
1354 != channel) && (dt_index < adc_tm->max_channels_available))
1355 dt_index++;
1356
1357 if (dt_index >= adc_tm->max_channels_available) {
1358 pr_err("not a valid ADC_TMN channel\n");
1359 rc = -EINVAL;
1360 goto fail;
1361 }
1362
1363 btm_chan_num = adc_tm->sensor[dt_index].btm_channel_num;
1364 sensor_mask = 1 << adc_tm->sensor[dt_index].sensor_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001365
1366 rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001367 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001368 if (rc < 0) {
1369 pr_err("low threshold int write failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001370 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001371 }
1372
1373 rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001374 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001375 if (rc < 0) {
1376 pr_err("high threshold int enable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001377 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001378 }
1379
1380 rc = qpnp_adc_tm_meas_int_update(QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001381 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001382 if (rc < 0) {
1383 pr_err("multi measurement en failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001384 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001385 }
1386
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001387 rc = qpnp_adc_tm_enable_if_channel_meas();
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001388 if (rc < 0)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001389 pr_err("re-enabling measurement failed\n");
1390
1391fail:
1392 mutex_unlock(&adc_tm->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001393
1394 return rc;
1395}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001396EXPORT_SYMBOL(qpnp_adc_tm_disable_chan_meas);
1397
1398int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_btm_param *param)
1399{
1400 param->channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
1401 return qpnp_adc_tm_channel_measure(param);
1402}
1403EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001404
1405int32_t qpnp_adc_tm_usbid_end(void)
1406{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001407 struct qpnp_adc_tm_btm_param param;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001408
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001409 return qpnp_adc_tm_disable_chan_meas(&param);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001410}
1411EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
1412
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001413int32_t qpnp_adc_tm_is_ready(void)
1414{
1415 struct qpnp_adc_tm_drv *adc_tm = qpnp_adc_tm;
1416
1417 if (!adc_tm || !adc_tm->adc_tm_initialized)
1418 return -EPROBE_DEFER;
1419 else
1420 return 0;
1421}
1422EXPORT_SYMBOL(qpnp_adc_tm_is_ready);
1423
1424static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
1425{
1426 struct device_node *node = spmi->dev.of_node, *child;
1427 struct qpnp_adc_tm_drv *adc_tm;
1428 struct qpnp_adc_drv *adc_qpnp;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001429 int32_t count_adc_channel_list = 0, rc, sen_idx = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001430 u8 thr_init = 0;
1431
1432 if (!node)
1433 return -EINVAL;
1434
1435 if (qpnp_adc_tm) {
1436 pr_err("adc-tm already in use\n");
1437 return -EBUSY;
1438 }
1439
1440 for_each_child_of_node(node, child)
1441 count_adc_channel_list++;
1442
1443 if (!count_adc_channel_list) {
1444 pr_err("No channel listing\n");
1445 return -EINVAL;
1446 }
1447
1448 adc_tm = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_drv) +
1449 (count_adc_channel_list *
1450 sizeof(struct qpnp_adc_tm_sensor)),
1451 GFP_KERNEL);
1452 if (!adc_tm) {
1453 dev_err(&spmi->dev, "Unable to allocate memory\n");
1454 return -ENOMEM;
1455 }
1456
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001457 qpnp_adc_tm = adc_tm;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001458 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1459 GFP_KERNEL);
1460 if (!adc_qpnp) {
1461 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001462 rc = -ENOMEM;
1463 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001464 }
1465
1466 adc_tm->adc = adc_qpnp;
1467
1468 rc = qpnp_adc_get_devicetree_data(spmi, adc_tm->adc);
1469 if (rc) {
1470 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001471 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001472 }
1473
1474 /* Register the ADC peripheral interrupt */
1475 adc_tm->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
1476 NULL, "high-thr-en-set");
1477 if (adc_tm->adc->adc_high_thr_irq < 0) {
1478 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001479 rc = -ENXIO;
1480 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001481 }
1482
1483 adc_tm->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
1484 NULL, "low-thr-en-set");
1485 if (adc_tm->adc->adc_low_thr_irq < 0) {
1486 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001487 rc = -ENXIO;
1488 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001489 }
1490
1491 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_irq_eoc,
1492 qpnp_adc_tm_isr, IRQF_TRIGGER_RISING,
1493 "qpnp_adc_tm_interrupt", adc_tm);
1494 if (rc) {
1495 dev_err(&spmi->dev,
1496 "failed to request adc irq with error %d\n", rc);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001497 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001498 } else {
1499 enable_irq_wake(adc_tm->adc->adc_irq_eoc);
1500 }
1501
1502 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_high_thr_irq,
1503 qpnp_adc_tm_high_thr_isr,
1504 IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", adc_tm);
1505 if (rc) {
1506 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001507 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001508 } else {
1509 enable_irq_wake(adc_tm->adc->adc_high_thr_irq);
1510 }
1511
1512 rc = devm_request_irq(&spmi->dev, adc_tm->adc->adc_low_thr_irq,
1513 qpnp_adc_tm_low_thr_isr,
1514 IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", adc_tm);
1515 if (rc) {
1516 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001517 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001518 } else {
1519 enable_irq_wake(adc_tm->adc->adc_low_thr_irq);
1520 }
1521
1522 for_each_child_of_node(node, child) {
1523 char name[25];
1524 int btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001525 bool thermal_node = false;
1526
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001527 rc = of_property_read_u32(child,
1528 "qcom,btm-channel-number", &btm_channel_num);
1529 if (rc) {
1530 pr_err("Invalid btm channel number\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001531 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001532 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001533 adc_tm->sensor[sen_idx].btm_channel_num = btm_channel_num;
1534 adc_tm->sensor[sen_idx].vadc_channel_num =
1535 adc_tm->adc->adc_channels[sen_idx].channel_num;
1536 adc_tm->sensor[sen_idx].sensor_num = sen_idx;
1537 if (thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001538 /* Register with the thermal zone */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001539 pr_debug("thermal node%x\n", btm_channel_num);
1540 adc_tm->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
1541 adc_tm->sensor[sen_idx].thermal_node = true;
1542 snprintf(name, sizeof(name),
1543 adc_tm->adc->adc_channels[sen_idx].name);
1544 adc_tm->sensor[sen_idx].meas_interval =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001545 QPNP_ADC_TM_MEAS_INTERVAL;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001546 adc_tm->sensor[sen_idx].low_thr =
1547 QPNP_ADC_TM_M0_LOW_THR;
1548 adc_tm->sensor[sen_idx].high_thr =
1549 QPNP_ADC_TM_M0_HIGH_THR;
1550 adc_tm->sensor[sen_idx].tz_dev =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001551 thermal_zone_device_register(name,
1552 ADC_TM_TRIP_NUM,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001553 &adc_tm->sensor[sen_idx],
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001554 &qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001555 if (IS_ERR(adc_tm->sensor[sen_idx].tz_dev))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001556 pr_err("thermal device register failed.\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001557 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001558 INIT_WORK(&adc_tm->sensor[sen_idx].work, notify_adc_tm_fn);
1559 sen_idx++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001560 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001561 adc_tm->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001562 dev_set_drvdata(&spmi->dev, adc_tm);
1563 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_HIGH_THR_INT_EN, thr_init);
1564 if (rc < 0) {
1565 pr_err("high thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001566 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001567 }
1568
1569 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_LOW_THR_INT_EN, thr_init);
1570 if (rc < 0) {
1571 pr_err("low thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001572 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001573 }
1574
1575 rc = qpnp_adc_tm_write_reg(QPNP_ADC_TM_MULTI_MEAS_EN, thr_init);
1576 if (rc < 0) {
1577 pr_err("multi meas en failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001578 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001579 }
1580
1581 adc_tm->adc_tm_initialized = true;
1582
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001583 pr_debug("OK\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001584 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001585fail:
Siddartha Mohanadoss32019b52012-12-23 17:05:45 -08001586 qpnp_adc_tm = NULL;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001587 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001588}
1589
1590static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
1591{
1592 struct qpnp_adc_tm_drv *adc_tm = dev_get_drvdata(&spmi->dev);
1593 struct device_node *node = spmi->dev.of_node;
1594 struct device_node *child;
1595 int i = 0;
1596
1597 for_each_child_of_node(node, child) {
1598 thermal_zone_device_unregister(adc_tm->sensor[i].tz_dev);
1599 i++;
1600 }
1601
1602 adc_tm->adc_tm_initialized = false;
1603 dev_set_drvdata(&spmi->dev, NULL);
1604
1605 return 0;
1606}
1607
1608static const struct of_device_id qpnp_adc_tm_match_table[] = {
1609 { .compatible = "qcom,qpnp-adc-tm" },
1610 {}
1611};
1612
1613static struct spmi_driver qpnp_adc_tm_driver = {
1614 .driver = {
1615 .name = "qcom,qpnp-adc-tm",
1616 .of_match_table = qpnp_adc_tm_match_table,
1617 },
1618 .probe = qpnp_adc_tm_probe,
1619 .remove = qpnp_adc_tm_remove,
1620};
1621
1622static int __init qpnp_adc_tm_init(void)
1623{
1624 return spmi_driver_register(&qpnp_adc_tm_driver);
1625}
1626module_init(qpnp_adc_tm_init);
1627
1628static void __exit qpnp_adc_tm_exit(void)
1629{
1630 spmi_driver_unregister(&qpnp_adc_tm_driver);
1631}
1632module_exit(qpnp_adc_tm_exit);
1633
1634MODULE_DESCRIPTION("QPNP PMIC ADC Threshold Monitoring driver");
1635MODULE_LICENSE("GPL v2");