blob: d296a47076fa5f24f8ceee36fd03396de49d410b [file] [log] [blame]
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07002 *
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#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/kernel.h>
16#include <linux/of.h>
17#include <linux/err.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/delay.h>
21#include <linux/mutex.h>
22#include <linux/types.h>
23#include <linux/hwmon.h>
24#include <linux/module.h>
25#include <linux/debugfs.h>
26#include <linux/spmi.h>
27#include <linux/of_irq.h>
28#include <linux/interrupt.h>
29#include <linux/completion.h>
30#include <linux/hwmon-sysfs.h>
31#include <linux/qpnp/qpnp-adc.h>
32#include <linux/platform_device.h>
33
34/* QPNP VADC register definition */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070035#define QPNP_VADC_REVISION1 0x0
36#define QPNP_VADC_REVISION2 0x1
37#define QPNP_VADC_REVISION3 0x2
38#define QPNP_VADC_REVISION4 0x3
39#define QPNP_VADC_PERPH_TYPE 0x4
40#define QPNP_VADC_PERH_SUBTYPE 0x5
41
42#define QPNP_VADC_SUPPORTED_REVISION2 1
43
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070044#define QPNP_VADC_STATUS1 0x8
45#define QPNP_VADC_STATUS1_OP_MODE 4
46#define QPNP_VADC_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
47#define QPNP_VADC_STATUS1_REQ_STS BIT(1)
48#define QPNP_VADC_STATUS1_EOC BIT(0)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -070049#define QPNP_VADC_STATUS1_REQ_STS_EOC_MASK 0x3
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070050#define QPNP_VADC_STATUS2 0x9
51#define QPNP_VADC_STATUS2_CONV_SEQ_STATE 6
52#define QPNP_VADC_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
53#define QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
54#define QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT 4
55#define QPNP_VADC_CONV_TIMEOUT_ERR 2
56
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070057#define QPNP_VADC_MODE_CTL 0x40
58#define QPNP_VADC_OP_MODE_SHIFT 4
59#define QPNP_VADC_VREF_XO_THM_FORCE BIT(2)
60#define QPNP_VADC_AMUX_TRIM_EN BIT(1)
61#define QPNP_VADC_ADC_TRIM_EN BIT(0)
62#define QPNP_VADC_EN_CTL1 0x46
63#define QPNP_VADC_ADC_EN BIT(7)
64#define QPNP_VADC_ADC_CH_SEL_CTL 0x48
65#define QPNP_VADC_ADC_DIG_PARAM 0x50
66#define QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT 3
67#define QPNP_VADC_HW_SETTLE_DELAY 0x51
68#define QPNP_VADC_CONV_REQ 0x52
69#define QPNP_VADC_CONV_REQ_SET BIT(7)
70#define QPNP_VADC_CONV_SEQ_CTL 0x54
71#define QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT 4
72#define QPNP_VADC_CONV_SEQ_TRIG_CTL 0x55
73#define QPNP_VADC_CONV_SEQ_FALLING_EDGE 0x0
74#define QPNP_VADC_CONV_SEQ_RISING_EDGE 0x1
75#define QPNP_VADC_CONV_SEQ_EDGE_SHIFT 7
76#define QPNP_VADC_FAST_AVG_CTL 0x5a
77
78#define QPNP_VADC_M0_LOW_THR_LSB 0x5c
79#define QPNP_VADC_M0_LOW_THR_MSB 0x5d
80#define QPNP_VADC_M0_HIGH_THR_LSB 0x5e
81#define QPNP_VADC_M0_HIGH_THR_MSB 0x5f
82#define QPNP_VADC_M1_LOW_THR_LSB 0x69
83#define QPNP_VADC_M1_LOW_THR_MSB 0x6a
84#define QPNP_VADC_M1_HIGH_THR_LSB 0x6b
85#define QPNP_VADC_M1_HIGH_THR_MSB 0x6c
86
87#define QPNP_VADC_DATA0 0x60
88#define QPNP_VADC_DATA1 0x61
89#define QPNP_VADC_CONV_TIMEOUT_ERR 2
90#define QPNP_VADC_CONV_TIME_MIN 2000
91#define QPNP_VADC_CONV_TIME_MAX 2100
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -070092#define QPNP_ADC_COMPLETION_TIMEOUT HZ
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -070093#define QPNP_VADC_ERR_COUNT 5
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070094
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070095struct qpnp_vadc_drv {
96 struct qpnp_adc_drv *adc;
97 struct dentry *dent;
98 struct device *vadc_hwmon;
99 bool vadc_init_calib;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700100 bool vadc_initialized;
101 int max_channels_available;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800102 bool vadc_iadc_sync_lock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700103 struct sensor_device_attribute sens_attr[0];
104};
105
106struct qpnp_vadc_drv *qpnp_vadc;
107
108static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
109 [SCALE_DEFAULT] = {qpnp_adc_scale_default},
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700110 [SCALE_BATT_THERM] = {qpnp_adc_scale_batt_therm},
111 [SCALE_PMIC_THERM] = {qpnp_adc_scale_pmic_therm},
112 [SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700113 [SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
114 [SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700115};
116
117static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
118{
119 struct qpnp_vadc_drv *vadc = qpnp_vadc;
120 int rc;
121
122 rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700123 (vadc->adc->offset + reg), data, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700124 if (rc < 0) {
125 pr_err("qpnp adc read reg %d failed with %d\n", reg, rc);
126 return rc;
127 }
128
129 return 0;
130}
131
132static int32_t qpnp_vadc_write_reg(int16_t reg, u8 data)
133{
134 struct qpnp_vadc_drv *vadc = qpnp_vadc;
135 int rc;
136 u8 *buf;
137
138 buf = &data;
139
140 rc = spmi_ext_register_writel(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700141 (vadc->adc->offset + reg), buf, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700142 if (rc < 0) {
143 pr_err("qpnp adc write reg %d failed with %d\n", reg, rc);
144 return rc;
145 }
146
147 return 0;
148}
149
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700150static int32_t qpnp_vadc_enable(bool state)
151{
152 int rc = 0;
153 u8 data = 0;
154
155 data = QPNP_VADC_ADC_EN;
156 if (state) {
157 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
158 data);
159 if (rc < 0) {
160 pr_err("VADC enable failed\n");
161 return rc;
162 }
163 } else {
164 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
165 (~data & QPNP_VADC_ADC_EN));
166 if (rc < 0) {
167 pr_err("VADC disable failed\n");
168 return rc;
169 }
170 }
171
172 return 0;
173}
174
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800175static int32_t qpnp_vadc_status_debug(void)
176{
177 int rc = 0;
178 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0, status2 = 0;
179
180 rc = qpnp_vadc_read_reg(QPNP_VADC_MODE_CTL, &mode);
181 if (rc < 0) {
182 pr_err("mode ctl register read failed with %d\n", rc);
183 return rc;
184 }
185
186 rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_DIG_PARAM, &dig);
187 if (rc < 0) {
188 pr_err("digital param read failed with %d\n", rc);
189 return rc;
190 }
191
192 rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_CH_SEL_CTL, &chan);
193 if (rc < 0) {
194 pr_err("channel read failed with %d\n", rc);
195 return rc;
196 }
197
198 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
199 if (rc < 0) {
200 pr_err("status1 read failed with %d\n", rc);
201 return rc;
202 }
203
204 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
205 if (rc < 0) {
206 pr_err("status2 read failed with %d\n", rc);
207 return rc;
208 }
209
210 rc = qpnp_vadc_read_reg(QPNP_VADC_EN_CTL1, &en);
211 if (rc < 0) {
212 pr_err("en read failed with %d\n", rc);
213 return rc;
214 }
215
216 pr_err("EOC not set - status1/2:%x/%x, dig:%x, ch:%x, mode:%x, en:%x\n",
217 status1, status2, dig, chan, mode, en);
218
219 rc = qpnp_vadc_enable(false);
220 if (rc < 0) {
221 pr_err("VADC disable failed with %d\n", rc);
222 return rc;
223 }
224
225 return 0;
226}
Siddartha Mohanadoss8dbb5c22012-12-11 14:50:45 -0800227static int32_t qpnp_vadc_configure(
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700228 struct qpnp_adc_amux_properties *chan_prop)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700229{
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700230 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700231 u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700232 u8 mode_ctrl = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700233 int rc = 0;
234
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700235 /* Mode selection */
Siddartha Mohanadoss429b4492012-12-11 13:29:58 -0800236 mode_ctrl |= ((chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT) |
237 (QPNP_VADC_ADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700238 rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
239 if (rc < 0) {
240 pr_err("Mode configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700241 return rc;
242 }
243
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700244
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700245 /* Channel selection */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700246 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
247 chan_prop->amux_channel);
248 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700249 pr_err("Channel configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700250 return rc;
251 }
252
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700253 /* Digital parameter setup */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700254 decimation = chan_prop->decimation <<
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700255 QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
256 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
257 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700258 pr_err("Digital parameter configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700259 return rc;
260 }
261
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700262 /* HW settling time delay */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700263 rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
264 chan_prop->hw_settle_time);
265 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700266 pr_err("HW settling time setup error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700267 return rc;
268 }
269
270 if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
271 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700272 /* Normal measurement mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700273 rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
274 chan_prop->fast_avg_setup);
275 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700276 pr_err("Fast averaging configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700277 return rc;
278 }
279 } else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
280 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700281 /* Conversion sequence mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700282 conv_sequence = ((ADC_SEQ_HOLD_100US <<
283 QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
284 ADC_CONV_SEQ_TIMEOUT_5MS);
285 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
286 conv_sequence);
287 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700288 pr_err("Conversion sequence error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700289 return rc;
290 }
291
292 conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
293 QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
294 chan_prop->trigger_channel);
295 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
296 conv_sequence_trig);
297 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700298 pr_err("Conversion trigger error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700299 return rc;
300 }
301 }
302
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700303 INIT_COMPLETION(vadc->adc->adc_rslt_completion);
304
305 rc = qpnp_vadc_enable(true);
306 if (rc)
307 return rc;
308
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800309 if (!vadc->vadc_iadc_sync_lock) {
310 /* Request conversion */
311 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ,
312 QPNP_VADC_CONV_REQ_SET);
313 if (rc < 0) {
314 pr_err("Request conversion failed\n");
315 return rc;
316 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700317 }
318
319 return 0;
320}
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700321
322static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
323{
324 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700325 int rc = 0, status = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700326
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700327 status = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
328 if (status < 0) {
329 pr_err("qpnp adc result read failed for data0\n");
330 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700331 }
332
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700333 status = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
334 if (status < 0) {
335 pr_err("qpnp adc result read failed for data1\n");
336 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700337 }
338
339 *data = (rslt_msb << 8) | rslt_lsb;
340
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700341 status = qpnp_vadc_check_result(data);
342 if (status < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700343 pr_err("VADC data check failed\n");
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700344 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700345 }
346
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700347fail:
348 rc = qpnp_vadc_enable(false);
349 if (rc)
350 return rc;
351
352 return status;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700353}
354
355static int32_t qpnp_vadc_read_status(int mode_sel)
356{
357 u8 status1, status2, status2_conv_seq_state;
358 u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
359 int rc;
360
361 switch (mode_sel) {
362 case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
363 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
364 if (rc) {
365 pr_err("qpnp_vadc read mask interrupt failed\n");
366 return rc;
367 }
368
369 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
370 if (rc) {
371 pr_err("qpnp_vadc read mask interrupt failed\n");
372 return rc;
373 }
374
375 if (!(status2 & ~QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS) &&
376 (status1 & (~QPNP_VADC_STATUS1_REQ_STS |
377 QPNP_VADC_STATUS1_EOC))) {
378 rc = status_err;
379 return rc;
380 }
381
382 status2_conv_seq_state = status2 >>
383 QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT;
384 if (status2_conv_seq_state != ADC_CONV_SEQ_IDLE) {
385 pr_err("qpnp vadc seq error with status %d\n",
386 status2);
387 rc = -EINVAL;
388 return rc;
389 }
390 }
391
392 return 0;
393}
394
395static void qpnp_vadc_work(struct work_struct *work)
396{
397 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700398
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800399 if (!vadc || !vadc->vadc_initialized)
400 return;
401
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700402 complete(&vadc->adc->adc_rslt_completion);
403
404 return;
405}
406DECLARE_WORK(trigger_completion_work, qpnp_vadc_work);
407
408static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
409{
410 schedule_work(&trigger_completion_work);
411
412 return IRQ_HANDLED;
413}
414
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700415static int32_t qpnp_vadc_version_check(void)
416{
417 uint8_t revision;
418 int rc;
419
420 rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
421 if (rc < 0) {
422 pr_err("qpnp adc result read failed with %d\n", rc);
423 return rc;
424 }
425
426 if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
427 pr_err("VADC Version not supported\n");
428 return -EINVAL;
429 }
430
431 return 0;
432}
433
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700434static uint32_t qpnp_vadc_calib_device(void)
435{
436 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700437 struct qpnp_adc_amux_properties conv;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700438 int rc, calib_read_1, calib_read_2, count = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700439 u8 status1 = 0;
440
441 conv.amux_channel = REF_125V;
442 conv.decimation = DECIMATION_TYPE2;
443 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
444 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
445 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
446
447 rc = qpnp_vadc_configure(&conv);
448 if (rc) {
449 pr_err("qpnp_vadc configure failed with %d\n", rc);
450 goto calib_fail;
451 }
452
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700453 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700454 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
455 if (rc < 0)
456 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700457 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700458 usleep_range(QPNP_VADC_CONV_TIME_MIN,
459 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700460 count++;
461 if (count > QPNP_VADC_ERR_COUNT) {
462 rc = -ENODEV;
463 goto calib_fail;
464 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700465 }
466
467 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
468 if (rc) {
469 pr_err("qpnp adc read adc failed with %d\n", rc);
470 goto calib_fail;
471 }
472
473 conv.amux_channel = REF_625MV;
474 conv.decimation = DECIMATION_TYPE2;
475 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
476 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
477 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
478 rc = qpnp_vadc_configure(&conv);
479 if (rc) {
480 pr_err("qpnp adc configure failed with %d\n", rc);
481 goto calib_fail;
482 }
483
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700484 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700485 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700486 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700487 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
488 if (rc < 0)
489 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700490 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700491 usleep_range(QPNP_VADC_CONV_TIME_MIN,
492 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700493 count++;
494 if (count > QPNP_VADC_ERR_COUNT) {
495 rc = -ENODEV;
496 goto calib_fail;
497 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700498 }
499
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700500 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700501 if (rc) {
502 pr_err("qpnp adc read adc failed with %d\n", rc);
503 goto calib_fail;
504 }
505
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700506 pr_debug("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
507 calib_read_1, calib_read_2);
508
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700509 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
510 (calib_read_1 - calib_read_2);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700511
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700512 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
513 = QPNP_ADC_625_UV;
514 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
515 calib_read_1;
516 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
517 calib_read_2;
518 /* Ratiometric Calibration */
519 conv.amux_channel = VDD_VADC;
520 conv.decimation = DECIMATION_TYPE2;
521 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
522 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
523 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
524 rc = qpnp_vadc_configure(&conv);
525 if (rc) {
526 pr_err("qpnp adc configure failed with %d\n", rc);
527 goto calib_fail;
528 }
529
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700530 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700531 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700532 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700533 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
534 if (rc < 0)
535 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700536 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700537 usleep_range(QPNP_VADC_CONV_TIME_MIN,
538 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700539 count++;
540 if (count > QPNP_VADC_ERR_COUNT) {
541 rc = -ENODEV;
542 goto calib_fail;
543 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700544 }
545
546 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
547 if (rc) {
548 pr_err("qpnp adc read adc failed with %d\n", rc);
549 goto calib_fail;
550 }
551
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700552 conv.amux_channel = GND_REF;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700553 conv.decimation = DECIMATION_TYPE2;
554 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
555 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
556 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
557 rc = qpnp_vadc_configure(&conv);
558 if (rc) {
559 pr_err("qpnp adc configure failed with %d\n", rc);
560 goto calib_fail;
561 }
562
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700563 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700564 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700565 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700566 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
567 if (rc < 0)
568 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700569 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700570 usleep_range(QPNP_VADC_CONV_TIME_MIN,
571 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700572 count++;
573 if (count > QPNP_VADC_ERR_COUNT) {
574 rc = -ENODEV;
575 goto calib_fail;
576 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700577 }
578
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700579 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700580 if (rc) {
581 pr_err("qpnp adc read adc failed with %d\n", rc);
582 goto calib_fail;
583 }
584
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700585 pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
586 calib_read_1, calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700587 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
588 (calib_read_1 - calib_read_2);
589 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
590 vadc->adc->adc_prop->adc_vdd_reference;
591 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
592 calib_read_1;
593 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
594 calib_read_2;
595
596calib_fail:
597 return rc;
598}
599
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800600int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
601 enum qpnp_adc_calib_type calib_type)
602{
603
604 struct qpnp_vadc_drv *vadc = qpnp_vadc;
605
606 switch (calib_type) {
607 case CALIB_RATIOMETRIC:
608 param->dy =
609 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
610 param->dx =
611 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
612 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
613 param->adc_gnd =
614 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
615 break;
616 case CALIB_ABSOLUTE:
617 param->dy =
618 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
619 param->dx =
620 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
621 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
622 param->adc_gnd =
623 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
624 break;
625 default:
626 return -EINVAL;
627 }
628
629 return 0;
630}
631EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
632
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700633int32_t qpnp_vadc_is_ready(void)
634{
635 struct qpnp_vadc_drv *vadc = qpnp_vadc;
636
637 if (!vadc || !vadc->vadc_initialized)
638 return -EPROBE_DEFER;
639 else
640 return 0;
641}
642EXPORT_SYMBOL(qpnp_vadc_is_ready);
643
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700644int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
645 enum qpnp_vadc_channels channel,
646 struct qpnp_vadc_result *result)
647{
648 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700649 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
650
651 if (!vadc || !vadc->vadc_initialized)
652 return -EPROBE_DEFER;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700653
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800654 mutex_lock(&vadc->adc->adc_lock);
655
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700656 if (!vadc->vadc_init_calib) {
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700657 rc = qpnp_vadc_version_check();
658 if (rc)
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800659 goto fail_unlock;
660
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700661 rc = qpnp_vadc_calib_device();
662 if (rc) {
663 pr_err("Calibration failed\n");
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800664 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700665 } else
666 vadc->vadc_init_calib = true;
667 }
668
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700669 vadc->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700670
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800671 while ((vadc->adc->adc_channels[dt_index].channel_num
672 != channel) && (dt_index < vadc->max_channels_available))
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700673 dt_index++;
674
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800675 if (dt_index >= vadc->max_channels_available) {
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700676 pr_err("not a valid VADC channel\n");
677 rc = -EINVAL;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700678 goto fail_unlock;
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700679 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700680
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700681 vadc->adc->amux_prop->decimation =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700682 vadc->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700683 vadc->adc->amux_prop->hw_settle_time =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700684 vadc->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700685 vadc->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700686 vadc->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700687
688 if (trigger_channel < ADC_SEQ_NONE)
689 vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
690 << QPNP_VADC_OP_MODE_SHIFT);
691 else if (trigger_channel == ADC_SEQ_NONE)
692 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
693 << QPNP_VADC_OP_MODE_SHIFT);
694 else {
695 pr_err("Invalid trigger channel:%d\n", trigger_channel);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700696 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700697 }
698
699 vadc->adc->amux_prop->trigger_channel = trigger_channel;
700
701 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
702 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700703 pr_err("qpnp vadc configure failed with %d\n", rc);
704 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700705 }
706
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700707 rc = wait_for_completion_timeout(&vadc->adc->adc_rslt_completion,
708 QPNP_ADC_COMPLETION_TIMEOUT);
709 if (!rc) {
710 u8 status1 = 0;
711 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
712 if (rc < 0)
713 goto fail_unlock;
714 status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
715 if (status1 == QPNP_VADC_STATUS1_EOC)
716 pr_debug("End of conversion status set\n");
717 else {
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800718 rc = qpnp_vadc_status_debug();
719 if (rc < 0)
720 pr_err("VADC disable failed\n");
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700721 rc = -EINVAL;
722 goto fail_unlock;
723 }
724 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700725
726 if (trigger_channel < ADC_SEQ_NONE) {
727 rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
728 if (rc)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700729 pr_debug("Conversion sequence timed out - %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700730 }
731
732 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
733 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700734 pr_err("qpnp vadc read adc code failed with %d\n", rc);
735 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700736 }
737
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700738 amux_prescaling =
739 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700740
741 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
742 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
743 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
744 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
745
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700746 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700747 if (scale_type >= SCALE_NONE) {
748 rc = -EBADF;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700749 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700750 }
751
752 vadc_scale_fn[scale_type].chan(result->adc_code,
753 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
754
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700755fail_unlock:
756 mutex_unlock(&vadc->adc->adc_lock);
757
758 return rc;
759}
760EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
761
762int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
763 struct qpnp_vadc_result *result)
764{
765 return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
766 channel, result);
767}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700768EXPORT_SYMBOL(qpnp_vadc_read);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700769
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800770static void qpnp_vadc_lock(void)
771{
772 struct qpnp_vadc_drv *vadc = qpnp_vadc;
773
774 mutex_lock(&vadc->adc->adc_lock);
775}
776
777static void qpnp_vadc_unlock(void)
778{
779 struct qpnp_vadc_drv *vadc = qpnp_vadc;
780
781 mutex_unlock(&vadc->adc->adc_lock);
782}
783
784int32_t qpnp_vadc_iadc_sync_request(enum qpnp_vadc_channels channel)
785{
786 struct qpnp_vadc_drv *vadc = qpnp_vadc;
787 int rc = 0, dt_index = 0;
788
789 if (!vadc || !vadc->vadc_initialized)
790 return -EPROBE_DEFER;
791
792 qpnp_vadc_lock();
793
794 if (!vadc->vadc_init_calib) {
795 rc = qpnp_vadc_version_check();
796 if (rc)
797 goto fail;
798
799 rc = qpnp_vadc_calib_device();
800 if (rc) {
801 pr_err("Calibration failed\n");
802 goto fail;
803 } else
804 vadc->vadc_init_calib = true;
805 }
806
807 vadc->adc->amux_prop->amux_channel = channel;
808
809 while ((vadc->adc->adc_channels[dt_index].channel_num
810 != channel) && (dt_index < vadc->max_channels_available))
811 dt_index++;
812
813 if (dt_index >= vadc->max_channels_available) {
814 pr_err("not a valid VADC channel\n");
815 rc = -EINVAL;
816 goto fail;
817 }
818
819 vadc->adc->amux_prop->decimation =
820 vadc->adc->adc_channels[dt_index].adc_decimation;
821 vadc->adc->amux_prop->hw_settle_time =
822 vadc->adc->adc_channels[dt_index].hw_settle_time;
823 vadc->adc->amux_prop->fast_avg_setup =
824 vadc->adc->adc_channels[dt_index].fast_avg_setup;
825 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
826 << QPNP_VADC_OP_MODE_SHIFT);
827 vadc->vadc_iadc_sync_lock = true;
828
829 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
830 if (rc) {
831 pr_err("qpnp vadc configure failed with %d\n", rc);
832 goto fail;
833 }
834
835 return rc;
836fail:
837 vadc->vadc_iadc_sync_lock = false;
838 qpnp_vadc_unlock();
839 return rc;
840}
841EXPORT_SYMBOL(qpnp_vadc_iadc_sync_request);
842
843int32_t qpnp_vadc_iadc_sync_complete_request(enum qpnp_vadc_channels channel,
844 struct qpnp_vadc_result *result)
845{
846 struct qpnp_vadc_drv *vadc = qpnp_vadc;
847 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
848
849 vadc->adc->amux_prop->amux_channel = channel;
850
851 while ((vadc->adc->adc_channels[dt_index].channel_num
852 != channel) && (dt_index < vadc->max_channels_available))
853 dt_index++;
854
855 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
856 if (rc) {
857 pr_err("qpnp vadc read adc code failed with %d\n", rc);
858 goto fail;
859 }
860
861 amux_prescaling =
862 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
863
864 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
865 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
866 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
867 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
868
869 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
870 if (scale_type >= SCALE_NONE) {
871 rc = -EBADF;
872 goto fail;
873 }
874
875 vadc_scale_fn[scale_type].chan(result->adc_code,
876 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
877
878fail:
879 vadc->vadc_iadc_sync_lock = false;
880 qpnp_vadc_unlock();
881 return rc;
882}
883EXPORT_SYMBOL(qpnp_vadc_iadc_sync_complete_request);
884
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700885static ssize_t qpnp_adc_show(struct device *dev,
886 struct device_attribute *devattr, char *buf)
887{
888 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
889 struct qpnp_vadc_result result;
890 int rc = -1;
891
892 rc = qpnp_vadc_read(attr->index, &result);
893
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700894 if (rc) {
895 pr_err("VADC read error with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700896 return 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700897 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700898
899 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
900 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
901}
902
903static struct sensor_device_attribute qpnp_adc_attr =
904 SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
905
906static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
907{
908 struct qpnp_vadc_drv *vadc = qpnp_vadc;
909 struct device_node *child;
910 struct device_node *node = spmi->dev.of_node;
911 int rc = 0, i = 0, channel;
912
913 for_each_child_of_node(node, child) {
914 channel = vadc->adc->adc_channels[i].channel_num;
915 qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
916 qpnp_adc_attr.dev_attr.attr.name =
917 vadc->adc->adc_channels[i].name;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700918 memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
919 sizeof(qpnp_adc_attr));
Stephen Boydd7337962012-10-30 11:10:46 -0700920 sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700921 rc = device_create_file(&spmi->dev,
922 &vadc->sens_attr[i].dev_attr);
923 if (rc) {
924 dev_err(&spmi->dev,
925 "device_create_file failed for dev %s\n",
926 vadc->adc->adc_channels[i].name);
927 goto hwmon_err_sens;
928 }
929 i++;
930 }
931
932 return 0;
933hwmon_err_sens:
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700934 pr_err("Init HWMON failed for qpnp_adc with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700935 return rc;
936}
937
938static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
939{
940 struct qpnp_vadc_drv *vadc;
941 struct qpnp_adc_drv *adc_qpnp;
942 struct device_node *node = spmi->dev.of_node;
943 struct device_node *child;
944 int rc, count_adc_channel_list = 0;
945
946 if (!node)
947 return -EINVAL;
948
949 if (qpnp_vadc) {
950 pr_err("VADC already in use\n");
951 return -EBUSY;
952 }
953
954 for_each_child_of_node(node, child)
955 count_adc_channel_list++;
956
957 if (!count_adc_channel_list) {
958 pr_err("No channel listing\n");
959 return -EINVAL;
960 }
961
962 vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
963 (sizeof(struct sensor_device_attribute) *
964 count_adc_channel_list), GFP_KERNEL);
965 if (!vadc) {
966 dev_err(&spmi->dev, "Unable to allocate memory\n");
967 return -ENOMEM;
968 }
969
970 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
971 GFP_KERNEL);
972 if (!adc_qpnp) {
973 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800974 rc = -ENOMEM;
975 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700976 }
977
978 vadc->adc = adc_qpnp;
979
980 rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
981 if (rc) {
982 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800983 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700984 }
985
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800986 rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700987 qpnp_vadc_isr, IRQF_TRIGGER_RISING,
988 "qpnp_vadc_interrupt", vadc);
989 if (rc) {
990 dev_err(&spmi->dev,
991 "failed to request adc irq with error %d\n", rc);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800992 goto fail;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700993 } else {
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800994 enable_irq_wake(vadc->adc->adc_irq_eoc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700995 }
996
997 qpnp_vadc = vadc;
998 dev_set_drvdata(&spmi->dev, vadc);
999 rc = qpnp_vadc_init_hwmon(spmi);
1000 if (rc) {
1001 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001002 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001003 }
1004 vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
1005 vadc->vadc_init_calib = false;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001006 vadc->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -07001007 vadc->vadc_initialized = true;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001008 vadc->vadc_iadc_sync_lock = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001009
1010 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001011fail:
1012 qpnp_vadc = NULL;
1013 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001014}
1015
1016static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
1017{
1018 struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
1019 struct device_node *node = spmi->dev.of_node;
1020 struct device_node *child;
1021 int i = 0;
1022
1023 for_each_child_of_node(node, child) {
1024 device_remove_file(&spmi->dev,
1025 &vadc->sens_attr[i].dev_attr);
1026 i++;
1027 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001028 vadc->vadc_initialized = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001029 dev_set_drvdata(&spmi->dev, NULL);
1030
1031 return 0;
1032}
1033
1034static const struct of_device_id qpnp_vadc_match_table[] = {
1035 { .compatible = "qcom,qpnp-vadc",
1036 },
1037 {}
1038};
1039
1040static struct spmi_driver qpnp_vadc_driver = {
1041 .driver = {
1042 .name = "qcom,qpnp-vadc",
1043 .of_match_table = qpnp_vadc_match_table,
1044 },
1045 .probe = qpnp_vadc_probe,
1046 .remove = qpnp_vadc_remove,
1047};
1048
1049static int __init qpnp_vadc_init(void)
1050{
1051 return spmi_driver_register(&qpnp_vadc_driver);
1052}
1053module_init(qpnp_vadc_init);
1054
1055static void __exit qpnp_vadc_exit(void)
1056{
1057 spmi_driver_unregister(&qpnp_vadc_driver);
1058}
1059module_exit(qpnp_vadc_exit);
1060
1061MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
1062MODULE_LICENSE("GPL v2");