blob: 3df19d7f4ed065639242e01666fa626d754afec4 [file] [log] [blame]
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001/* Copyright (c) 2012, 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 Mohanadoss7b116e12012-06-05 23:27:46 -070093
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070094struct qpnp_vadc_drv {
95 struct qpnp_adc_drv *adc;
96 struct dentry *dent;
97 struct device *vadc_hwmon;
98 bool vadc_init_calib;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070099 bool vadc_initialized;
100 int max_channels_available;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700101 struct sensor_device_attribute sens_attr[0];
102};
103
104struct qpnp_vadc_drv *qpnp_vadc;
105
106static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
107 [SCALE_DEFAULT] = {qpnp_adc_scale_default},
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700108 [SCALE_BATT_THERM] = {qpnp_adc_scale_batt_therm},
109 [SCALE_PMIC_THERM] = {qpnp_adc_scale_pmic_therm},
110 [SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700111 [SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
112 [SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700113};
114
115static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
116{
117 struct qpnp_vadc_drv *vadc = qpnp_vadc;
118 int rc;
119
120 rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700121 (vadc->adc->offset + reg), data, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700122 if (rc < 0) {
123 pr_err("qpnp adc read reg %d failed with %d\n", reg, rc);
124 return rc;
125 }
126
127 return 0;
128}
129
130static int32_t qpnp_vadc_write_reg(int16_t reg, u8 data)
131{
132 struct qpnp_vadc_drv *vadc = qpnp_vadc;
133 int rc;
134 u8 *buf;
135
136 buf = &data;
137
138 rc = spmi_ext_register_writel(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700139 (vadc->adc->offset + reg), buf, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700140 if (rc < 0) {
141 pr_err("qpnp adc write reg %d failed with %d\n", reg, rc);
142 return rc;
143 }
144
145 return 0;
146}
147
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700148static int32_t qpnp_vadc_enable(bool state)
149{
150 int rc = 0;
151 u8 data = 0;
152
153 data = QPNP_VADC_ADC_EN;
154 if (state) {
155 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
156 data);
157 if (rc < 0) {
158 pr_err("VADC enable failed\n");
159 return rc;
160 }
161 } else {
162 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
163 (~data & QPNP_VADC_ADC_EN));
164 if (rc < 0) {
165 pr_err("VADC disable failed\n");
166 return rc;
167 }
168 }
169
170 return 0;
171}
172
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800173static int32_t qpnp_vadc_status_debug(void)
174{
175 int rc = 0;
176 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0, status2 = 0;
177
178 rc = qpnp_vadc_read_reg(QPNP_VADC_MODE_CTL, &mode);
179 if (rc < 0) {
180 pr_err("mode ctl register read failed with %d\n", rc);
181 return rc;
182 }
183
184 rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_DIG_PARAM, &dig);
185 if (rc < 0) {
186 pr_err("digital param read failed with %d\n", rc);
187 return rc;
188 }
189
190 rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_CH_SEL_CTL, &chan);
191 if (rc < 0) {
192 pr_err("channel read failed with %d\n", rc);
193 return rc;
194 }
195
196 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
197 if (rc < 0) {
198 pr_err("status1 read failed with %d\n", rc);
199 return rc;
200 }
201
202 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
203 if (rc < 0) {
204 pr_err("status2 read failed with %d\n", rc);
205 return rc;
206 }
207
208 rc = qpnp_vadc_read_reg(QPNP_VADC_EN_CTL1, &en);
209 if (rc < 0) {
210 pr_err("en read failed with %d\n", rc);
211 return rc;
212 }
213
214 pr_err("EOC not set - status1/2:%x/%x, dig:%x, ch:%x, mode:%x, en:%x\n",
215 status1, status2, dig, chan, mode, en);
216
217 rc = qpnp_vadc_enable(false);
218 if (rc < 0) {
219 pr_err("VADC disable failed with %d\n", rc);
220 return rc;
221 }
222
223 return 0;
224}
Siddartha Mohanadoss8dbb5c22012-12-11 14:50:45 -0800225static int32_t qpnp_vadc_configure(
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700226 struct qpnp_adc_amux_properties *chan_prop)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700227{
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700228 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700229 u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700230 u8 mode_ctrl = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700231 int rc = 0;
232
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700233 /* Mode selection */
Siddartha Mohanadoss429b4492012-12-11 13:29:58 -0800234 mode_ctrl |= ((chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT) |
235 (QPNP_VADC_ADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700236 rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
237 if (rc < 0) {
238 pr_err("Mode configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700239 return rc;
240 }
241
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700242
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700243 /* Channel selection */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700244 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
245 chan_prop->amux_channel);
246 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700247 pr_err("Channel configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700248 return rc;
249 }
250
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700251 /* Digital parameter setup */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700252 decimation = chan_prop->decimation <<
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700253 QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
254 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
255 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700256 pr_err("Digital parameter configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700257 return rc;
258 }
259
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700260 /* HW settling time delay */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700261 rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
262 chan_prop->hw_settle_time);
263 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700264 pr_err("HW settling time setup error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700265 return rc;
266 }
267
268 if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
269 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700270 /* Normal measurement mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700271 rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
272 chan_prop->fast_avg_setup);
273 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700274 pr_err("Fast averaging configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700275 return rc;
276 }
277 } else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
278 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700279 /* Conversion sequence mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700280 conv_sequence = ((ADC_SEQ_HOLD_100US <<
281 QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
282 ADC_CONV_SEQ_TIMEOUT_5MS);
283 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
284 conv_sequence);
285 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700286 pr_err("Conversion sequence error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700287 return rc;
288 }
289
290 conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
291 QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
292 chan_prop->trigger_channel);
293 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
294 conv_sequence_trig);
295 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700296 pr_err("Conversion trigger error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700297 return rc;
298 }
299 }
300
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700301 INIT_COMPLETION(vadc->adc->adc_rslt_completion);
302
303 rc = qpnp_vadc_enable(true);
304 if (rc)
305 return rc;
306
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700307 /* Request conversion */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700308 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
309 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700310 pr_err("Request conversion failed\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700311 return rc;
312 }
313
314 return 0;
315}
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700316
317static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
318{
319 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700320 int rc = 0, status = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700321
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700322 status = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
323 if (status < 0) {
324 pr_err("qpnp adc result read failed for data0\n");
325 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700326 }
327
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700328 status = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
329 if (status < 0) {
330 pr_err("qpnp adc result read failed for data1\n");
331 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700332 }
333
334 *data = (rslt_msb << 8) | rslt_lsb;
335
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700336 status = qpnp_vadc_check_result(data);
337 if (status < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700338 pr_err("VADC data check failed\n");
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700339 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700340 }
341
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700342fail:
343 rc = qpnp_vadc_enable(false);
344 if (rc)
345 return rc;
346
347 return status;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700348}
349
350static int32_t qpnp_vadc_read_status(int mode_sel)
351{
352 u8 status1, status2, status2_conv_seq_state;
353 u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
354 int rc;
355
356 switch (mode_sel) {
357 case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
358 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
359 if (rc) {
360 pr_err("qpnp_vadc read mask interrupt failed\n");
361 return rc;
362 }
363
364 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
365 if (rc) {
366 pr_err("qpnp_vadc read mask interrupt failed\n");
367 return rc;
368 }
369
370 if (!(status2 & ~QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS) &&
371 (status1 & (~QPNP_VADC_STATUS1_REQ_STS |
372 QPNP_VADC_STATUS1_EOC))) {
373 rc = status_err;
374 return rc;
375 }
376
377 status2_conv_seq_state = status2 >>
378 QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT;
379 if (status2_conv_seq_state != ADC_CONV_SEQ_IDLE) {
380 pr_err("qpnp vadc seq error with status %d\n",
381 status2);
382 rc = -EINVAL;
383 return rc;
384 }
385 }
386
387 return 0;
388}
389
390static void qpnp_vadc_work(struct work_struct *work)
391{
392 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700393
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800394 if (!vadc || !vadc->vadc_initialized)
395 return;
396
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700397 complete(&vadc->adc->adc_rslt_completion);
398
399 return;
400}
401DECLARE_WORK(trigger_completion_work, qpnp_vadc_work);
402
403static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
404{
405 schedule_work(&trigger_completion_work);
406
407 return IRQ_HANDLED;
408}
409
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700410static int32_t qpnp_vadc_version_check(void)
411{
412 uint8_t revision;
413 int rc;
414
415 rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
416 if (rc < 0) {
417 pr_err("qpnp adc result read failed with %d\n", rc);
418 return rc;
419 }
420
421 if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
422 pr_err("VADC Version not supported\n");
423 return -EINVAL;
424 }
425
426 return 0;
427}
428
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700429static uint32_t qpnp_vadc_calib_device(void)
430{
431 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700432 struct qpnp_adc_amux_properties conv;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700433 int rc, calib_read_1, calib_read_2;
434 u8 status1 = 0;
435
436 conv.amux_channel = REF_125V;
437 conv.decimation = DECIMATION_TYPE2;
438 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
439 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
440 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
441
442 rc = qpnp_vadc_configure(&conv);
443 if (rc) {
444 pr_err("qpnp_vadc configure failed with %d\n", rc);
445 goto calib_fail;
446 }
447
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700448 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700449 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
450 if (rc < 0)
451 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700452 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700453 usleep_range(QPNP_VADC_CONV_TIME_MIN,
454 QPNP_VADC_CONV_TIME_MAX);
455 }
456
457 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
458 if (rc) {
459 pr_err("qpnp adc read adc failed with %d\n", rc);
460 goto calib_fail;
461 }
462
463 conv.amux_channel = REF_625MV;
464 conv.decimation = DECIMATION_TYPE2;
465 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
466 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
467 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
468 rc = qpnp_vadc_configure(&conv);
469 if (rc) {
470 pr_err("qpnp adc configure failed with %d\n", rc);
471 goto calib_fail;
472 }
473
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700474 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700475 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700476 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
477 if (rc < 0)
478 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700479 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700480 usleep_range(QPNP_VADC_CONV_TIME_MIN,
481 QPNP_VADC_CONV_TIME_MAX);
482 }
483
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700484 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700485 if (rc) {
486 pr_err("qpnp adc read adc failed with %d\n", rc);
487 goto calib_fail;
488 }
489
490 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
491 (calib_read_1 - calib_read_2);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700492
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700493 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
494 = QPNP_ADC_625_UV;
495 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
496 calib_read_1;
497 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
498 calib_read_2;
499 /* Ratiometric Calibration */
500 conv.amux_channel = VDD_VADC;
501 conv.decimation = DECIMATION_TYPE2;
502 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
503 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
504 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
505 rc = qpnp_vadc_configure(&conv);
506 if (rc) {
507 pr_err("qpnp adc configure failed with %d\n", rc);
508 goto calib_fail;
509 }
510
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700511 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700512 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700513 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
514 if (rc < 0)
515 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700516 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700517 usleep_range(QPNP_VADC_CONV_TIME_MIN,
518 QPNP_VADC_CONV_TIME_MAX);
519 }
520
521 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
522 if (rc) {
523 pr_err("qpnp adc read adc failed with %d\n", rc);
524 goto calib_fail;
525 }
526
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700527 conv.amux_channel = GND_REF;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700528 conv.decimation = DECIMATION_TYPE2;
529 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
530 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
531 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
532 rc = qpnp_vadc_configure(&conv);
533 if (rc) {
534 pr_err("qpnp adc configure failed with %d\n", rc);
535 goto calib_fail;
536 }
537
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700538 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700539 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700540 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
541 if (rc < 0)
542 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700543 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700544 usleep_range(QPNP_VADC_CONV_TIME_MIN,
545 QPNP_VADC_CONV_TIME_MAX);
546 }
547
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700548 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700549 if (rc) {
550 pr_err("qpnp adc read adc failed with %d\n", rc);
551 goto calib_fail;
552 }
553
554 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
555 (calib_read_1 - calib_read_2);
556 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
557 vadc->adc->adc_prop->adc_vdd_reference;
558 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
559 calib_read_1;
560 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
561 calib_read_2;
562
563calib_fail:
564 return rc;
565}
566
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800567int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
568 enum qpnp_adc_calib_type calib_type)
569{
570
571 struct qpnp_vadc_drv *vadc = qpnp_vadc;
572
573 switch (calib_type) {
574 case CALIB_RATIOMETRIC:
575 param->dy =
576 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
577 param->dx =
578 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
579 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
580 param->adc_gnd =
581 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
582 break;
583 case CALIB_ABSOLUTE:
584 param->dy =
585 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
586 param->dx =
587 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
588 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
589 param->adc_gnd =
590 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
591 break;
592 default:
593 return -EINVAL;
594 }
595
596 return 0;
597}
598EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
599
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700600int32_t qpnp_vadc_is_ready(void)
601{
602 struct qpnp_vadc_drv *vadc = qpnp_vadc;
603
604 if (!vadc || !vadc->vadc_initialized)
605 return -EPROBE_DEFER;
606 else
607 return 0;
608}
609EXPORT_SYMBOL(qpnp_vadc_is_ready);
610
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700611int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
612 enum qpnp_vadc_channels channel,
613 struct qpnp_vadc_result *result)
614{
615 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700616 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
617
618 if (!vadc || !vadc->vadc_initialized)
619 return -EPROBE_DEFER;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700620
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800621 mutex_lock(&vadc->adc->adc_lock);
622
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700623 if (!vadc->vadc_init_calib) {
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700624 rc = qpnp_vadc_version_check();
625 if (rc)
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800626 goto fail_unlock;
627
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700628 rc = qpnp_vadc_calib_device();
629 if (rc) {
630 pr_err("Calibration failed\n");
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800631 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700632 } else
633 vadc->vadc_init_calib = true;
634 }
635
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700636 vadc->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700637
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800638 while ((vadc->adc->adc_channels[dt_index].channel_num
639 != channel) && (dt_index < vadc->max_channels_available))
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700640 dt_index++;
641
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800642 if (dt_index >= vadc->max_channels_available) {
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700643 pr_err("not a valid VADC channel\n");
644 rc = -EINVAL;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700645 goto fail_unlock;
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700646 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700647
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700648 vadc->adc->amux_prop->decimation =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700649 vadc->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700650 vadc->adc->amux_prop->hw_settle_time =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700651 vadc->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700652 vadc->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700653 vadc->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700654
655 if (trigger_channel < ADC_SEQ_NONE)
656 vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
657 << QPNP_VADC_OP_MODE_SHIFT);
658 else if (trigger_channel == ADC_SEQ_NONE)
659 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
660 << QPNP_VADC_OP_MODE_SHIFT);
661 else {
662 pr_err("Invalid trigger channel:%d\n", trigger_channel);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700663 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700664 }
665
666 vadc->adc->amux_prop->trigger_channel = trigger_channel;
667
668 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
669 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700670 pr_err("qpnp vadc configure failed with %d\n", rc);
671 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700672 }
673
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700674 rc = wait_for_completion_timeout(&vadc->adc->adc_rslt_completion,
675 QPNP_ADC_COMPLETION_TIMEOUT);
676 if (!rc) {
677 u8 status1 = 0;
678 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
679 if (rc < 0)
680 goto fail_unlock;
681 status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
682 if (status1 == QPNP_VADC_STATUS1_EOC)
683 pr_debug("End of conversion status set\n");
684 else {
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800685 rc = qpnp_vadc_status_debug();
686 if (rc < 0)
687 pr_err("VADC disable failed\n");
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700688 rc = -EINVAL;
689 goto fail_unlock;
690 }
691 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700692
693 if (trigger_channel < ADC_SEQ_NONE) {
694 rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
695 if (rc)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700696 pr_debug("Conversion sequence timed out - %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700697 }
698
699 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
700 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700701 pr_err("qpnp vadc read adc code failed with %d\n", rc);
702 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700703 }
704
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700705 amux_prescaling =
706 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700707
708 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
709 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
710 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
711 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
712
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700713 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700714 if (scale_type >= SCALE_NONE) {
715 rc = -EBADF;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700716 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700717 }
718
719 vadc_scale_fn[scale_type].chan(result->adc_code,
720 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
721
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700722fail_unlock:
723 mutex_unlock(&vadc->adc->adc_lock);
724
725 return rc;
726}
727EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
728
729int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
730 struct qpnp_vadc_result *result)
731{
732 return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
733 channel, result);
734}
735EXPORT_SYMBOL_GPL(qpnp_vadc_read);
736
737static ssize_t qpnp_adc_show(struct device *dev,
738 struct device_attribute *devattr, char *buf)
739{
740 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
741 struct qpnp_vadc_result result;
742 int rc = -1;
743
744 rc = qpnp_vadc_read(attr->index, &result);
745
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700746 if (rc) {
747 pr_err("VADC read error with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700748 return 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700749 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700750
751 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
752 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
753}
754
755static struct sensor_device_attribute qpnp_adc_attr =
756 SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
757
758static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
759{
760 struct qpnp_vadc_drv *vadc = qpnp_vadc;
761 struct device_node *child;
762 struct device_node *node = spmi->dev.of_node;
763 int rc = 0, i = 0, channel;
764
765 for_each_child_of_node(node, child) {
766 channel = vadc->adc->adc_channels[i].channel_num;
767 qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
768 qpnp_adc_attr.dev_attr.attr.name =
769 vadc->adc->adc_channels[i].name;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700770 memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
771 sizeof(qpnp_adc_attr));
Stephen Boydd7337962012-10-30 11:10:46 -0700772 sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700773 rc = device_create_file(&spmi->dev,
774 &vadc->sens_attr[i].dev_attr);
775 if (rc) {
776 dev_err(&spmi->dev,
777 "device_create_file failed for dev %s\n",
778 vadc->adc->adc_channels[i].name);
779 goto hwmon_err_sens;
780 }
781 i++;
782 }
783
784 return 0;
785hwmon_err_sens:
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700786 pr_err("Init HWMON failed for qpnp_adc with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700787 return rc;
788}
789
790static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
791{
792 struct qpnp_vadc_drv *vadc;
793 struct qpnp_adc_drv *adc_qpnp;
794 struct device_node *node = spmi->dev.of_node;
795 struct device_node *child;
796 int rc, count_adc_channel_list = 0;
797
798 if (!node)
799 return -EINVAL;
800
801 if (qpnp_vadc) {
802 pr_err("VADC already in use\n");
803 return -EBUSY;
804 }
805
806 for_each_child_of_node(node, child)
807 count_adc_channel_list++;
808
809 if (!count_adc_channel_list) {
810 pr_err("No channel listing\n");
811 return -EINVAL;
812 }
813
814 vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
815 (sizeof(struct sensor_device_attribute) *
816 count_adc_channel_list), GFP_KERNEL);
817 if (!vadc) {
818 dev_err(&spmi->dev, "Unable to allocate memory\n");
819 return -ENOMEM;
820 }
821
822 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
823 GFP_KERNEL);
824 if (!adc_qpnp) {
825 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800826 rc = -ENOMEM;
827 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700828 }
829
830 vadc->adc = adc_qpnp;
831
832 rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
833 if (rc) {
834 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800835 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700836 }
837
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800838 rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700839 qpnp_vadc_isr, IRQF_TRIGGER_RISING,
840 "qpnp_vadc_interrupt", vadc);
841 if (rc) {
842 dev_err(&spmi->dev,
843 "failed to request adc irq with error %d\n", rc);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800844 goto fail;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700845 } else {
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800846 enable_irq_wake(vadc->adc->adc_irq_eoc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700847 }
848
849 qpnp_vadc = vadc;
850 dev_set_drvdata(&spmi->dev, vadc);
851 rc = qpnp_vadc_init_hwmon(spmi);
852 if (rc) {
853 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800854 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700855 }
856 vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
857 vadc->vadc_init_calib = false;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700858 vadc->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -0700859 vadc->vadc_initialized = true;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700860
861 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800862fail:
863 qpnp_vadc = NULL;
864 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700865}
866
867static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
868{
869 struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
870 struct device_node *node = spmi->dev.of_node;
871 struct device_node *child;
872 int i = 0;
873
874 for_each_child_of_node(node, child) {
875 device_remove_file(&spmi->dev,
876 &vadc->sens_attr[i].dev_attr);
877 i++;
878 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700879 vadc->vadc_initialized = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700880 dev_set_drvdata(&spmi->dev, NULL);
881
882 return 0;
883}
884
885static const struct of_device_id qpnp_vadc_match_table[] = {
886 { .compatible = "qcom,qpnp-vadc",
887 },
888 {}
889};
890
891static struct spmi_driver qpnp_vadc_driver = {
892 .driver = {
893 .name = "qcom,qpnp-vadc",
894 .of_match_table = qpnp_vadc_match_table,
895 },
896 .probe = qpnp_vadc_probe,
897 .remove = qpnp_vadc_remove,
898};
899
900static int __init qpnp_vadc_init(void)
901{
902 return spmi_driver_register(&qpnp_vadc_driver);
903}
904module_init(qpnp_vadc_init);
905
906static void __exit qpnp_vadc_exit(void)
907{
908 spmi_driver_unregister(&qpnp_vadc_driver);
909}
910module_exit(qpnp_vadc_exit);
911
912MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
913MODULE_LICENSE("GPL v2");