blob: edb1d66ed26a07dae0d9e12e1e73b5e5c93a39a3 [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 Mohanadossb99cfa92013-05-01 20:19:58 -0700115 [SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700116};
117
118static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
119{
120 struct qpnp_vadc_drv *vadc = qpnp_vadc;
121 int rc;
122
123 rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700124 (vadc->adc->offset + reg), data, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700125 if (rc < 0) {
126 pr_err("qpnp adc read reg %d failed with %d\n", reg, rc);
127 return rc;
128 }
129
130 return 0;
131}
132
133static int32_t qpnp_vadc_write_reg(int16_t reg, u8 data)
134{
135 struct qpnp_vadc_drv *vadc = qpnp_vadc;
136 int rc;
137 u8 *buf;
138
139 buf = &data;
140
141 rc = spmi_ext_register_writel(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700142 (vadc->adc->offset + reg), buf, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700143 if (rc < 0) {
144 pr_err("qpnp adc write reg %d failed with %d\n", reg, rc);
145 return rc;
146 }
147
148 return 0;
149}
150
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700151static int32_t qpnp_vadc_enable(bool state)
152{
153 int rc = 0;
154 u8 data = 0;
155
156 data = QPNP_VADC_ADC_EN;
157 if (state) {
158 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
159 data);
160 if (rc < 0) {
161 pr_err("VADC enable failed\n");
162 return rc;
163 }
164 } else {
165 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
166 (~data & QPNP_VADC_ADC_EN));
167 if (rc < 0) {
168 pr_err("VADC disable failed\n");
169 return rc;
170 }
171 }
172
173 return 0;
174}
175
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800176static int32_t qpnp_vadc_status_debug(void)
177{
178 int rc = 0;
179 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0, status2 = 0;
180
181 rc = qpnp_vadc_read_reg(QPNP_VADC_MODE_CTL, &mode);
182 if (rc < 0) {
183 pr_err("mode ctl register read failed with %d\n", rc);
184 return rc;
185 }
186
187 rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_DIG_PARAM, &dig);
188 if (rc < 0) {
189 pr_err("digital param read failed with %d\n", rc);
190 return rc;
191 }
192
193 rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_CH_SEL_CTL, &chan);
194 if (rc < 0) {
195 pr_err("channel read failed with %d\n", rc);
196 return rc;
197 }
198
199 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
200 if (rc < 0) {
201 pr_err("status1 read failed with %d\n", rc);
202 return rc;
203 }
204
205 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
206 if (rc < 0) {
207 pr_err("status2 read failed with %d\n", rc);
208 return rc;
209 }
210
211 rc = qpnp_vadc_read_reg(QPNP_VADC_EN_CTL1, &en);
212 if (rc < 0) {
213 pr_err("en read failed with %d\n", rc);
214 return rc;
215 }
216
217 pr_err("EOC not set - status1/2:%x/%x, dig:%x, ch:%x, mode:%x, en:%x\n",
218 status1, status2, dig, chan, mode, en);
219
220 rc = qpnp_vadc_enable(false);
221 if (rc < 0) {
222 pr_err("VADC disable failed with %d\n", rc);
223 return rc;
224 }
225
226 return 0;
227}
Siddartha Mohanadoss8dbb5c22012-12-11 14:50:45 -0800228static int32_t qpnp_vadc_configure(
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700229 struct qpnp_adc_amux_properties *chan_prop)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700230{
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700231 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700232 u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700233 u8 mode_ctrl = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700234 int rc = 0;
235
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700236 /* Mode selection */
Siddartha Mohanadoss429b4492012-12-11 13:29:58 -0800237 mode_ctrl |= ((chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT) |
238 (QPNP_VADC_ADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700239 rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
240 if (rc < 0) {
241 pr_err("Mode configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700242 return rc;
243 }
244
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700245
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700246 /* Channel selection */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700247 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
248 chan_prop->amux_channel);
249 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700250 pr_err("Channel configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700251 return rc;
252 }
253
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700254 /* Digital parameter setup */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700255 decimation = chan_prop->decimation <<
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700256 QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
257 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
258 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700259 pr_err("Digital parameter configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700260 return rc;
261 }
262
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700263 /* HW settling time delay */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700264 rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
265 chan_prop->hw_settle_time);
266 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700267 pr_err("HW settling time setup error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700268 return rc;
269 }
270
271 if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
272 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700273 /* Normal measurement mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700274 rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
275 chan_prop->fast_avg_setup);
276 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700277 pr_err("Fast averaging configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700278 return rc;
279 }
280 } else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
281 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700282 /* Conversion sequence mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700283 conv_sequence = ((ADC_SEQ_HOLD_100US <<
284 QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
285 ADC_CONV_SEQ_TIMEOUT_5MS);
286 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
287 conv_sequence);
288 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700289 pr_err("Conversion sequence error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700290 return rc;
291 }
292
293 conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
294 QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
295 chan_prop->trigger_channel);
296 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
297 conv_sequence_trig);
298 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700299 pr_err("Conversion trigger error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700300 return rc;
301 }
302 }
303
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700304 INIT_COMPLETION(vadc->adc->adc_rslt_completion);
305
306 rc = qpnp_vadc_enable(true);
307 if (rc)
308 return rc;
309
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800310 if (!vadc->vadc_iadc_sync_lock) {
311 /* Request conversion */
312 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ,
313 QPNP_VADC_CONV_REQ_SET);
314 if (rc < 0) {
315 pr_err("Request conversion failed\n");
316 return rc;
317 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700318 }
319
320 return 0;
321}
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700322
323static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
324{
325 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700326 int rc = 0, status = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700327
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700328 status = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
329 if (status < 0) {
330 pr_err("qpnp adc result read failed for data0\n");
331 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700332 }
333
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700334 status = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
335 if (status < 0) {
336 pr_err("qpnp adc result read failed for data1\n");
337 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700338 }
339
340 *data = (rslt_msb << 8) | rslt_lsb;
341
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700342 status = qpnp_vadc_check_result(data);
343 if (status < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700344 pr_err("VADC data check failed\n");
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700345 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700346 }
347
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700348fail:
349 rc = qpnp_vadc_enable(false);
350 if (rc)
351 return rc;
352
353 return status;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700354}
355
356static int32_t qpnp_vadc_read_status(int mode_sel)
357{
358 u8 status1, status2, status2_conv_seq_state;
359 u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
360 int rc;
361
362 switch (mode_sel) {
363 case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
364 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
365 if (rc) {
366 pr_err("qpnp_vadc read mask interrupt failed\n");
367 return rc;
368 }
369
370 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
371 if (rc) {
372 pr_err("qpnp_vadc read mask interrupt failed\n");
373 return rc;
374 }
375
376 if (!(status2 & ~QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS) &&
377 (status1 & (~QPNP_VADC_STATUS1_REQ_STS |
378 QPNP_VADC_STATUS1_EOC))) {
379 rc = status_err;
380 return rc;
381 }
382
383 status2_conv_seq_state = status2 >>
384 QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT;
385 if (status2_conv_seq_state != ADC_CONV_SEQ_IDLE) {
386 pr_err("qpnp vadc seq error with status %d\n",
387 status2);
388 rc = -EINVAL;
389 return rc;
390 }
391 }
392
393 return 0;
394}
395
396static void qpnp_vadc_work(struct work_struct *work)
397{
398 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700399
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800400 if (!vadc || !vadc->vadc_initialized)
401 return;
402
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700403 complete(&vadc->adc->adc_rslt_completion);
404
405 return;
406}
407DECLARE_WORK(trigger_completion_work, qpnp_vadc_work);
408
409static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
410{
411 schedule_work(&trigger_completion_work);
412
413 return IRQ_HANDLED;
414}
415
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700416static int32_t qpnp_vadc_version_check(void)
417{
418 uint8_t revision;
419 int rc;
420
421 rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
422 if (rc < 0) {
423 pr_err("qpnp adc result read failed with %d\n", rc);
424 return rc;
425 }
426
427 if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
428 pr_err("VADC Version not supported\n");
429 return -EINVAL;
430 }
431
432 return 0;
433}
434
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700435static void qpnp_vadc_625mv_channel_sel(uint32_t *ref_channel_sel)
436{
437 struct qpnp_vadc_drv *vadc = qpnp_vadc;
438 uint32_t dt_index = 0;
439
440 /* Check if the buffered 625mV channel exists */
441 while ((vadc->adc->adc_channels[dt_index].channel_num
442 != SPARE1) && (dt_index < vadc->max_channels_available))
443 dt_index++;
444
445 if (dt_index >= vadc->max_channels_available) {
446 pr_debug("Use default 625mV ref channel\n");
447 *ref_channel_sel = REF_625MV;
448 } else {
449 pr_debug("Use buffered 625mV ref channel\n");
450 *ref_channel_sel = SPARE1;
451 }
452}
453
454static int32_t qpnp_vadc_calib_device(void)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700455{
456 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700457 struct qpnp_adc_amux_properties conv;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700458 int rc, calib_read_1, calib_read_2, count = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700459 u8 status1 = 0;
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700460 uint32_t ref_channel_sel = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700461
462 conv.amux_channel = REF_125V;
463 conv.decimation = DECIMATION_TYPE2;
464 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
465 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
466 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
467
468 rc = qpnp_vadc_configure(&conv);
469 if (rc) {
470 pr_err("qpnp_vadc configure failed with %d\n", rc);
471 goto calib_fail;
472 }
473
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700474 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700475 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
476 if (rc < 0)
477 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700478 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700479 usleep_range(QPNP_VADC_CONV_TIME_MIN,
480 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700481 count++;
482 if (count > QPNP_VADC_ERR_COUNT) {
483 rc = -ENODEV;
484 goto calib_fail;
485 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700486 }
487
488 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
489 if (rc) {
490 pr_err("qpnp adc read adc failed with %d\n", rc);
491 goto calib_fail;
492 }
493
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700494 qpnp_vadc_625mv_channel_sel(&ref_channel_sel);
495 conv.amux_channel = ref_channel_sel;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700496 conv.decimation = DECIMATION_TYPE2;
497 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
498 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
499 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
500 rc = qpnp_vadc_configure(&conv);
501 if (rc) {
502 pr_err("qpnp adc configure failed with %d\n", rc);
503 goto calib_fail;
504 }
505
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700506 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700507 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700508 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700509 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
510 if (rc < 0)
511 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700512 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700513 usleep_range(QPNP_VADC_CONV_TIME_MIN,
514 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700515 count++;
516 if (count > QPNP_VADC_ERR_COUNT) {
517 rc = -ENODEV;
518 goto calib_fail;
519 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700520 }
521
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700522 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700523 if (rc) {
524 pr_err("qpnp adc read adc failed with %d\n", rc);
525 goto calib_fail;
526 }
527
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700528 pr_debug("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
529 calib_read_1, calib_read_2);
530
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700531 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
532 (calib_read_1 - calib_read_2);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700533
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700534 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
535 = QPNP_ADC_625_UV;
536 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
537 calib_read_1;
538 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
539 calib_read_2;
540 /* Ratiometric Calibration */
541 conv.amux_channel = VDD_VADC;
542 conv.decimation = DECIMATION_TYPE2;
543 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
544 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
545 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
546 rc = qpnp_vadc_configure(&conv);
547 if (rc) {
548 pr_err("qpnp adc configure failed with %d\n", rc);
549 goto calib_fail;
550 }
551
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700552 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700553 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700554 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700555 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
556 if (rc < 0)
557 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700558 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700559 usleep_range(QPNP_VADC_CONV_TIME_MIN,
560 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700561 count++;
562 if (count > QPNP_VADC_ERR_COUNT) {
563 rc = -ENODEV;
564 goto calib_fail;
565 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700566 }
567
568 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
569 if (rc) {
570 pr_err("qpnp adc read adc failed with %d\n", rc);
571 goto calib_fail;
572 }
573
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700574 conv.amux_channel = GND_REF;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700575 conv.decimation = DECIMATION_TYPE2;
576 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
577 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
578 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
579 rc = qpnp_vadc_configure(&conv);
580 if (rc) {
581 pr_err("qpnp adc configure failed with %d\n", rc);
582 goto calib_fail;
583 }
584
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700585 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700586 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700587 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700588 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
589 if (rc < 0)
590 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700591 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700592 usleep_range(QPNP_VADC_CONV_TIME_MIN,
593 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700594 count++;
595 if (count > QPNP_VADC_ERR_COUNT) {
596 rc = -ENODEV;
597 goto calib_fail;
598 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700599 }
600
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700601 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700602 if (rc) {
603 pr_err("qpnp adc read adc failed with %d\n", rc);
604 goto calib_fail;
605 }
606
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700607 pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
608 calib_read_1, calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700609 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
610 (calib_read_1 - calib_read_2);
611 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
612 vadc->adc->adc_prop->adc_vdd_reference;
613 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
614 calib_read_1;
615 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
616 calib_read_2;
617
618calib_fail:
619 return rc;
620}
621
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800622int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
623 enum qpnp_adc_calib_type calib_type)
624{
625
626 struct qpnp_vadc_drv *vadc = qpnp_vadc;
627
628 switch (calib_type) {
629 case CALIB_RATIOMETRIC:
630 param->dy =
631 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
632 param->dx =
633 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
634 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
635 param->adc_gnd =
636 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
637 break;
638 case CALIB_ABSOLUTE:
639 param->dy =
640 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
641 param->dx =
642 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
643 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
644 param->adc_gnd =
645 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
646 break;
647 default:
648 return -EINVAL;
649 }
650
651 return 0;
652}
653EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
654
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700655int32_t qpnp_vadc_is_ready(void)
656{
657 struct qpnp_vadc_drv *vadc = qpnp_vadc;
658
659 if (!vadc || !vadc->vadc_initialized)
660 return -EPROBE_DEFER;
661 else
662 return 0;
663}
664EXPORT_SYMBOL(qpnp_vadc_is_ready);
665
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700666int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
667 enum qpnp_vadc_channels channel,
668 struct qpnp_vadc_result *result)
669{
670 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700671 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700672 uint32_t ref_channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700673
674 if (!vadc || !vadc->vadc_initialized)
675 return -EPROBE_DEFER;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700676
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800677 mutex_lock(&vadc->adc->adc_lock);
678
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700679 if (!vadc->vadc_init_calib) {
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700680 rc = qpnp_vadc_version_check();
681 if (rc)
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800682 goto fail_unlock;
683
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700684 rc = qpnp_vadc_calib_device();
685 if (rc) {
686 pr_err("Calibration failed\n");
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800687 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700688 } else
689 vadc->vadc_init_calib = true;
690 }
691
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700692 if (channel == REF_625MV) {
693 qpnp_vadc_625mv_channel_sel(&ref_channel);
694 channel = ref_channel;
695 }
696
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700697 vadc->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700698
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800699 while ((vadc->adc->adc_channels[dt_index].channel_num
700 != channel) && (dt_index < vadc->max_channels_available))
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700701 dt_index++;
702
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800703 if (dt_index >= vadc->max_channels_available) {
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700704 pr_err("not a valid VADC channel\n");
705 rc = -EINVAL;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700706 goto fail_unlock;
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700707 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700708
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700709 vadc->adc->amux_prop->decimation =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700710 vadc->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700711 vadc->adc->amux_prop->hw_settle_time =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700712 vadc->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700713 vadc->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700714 vadc->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700715
716 if (trigger_channel < ADC_SEQ_NONE)
717 vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
718 << QPNP_VADC_OP_MODE_SHIFT);
719 else if (trigger_channel == ADC_SEQ_NONE)
720 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
721 << QPNP_VADC_OP_MODE_SHIFT);
722 else {
723 pr_err("Invalid trigger channel:%d\n", trigger_channel);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700724 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700725 }
726
727 vadc->adc->amux_prop->trigger_channel = trigger_channel;
728
729 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
730 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700731 pr_err("qpnp vadc configure failed with %d\n", rc);
732 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700733 }
734
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700735 rc = wait_for_completion_timeout(&vadc->adc->adc_rslt_completion,
736 QPNP_ADC_COMPLETION_TIMEOUT);
737 if (!rc) {
738 u8 status1 = 0;
739 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
740 if (rc < 0)
741 goto fail_unlock;
742 status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
743 if (status1 == QPNP_VADC_STATUS1_EOC)
744 pr_debug("End of conversion status set\n");
745 else {
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800746 rc = qpnp_vadc_status_debug();
747 if (rc < 0)
748 pr_err("VADC disable failed\n");
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700749 rc = -EINVAL;
750 goto fail_unlock;
751 }
752 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700753
754 if (trigger_channel < ADC_SEQ_NONE) {
755 rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
756 if (rc)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700757 pr_debug("Conversion sequence timed out - %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700758 }
759
760 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
761 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700762 pr_err("qpnp vadc read adc code failed with %d\n", rc);
763 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700764 }
765
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700766 amux_prescaling =
767 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700768
769 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
770 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
771 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
772 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
773
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700774 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700775 if (scale_type >= SCALE_NONE) {
776 rc = -EBADF;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700777 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700778 }
779
780 vadc_scale_fn[scale_type].chan(result->adc_code,
781 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
782
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700783fail_unlock:
784 mutex_unlock(&vadc->adc->adc_lock);
785
786 return rc;
787}
788EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
789
790int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
791 struct qpnp_vadc_result *result)
792{
793 return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
794 channel, result);
795}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700796EXPORT_SYMBOL(qpnp_vadc_read);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700797
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800798static void qpnp_vadc_lock(void)
799{
800 struct qpnp_vadc_drv *vadc = qpnp_vadc;
801
802 mutex_lock(&vadc->adc->adc_lock);
803}
804
805static void qpnp_vadc_unlock(void)
806{
807 struct qpnp_vadc_drv *vadc = qpnp_vadc;
808
809 mutex_unlock(&vadc->adc->adc_lock);
810}
811
812int32_t qpnp_vadc_iadc_sync_request(enum qpnp_vadc_channels channel)
813{
814 struct qpnp_vadc_drv *vadc = qpnp_vadc;
815 int rc = 0, dt_index = 0;
816
817 if (!vadc || !vadc->vadc_initialized)
818 return -EPROBE_DEFER;
819
820 qpnp_vadc_lock();
821
822 if (!vadc->vadc_init_calib) {
823 rc = qpnp_vadc_version_check();
824 if (rc)
825 goto fail;
826
827 rc = qpnp_vadc_calib_device();
828 if (rc) {
829 pr_err("Calibration failed\n");
830 goto fail;
831 } else
832 vadc->vadc_init_calib = true;
833 }
834
835 vadc->adc->amux_prop->amux_channel = channel;
836
837 while ((vadc->adc->adc_channels[dt_index].channel_num
838 != channel) && (dt_index < vadc->max_channels_available))
839 dt_index++;
840
841 if (dt_index >= vadc->max_channels_available) {
842 pr_err("not a valid VADC channel\n");
843 rc = -EINVAL;
844 goto fail;
845 }
846
847 vadc->adc->amux_prop->decimation =
848 vadc->adc->adc_channels[dt_index].adc_decimation;
849 vadc->adc->amux_prop->hw_settle_time =
850 vadc->adc->adc_channels[dt_index].hw_settle_time;
851 vadc->adc->amux_prop->fast_avg_setup =
852 vadc->adc->adc_channels[dt_index].fast_avg_setup;
853 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
854 << QPNP_VADC_OP_MODE_SHIFT);
855 vadc->vadc_iadc_sync_lock = true;
856
857 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
858 if (rc) {
859 pr_err("qpnp vadc configure failed with %d\n", rc);
860 goto fail;
861 }
862
863 return rc;
864fail:
865 vadc->vadc_iadc_sync_lock = false;
866 qpnp_vadc_unlock();
867 return rc;
868}
869EXPORT_SYMBOL(qpnp_vadc_iadc_sync_request);
870
871int32_t qpnp_vadc_iadc_sync_complete_request(enum qpnp_vadc_channels channel,
872 struct qpnp_vadc_result *result)
873{
874 struct qpnp_vadc_drv *vadc = qpnp_vadc;
875 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
876
877 vadc->adc->amux_prop->amux_channel = channel;
878
879 while ((vadc->adc->adc_channels[dt_index].channel_num
880 != channel) && (dt_index < vadc->max_channels_available))
881 dt_index++;
882
883 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
884 if (rc) {
885 pr_err("qpnp vadc read adc code failed with %d\n", rc);
886 goto fail;
887 }
888
889 amux_prescaling =
890 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
891
892 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
893 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
894 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
895 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
896
897 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
898 if (scale_type >= SCALE_NONE) {
899 rc = -EBADF;
900 goto fail;
901 }
902
903 vadc_scale_fn[scale_type].chan(result->adc_code,
904 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
905
906fail:
907 vadc->vadc_iadc_sync_lock = false;
908 qpnp_vadc_unlock();
909 return rc;
910}
911EXPORT_SYMBOL(qpnp_vadc_iadc_sync_complete_request);
912
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700913static ssize_t qpnp_adc_show(struct device *dev,
914 struct device_attribute *devattr, char *buf)
915{
916 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
917 struct qpnp_vadc_result result;
918 int rc = -1;
919
920 rc = qpnp_vadc_read(attr->index, &result);
921
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700922 if (rc) {
923 pr_err("VADC read error with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700924 return 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700925 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700926
927 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
928 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
929}
930
931static struct sensor_device_attribute qpnp_adc_attr =
932 SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
933
934static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
935{
936 struct qpnp_vadc_drv *vadc = qpnp_vadc;
937 struct device_node *child;
938 struct device_node *node = spmi->dev.of_node;
939 int rc = 0, i = 0, channel;
940
941 for_each_child_of_node(node, child) {
942 channel = vadc->adc->adc_channels[i].channel_num;
943 qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
944 qpnp_adc_attr.dev_attr.attr.name =
945 vadc->adc->adc_channels[i].name;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700946 memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
947 sizeof(qpnp_adc_attr));
Stephen Boydd7337962012-10-30 11:10:46 -0700948 sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700949 rc = device_create_file(&spmi->dev,
950 &vadc->sens_attr[i].dev_attr);
951 if (rc) {
952 dev_err(&spmi->dev,
953 "device_create_file failed for dev %s\n",
954 vadc->adc->adc_channels[i].name);
955 goto hwmon_err_sens;
956 }
957 i++;
958 }
959
960 return 0;
961hwmon_err_sens:
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700962 pr_err("Init HWMON failed for qpnp_adc with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700963 return rc;
964}
965
966static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
967{
968 struct qpnp_vadc_drv *vadc;
969 struct qpnp_adc_drv *adc_qpnp;
970 struct device_node *node = spmi->dev.of_node;
971 struct device_node *child;
972 int rc, count_adc_channel_list = 0;
973
974 if (!node)
975 return -EINVAL;
976
977 if (qpnp_vadc) {
978 pr_err("VADC already in use\n");
979 return -EBUSY;
980 }
981
982 for_each_child_of_node(node, child)
983 count_adc_channel_list++;
984
985 if (!count_adc_channel_list) {
986 pr_err("No channel listing\n");
987 return -EINVAL;
988 }
989
990 vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
991 (sizeof(struct sensor_device_attribute) *
992 count_adc_channel_list), GFP_KERNEL);
993 if (!vadc) {
994 dev_err(&spmi->dev, "Unable to allocate memory\n");
995 return -ENOMEM;
996 }
997
998 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
999 GFP_KERNEL);
1000 if (!adc_qpnp) {
1001 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001002 rc = -ENOMEM;
1003 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001004 }
1005
1006 vadc->adc = adc_qpnp;
1007
1008 rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
1009 if (rc) {
1010 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001011 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001012 }
Stephen Boydbeab4502013-04-25 10:18:17 -07001013 mutex_init(&vadc->adc->adc_lock);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001014
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001015 rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001016 qpnp_vadc_isr, IRQF_TRIGGER_RISING,
1017 "qpnp_vadc_interrupt", vadc);
1018 if (rc) {
1019 dev_err(&spmi->dev,
1020 "failed to request adc irq with error %d\n", rc);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001021 goto fail;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001022 } else {
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001023 enable_irq_wake(vadc->adc->adc_irq_eoc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001024 }
1025
1026 qpnp_vadc = vadc;
1027 dev_set_drvdata(&spmi->dev, vadc);
1028 rc = qpnp_vadc_init_hwmon(spmi);
1029 if (rc) {
1030 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001031 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001032 }
1033 vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
1034 vadc->vadc_init_calib = false;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001035 vadc->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -07001036 vadc->vadc_initialized = true;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001037 vadc->vadc_iadc_sync_lock = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001038
1039 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001040fail:
1041 qpnp_vadc = NULL;
1042 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001043}
1044
1045static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
1046{
1047 struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
1048 struct device_node *node = spmi->dev.of_node;
1049 struct device_node *child;
1050 int i = 0;
1051
1052 for_each_child_of_node(node, child) {
1053 device_remove_file(&spmi->dev,
1054 &vadc->sens_attr[i].dev_attr);
1055 i++;
1056 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001057 vadc->vadc_initialized = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001058 dev_set_drvdata(&spmi->dev, NULL);
1059
1060 return 0;
1061}
1062
1063static const struct of_device_id qpnp_vadc_match_table[] = {
1064 { .compatible = "qcom,qpnp-vadc",
1065 },
1066 {}
1067};
1068
1069static struct spmi_driver qpnp_vadc_driver = {
1070 .driver = {
1071 .name = "qcom,qpnp-vadc",
1072 .of_match_table = qpnp_vadc_match_table,
1073 },
1074 .probe = qpnp_vadc_probe,
1075 .remove = qpnp_vadc_remove,
1076};
1077
1078static int __init qpnp_vadc_init(void)
1079{
1080 return spmi_driver_register(&qpnp_vadc_driver);
1081}
1082module_init(qpnp_vadc_init);
1083
1084static void __exit qpnp_vadc_exit(void)
1085{
1086 spmi_driver_unregister(&qpnp_vadc_driver);
1087}
1088module_exit(qpnp_vadc_exit);
1089
1090MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
1091MODULE_LICENSE("GPL v2");