blob: 66811bf2420ddea009bde5c39b99c7a6ff26f0f9 [file] [log] [blame]
Xiaozhe Shi767fdb62013-01-10 15:09:08 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -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/wakelock.h>
29#include <linux/interrupt.h>
30#include <linux/completion.h>
31#include <linux/hwmon-sysfs.h>
32#include <linux/qpnp/qpnp-adc.h>
33#include <linux/platform_device.h>
34
35/* QPNP IADC register definition */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070036#define QPNP_IADC_REVISION1 0x0
37#define QPNP_IADC_REVISION2 0x1
38#define QPNP_IADC_REVISION3 0x2
39#define QPNP_IADC_REVISION4 0x3
40#define QPNP_IADC_PERPH_TYPE 0x4
41#define QPNP_IADC_PERH_SUBTYPE 0x5
42
43#define QPNP_IADC_SUPPORTED_REVISION2 1
44
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070045#define QPNP_STATUS1 0x8
46#define QPNP_STATUS1_OP_MODE 4
47#define QPNP_STATUS1_MULTI_MEAS_EN BIT(3)
48#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
49#define QPNP_STATUS1_REQ_STS BIT(1)
50#define QPNP_STATUS1_EOC BIT(0)
51#define QPNP_STATUS2 0x9
52#define QPNP_STATUS2_CONV_SEQ_STATE_SHIFT 4
53#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
54#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
55#define QPNP_CONV_TIMEOUT_ERR 2
56
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070057#define QPNP_IADC_MODE_CTL 0x40
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070058#define QPNP_OP_MODE_SHIFT 4
59#define QPNP_USE_BMS_DATA BIT(4)
60#define QPNP_VADC_SYNCH_EN BIT(2)
61#define QPNP_OFFSET_RMV_EN BIT(1)
62#define QPNP_ADC_TRIM_EN BIT(0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070063#define QPNP_IADC_EN_CTL1 0x46
64#define QPNP_IADC_ADC_EN BIT(7)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070065#define QPNP_ADC_CH_SEL_CTL 0x48
66#define QPNP_ADC_DIG_PARAM 0x50
67#define QPNP_ADC_CLK_SEL_MASK 0x3
68#define QPNP_ADC_DEC_RATIO_SEL_MASK 0xc
69#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 2
70
71#define QPNP_HW_SETTLE_DELAY 0x51
72#define QPNP_CONV_REQ 0x52
73#define QPNP_CONV_REQ_SET BIT(7)
74#define QPNP_CONV_SEQ_CTL 0x54
75#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
76#define QPNP_CONV_SEQ_TRIG_CTL 0x55
77#define QPNP_FAST_AVG_CTL 0x5a
78
79#define QPNP_M0_LOW_THR_LSB 0x5c
80#define QPNP_M0_LOW_THR_MSB 0x5d
81#define QPNP_M0_HIGH_THR_LSB 0x5e
82#define QPNP_M0_HIGH_THR_MSB 0x5f
83#define QPNP_M1_LOW_THR_LSB 0x69
84#define QPNP_M1_LOW_THR_MSB 0x6a
85#define QPNP_M1_HIGH_THR_LSB 0x6b
86#define QPNP_M1_HIGH_THR_MSB 0x6c
87
88#define QPNP_DATA0 0x60
89#define QPNP_DATA1 0x61
90#define QPNP_CONV_TIMEOUT_ERR 2
91
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -070092#define QPNP_IADC_SEC_ACCESS 0xD0
93#define QPNP_IADC_SEC_ACCESS_DATA 0xA5
94#define QPNP_IADC_MSB_OFFSET 0xF2
95#define QPNP_IADC_LSB_OFFSET 0xF3
96#define QPNP_IADC_NOMINAL_RSENSE 0xF4
97#define QPNP_IADC_ATE_GAIN_CALIB_OFFSET 0xF5
98
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070099#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
100#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
101
102#define QPNP_IADC_ADC_DIG_PARAM 0x50
103#define QPNP_IADC_CLK_SEL_SHIFT 1
104#define QPNP_IADC_DEC_RATIO_SEL 3
105
106#define QPNP_IADC_CONV_REQUEST 0x52
107#define QPNP_IADC_CONV_REQ BIT(7)
108
109#define QPNP_IADC_DATA0 0x60
110#define QPNP_IADC_DATA1 0x61
111
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700112#define QPNP_ADC_CONV_TIME_MIN 8000
113#define QPNP_ADC_CONV_TIME_MAX 8200
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700114
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700115#define QPNP_ADC_GAIN_NV 17857
116#define QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL 0
117#define QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR 10000000
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700118#define QPNP_IADC_NANO_VOLTS_FACTOR 1000000
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700119#define QPNP_IADC_CALIB_SECONDS 300000
120#define QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT 15625
121#define QPNP_IADC_DIE_TEMP_CALIB_OFFSET 5000
122
123#define QPNP_RAW_CODE_16_BIT_MSB_MASK 0xff00
124#define QPNP_RAW_CODE_16_BIT_LSB_MASK 0xff
125#define QPNP_BIT_SHIFT_8 8
126#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700127#define QPNP_ADC_COMPLETION_TIMEOUT HZ
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700128
129struct qpnp_iadc_drv {
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700130 struct qpnp_adc_drv *adc;
131 int32_t rsense;
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700132 bool external_rsense;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700133 struct device *iadc_hwmon;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700134 bool iadc_initialized;
135 int64_t die_temp_calib_offset;
136 struct delayed_work iadc_work;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800137 struct mutex iadc_vadc_lock;
138 bool iadc_mode_sel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700139 struct sensor_device_attribute sens_attr[0];
140};
141
142struct qpnp_iadc_drv *qpnp_iadc;
143
144static int32_t qpnp_iadc_read_reg(uint32_t reg, u8 *data)
145{
146 struct qpnp_iadc_drv *iadc = qpnp_iadc;
147 int rc;
148
149 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700150 (iadc->adc->offset + reg), data, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700151 if (rc < 0) {
152 pr_err("qpnp iadc read reg %d failed with %d\n", reg, rc);
153 return rc;
154 }
155
156 return 0;
157}
158
159static int32_t qpnp_iadc_write_reg(uint32_t reg, u8 data)
160{
161 struct qpnp_iadc_drv *iadc = qpnp_iadc;
162 int rc;
163 u8 *buf;
164
165 buf = &data;
166 rc = spmi_ext_register_writel(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700167 (iadc->adc->offset + reg), buf, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700168 if (rc < 0) {
169 pr_err("qpnp iadc write reg %d failed with %d\n", reg, rc);
170 return rc;
171 }
172
173 return 0;
174}
175
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800176static void trigger_iadc_completion(struct work_struct *work)
177{
178 struct qpnp_iadc_drv *iadc = qpnp_iadc;
179
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800180 if (!iadc || !iadc->iadc_initialized)
181 return;
182
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800183 complete(&iadc->adc->adc_rslt_completion);
184
185 return;
186}
187DECLARE_WORK(trigger_iadc_completion_work, trigger_iadc_completion);
188
189static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
190{
191 schedule_work(&trigger_iadc_completion_work);
192
193 return IRQ_HANDLED;
194}
195
196static int32_t qpnp_iadc_enable(bool state)
197{
198 int rc = 0;
199 u8 data = 0;
200
201 data = QPNP_IADC_ADC_EN;
202 if (state) {
203 rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
204 data);
205 if (rc < 0) {
206 pr_err("IADC enable failed\n");
207 return rc;
208 }
209 } else {
210 rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
211 (~data & QPNP_IADC_ADC_EN));
212 if (rc < 0) {
213 pr_err("IADC disable failed\n");
214 return rc;
215 }
216 }
217
218 return 0;
219}
220
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800221static int32_t qpnp_iadc_status_debug(void)
222{
223 int rc = 0;
224 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
225
226 rc = qpnp_iadc_read_reg(QPNP_IADC_MODE_CTL, &mode);
227 if (rc < 0) {
228 pr_err("mode ctl register read failed with %d\n", rc);
229 return rc;
230 }
231
232 rc = qpnp_iadc_read_reg(QPNP_ADC_DIG_PARAM, &dig);
233 if (rc < 0) {
234 pr_err("digital param read failed with %d\n", rc);
235 return rc;
236 }
237
238 rc = qpnp_iadc_read_reg(QPNP_IADC_ADC_CH_SEL_CTL, &chan);
239 if (rc < 0) {
240 pr_err("channel read failed with %d\n", rc);
241 return rc;
242 }
243
244 rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
245 if (rc < 0) {
246 pr_err("status1 read failed with %d\n", rc);
247 return rc;
248 }
249
250 rc = qpnp_iadc_read_reg(QPNP_IADC_EN_CTL1, &en);
251 if (rc < 0) {
252 pr_err("en read failed with %d\n", rc);
253 return rc;
254 }
255
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700256 pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800257 status1, dig, chan, mode, en);
258
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800259 rc = qpnp_iadc_enable(false);
260 if (rc < 0) {
261 pr_err("IADC disable failed with %d\n", rc);
262 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700263 }
264
265 return 0;
266}
267
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700268static int32_t qpnp_iadc_read_conversion_result(uint16_t *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700269{
270 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700271 uint16_t rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700272 int32_t rc;
273
274 rc = qpnp_iadc_read_reg(QPNP_IADC_DATA0, &rslt_lsb);
275 if (rc < 0) {
276 pr_err("qpnp adc result read failed with %d\n", rc);
277 return rc;
278 }
279
280 rc = qpnp_iadc_read_reg(QPNP_IADC_DATA1, &rslt_msb);
281 if (rc < 0) {
282 pr_err("qpnp adc result read failed with %d\n", rc);
283 return rc;
284 }
285
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700286 rslt = (rslt_msb << 8) | rslt_lsb;
287 *data = rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700288
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700289 rc = qpnp_iadc_enable(false);
290 if (rc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700291 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700292
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700293 return 0;
294}
295
296static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800297 uint16_t *raw_code, uint32_t mode_sel)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700298{
299 struct qpnp_iadc_drv *iadc = qpnp_iadc;
300 u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
301 u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
302 int32_t rc = 0;
303
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700304 qpnp_iadc_ch_sel_reg = channel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700305
306 qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
307 QPNP_IADC_DEC_RATIO_SEL;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800308 if (iadc->iadc_mode_sel)
309 qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN);
310 else
311 qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
312
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700313 qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
314
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700315 rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
316 if (rc) {
317 pr_err("qpnp adc read adc failed with %d\n", rc);
318 return rc;
319 }
320
321 rc = qpnp_iadc_write_reg(QPNP_IADC_ADC_CH_SEL_CTL,
322 qpnp_iadc_ch_sel_reg);
323 if (rc) {
324 pr_err("qpnp adc read adc failed with %d\n", rc);
325 return rc;
326 }
327
328 rc = qpnp_iadc_write_reg(QPNP_ADC_DIG_PARAM,
329 qpnp_iadc_dig_param_reg);
330 if (rc) {
331 pr_err("qpnp adc read adc failed with %d\n", rc);
332 return rc;
333 }
334
335 rc = qpnp_iadc_write_reg(QPNP_HW_SETTLE_DELAY,
336 iadc->adc->amux_prop->hw_settle_time);
337 if (rc < 0) {
338 pr_err("qpnp adc configure error for hw settling time setup\n");
339 return rc;
340 }
341
342 rc = qpnp_iadc_write_reg(QPNP_FAST_AVG_CTL,
343 iadc->adc->amux_prop->fast_avg_setup);
344 if (rc < 0) {
345 pr_err("qpnp adc fast averaging configure error\n");
346 return rc;
347 }
348
Siddartha Mohanadoss3f219c42013-04-02 11:01:28 -0700349 INIT_COMPLETION(iadc->adc->adc_rslt_completion);
350
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700351 rc = qpnp_iadc_enable(true);
352 if (rc)
353 return rc;
354
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700355 rc = qpnp_iadc_write_reg(QPNP_CONV_REQ, qpnp_iadc_conv_req);
356 if (rc) {
357 pr_err("qpnp adc read adc failed with %d\n", rc);
358 return rc;
359 }
360
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700361 rc = wait_for_completion_timeout(&iadc->adc->adc_rslt_completion,
362 QPNP_ADC_COMPLETION_TIMEOUT);
363 if (!rc) {
364 u8 status1 = 0;
365 rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
366 if (rc < 0)
367 return rc;
368 status1 &= (QPNP_STATUS1_REQ_STS | QPNP_STATUS1_EOC);
369 if (status1 == QPNP_STATUS1_EOC)
370 pr_debug("End of conversion status set\n");
371 else {
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800372 rc = qpnp_iadc_status_debug();
373 if (rc < 0) {
374 pr_err("status1 read failed with %d\n", rc);
375 return rc;
376 }
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700377 return -EINVAL;
378 }
379 }
380
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700381 rc = qpnp_iadc_read_conversion_result(raw_code);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700382 if (rc) {
383 pr_err("qpnp adc read adc failed with %d\n", rc);
384 return rc;
385 }
386
387 return 0;
388}
389
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700390static int32_t qpnp_convert_raw_offset_voltage(void)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700391{
392 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700393 uint32_t num = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700394
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800395 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
396 pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
397 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
398 return -EINVAL;
399 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700400
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800401 iadc->adc->calib.offset_uv = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700402
403 num = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
404
405 iadc->adc->calib.gain_uv = (num * QPNP_ADC_GAIN_NV)/
406 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
407
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700408 pr_debug("gain_uv:%d offset_uv:%d\n",
409 iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700410 return 0;
411}
412
Siddartha Mohanadoss06673922013-03-27 11:14:19 -0700413int32_t qpnp_iadc_calibrate_for_trim(void)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700414{
415 struct qpnp_iadc_drv *iadc = qpnp_iadc;
416 uint8_t rslt_lsb, rslt_msb;
417 int32_t rc = 0;
418 uint16_t raw_data;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800419 uint32_t mode_sel = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700420
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800421 mutex_lock(&iadc->adc->adc_lock);
422
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800423 rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV,
424 &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700425 if (rc < 0) {
426 pr_err("qpnp adc result read failed with %d\n", rc);
427 goto fail;
428 }
429
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700430 iadc->adc->calib.gain_raw = raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700431
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800432 rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP2_CSN2,
433 &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700434 if (rc < 0) {
435 pr_err("qpnp adc result read failed with %d\n", rc);
436 goto fail;
437 }
438
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700439 iadc->adc->calib.offset_raw = raw_data;
440 if (rc < 0) {
441 pr_err("qpnp adc offset/gain calculation failed\n");
442 goto fail;
443 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700444
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700445 pr_debug("raw gain:0x%x, raw offset:0x%x\n",
446 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
447
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700448 rc = qpnp_convert_raw_offset_voltage();
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800449 if (rc < 0) {
450 pr_err("qpnp raw_voltage conversion failed\n");
451 goto fail;
452 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700453
454 rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
455 QPNP_BIT_SHIFT_8;
456 rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
457
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700458 pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
459
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700460 rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
461 QPNP_IADC_SEC_ACCESS_DATA);
462 if (rc < 0) {
463 pr_err("qpnp iadc configure error for sec access\n");
464 goto fail;
465 }
466
467 rc = qpnp_iadc_write_reg(QPNP_IADC_MSB_OFFSET,
468 rslt_msb);
469 if (rc < 0) {
470 pr_err("qpnp iadc configure error for MSB write\n");
471 goto fail;
472 }
473
474 rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
475 QPNP_IADC_SEC_ACCESS_DATA);
476 if (rc < 0) {
477 pr_err("qpnp iadc configure error for sec access\n");
478 goto fail;
479 }
480
481 rc = qpnp_iadc_write_reg(QPNP_IADC_LSB_OFFSET,
482 rslt_lsb);
483 if (rc < 0) {
484 pr_err("qpnp iadc configure error for LSB write\n");
485 goto fail;
486 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700487fail:
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800488 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700489 return rc;
490}
Siddartha Mohanadoss06673922013-03-27 11:14:19 -0700491EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700492
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700493static void qpnp_iadc_work(struct work_struct *work)
494{
495 struct qpnp_iadc_drv *iadc = qpnp_iadc;
496 int rc = 0;
497
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700498 rc = qpnp_iadc_calibrate_for_trim();
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700499 if (rc)
500 pr_debug("periodic IADC calibration failed\n");
501 else
Siddartha Mohanadoss12a15ea2013-02-05 19:13:41 -0800502 schedule_delayed_work(&iadc->iadc_work,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700503 round_jiffies_relative(msecs_to_jiffies
504 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700505 return;
506}
507
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700508static int32_t qpnp_iadc_version_check(void)
509{
510 uint8_t revision;
511 int rc;
512
513 rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &revision);
514 if (rc < 0) {
515 pr_err("qpnp adc result read failed with %d\n", rc);
516 return rc;
517 }
518
519 if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
520 pr_err("IADC Version not supported\n");
521 return -EINVAL;
522 }
523
524 return 0;
525}
526
527int32_t qpnp_iadc_is_ready(void)
528{
529 struct qpnp_iadc_drv *iadc = qpnp_iadc;
530
531 if (!iadc || !iadc->iadc_initialized)
532 return -EPROBE_DEFER;
533 else
534 return 0;
535}
536EXPORT_SYMBOL(qpnp_iadc_is_ready);
537
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700538int32_t qpnp_iadc_get_rsense(int32_t *rsense)
539{
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800540 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700541 uint8_t rslt_rsense;
542 int32_t rc, sign_bit = 0;
543
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800544 if (!iadc || !iadc->iadc_initialized)
545 return -EPROBE_DEFER;
546
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700547 if (iadc->external_rsense)
548 *rsense = iadc->rsense;
549
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700550 rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
551 if (rc < 0) {
552 pr_err("qpnp adc rsense read failed with %d\n", rc);
553 return rc;
554 }
555
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700556 pr_debug("rsense:0%x\n", rslt_rsense);
557
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700558 if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
559 sign_bit = 1;
560
561 rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
562
563 if (sign_bit)
564 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
565 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
566 else
567 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
568 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
569
570 return rc;
571}
Xiaozhe Shi767fdb62013-01-10 15:09:08 -0800572EXPORT_SYMBOL(qpnp_iadc_get_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700573
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800574static int32_t qpnp_check_pmic_temp(void)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700575{
576 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700577 struct qpnp_vadc_result result_pmic_therm;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700578 int64_t die_temp_offset;
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800579 int rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700580
581 rc = qpnp_vadc_read(DIE_TEMP, &result_pmic_therm);
582 if (rc < 0)
583 return rc;
584
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700585 die_temp_offset = result_pmic_therm.physical -
586 iadc->die_temp_calib_offset;
587 if (die_temp_offset < 0)
588 die_temp_offset = -die_temp_offset;
589
590 if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
591 iadc->die_temp_calib_offset =
592 result_pmic_therm.physical;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700593 rc = qpnp_iadc_calibrate_for_trim();
594 if (rc)
595 pr_err("periodic IADC calibration failed\n");
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700596 }
597
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800598 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700599}
600
601int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
602 struct qpnp_iadc_result *result)
603{
604 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800605 int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700606 int32_t rsense_u_ohms = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700607 int64_t result_current;
608 uint16_t raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700609
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700610 if (!iadc || !iadc->iadc_initialized)
611 return -EPROBE_DEFER;
612
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800613 if (!iadc->iadc_mode_sel) {
614 rc = qpnp_check_pmic_temp();
615 if (rc) {
616 pr_err("Error checking pmic therm temp\n");
617 return rc;
618 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700619 }
620
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700621 mutex_lock(&iadc->adc->adc_lock);
622
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800623 rc = qpnp_iadc_configure(channel, &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700624 if (rc < 0) {
625 pr_err("qpnp adc result read failed with %d\n", rc);
626 goto fail;
627 }
628
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700629 rc = qpnp_iadc_get_rsense(&rsense_n_ohms);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700630 pr_debug("current raw:0%x and rsense:%d\n",
631 raw_data, rsense_n_ohms);
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700632 rsense_u_ohms = rsense_n_ohms/1000;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700633 num = raw_data - iadc->adc->calib.offset_raw;
634 if (num < 0) {
635 sign = 1;
636 num = -num;
637 }
638
639 result->result_uv = (num * QPNP_ADC_GAIN_NV)/
640 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
641 result_current = result->result_uv;
642 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700643 do_div(result_current, rsense_u_ohms);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700644
645 if (sign) {
646 result->result_uv = -result->result_uv;
647 result_current = -result_current;
648 }
649
650 result->result_ua = (int32_t) result_current;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700651fail:
652 mutex_unlock(&iadc->adc->adc_lock);
653
654 return rc;
655}
656EXPORT_SYMBOL(qpnp_iadc_read);
657
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700658int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700659{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700660 struct qpnp_iadc_drv *iadc = qpnp_iadc;
661 int rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700662
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700663 if (!iadc || !iadc->iadc_initialized)
664 return -EPROBE_DEFER;
665
666 rc = qpnp_check_pmic_temp();
667 if (rc) {
668 pr_err("Error checking pmic therm temp\n");
669 return rc;
670 }
671
672 mutex_lock(&iadc->adc->adc_lock);
673 result->gain_raw = iadc->adc->calib.gain_raw;
674 result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
675 result->gain_uv = iadc->adc->calib.gain_uv;
676 result->offset_raw = iadc->adc->calib.offset_raw;
677 result->ideal_offset_uv =
678 QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
679 result->offset_uv = iadc->adc->calib.offset_uv;
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700680 pr_debug("raw gain:0%x, raw offset:0%x\n",
681 result->gain_raw, result->offset_raw);
682 pr_debug("gain_uv:%d offset_uv:%d\n",
683 result->gain_uv, result->offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700684 mutex_unlock(&iadc->adc->adc_lock);
685
686 return 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700687}
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700688EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700689
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800690int32_t qpnp_iadc_vadc_sync_read(
691 enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
692 enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
693{
694 struct qpnp_iadc_drv *iadc = qpnp_iadc;
695 int rc = 0;
696
697 if (!iadc || !iadc->iadc_initialized)
698 return -EPROBE_DEFER;
699
700 mutex_lock(&iadc->iadc_vadc_lock);
701
702 rc = qpnp_check_pmic_temp();
703 if (rc) {
704 pr_err("PMIC die temp check failed\n");
705 goto fail;
706 }
707
708 iadc->iadc_mode_sel = true;
709
710 rc = qpnp_vadc_iadc_sync_request(v_channel);
711 if (rc) {
712 pr_err("Configuring VADC failed\n");
713 goto fail;
714 }
715
716 rc = qpnp_iadc_read(i_channel, i_result);
717 if (rc)
718 pr_err("Configuring IADC failed\n");
719 /* Intentional fall through to release VADC */
720
721 rc = qpnp_vadc_iadc_sync_complete_request(v_channel,
722 v_result);
723 if (rc)
724 pr_err("Releasing VADC failed\n");
725fail:
726 iadc->iadc_mode_sel = false;
727
728 mutex_unlock(&iadc->iadc_vadc_lock);
729
730 return rc;
731}
732EXPORT_SYMBOL(qpnp_iadc_vadc_sync_read);
733
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700734static ssize_t qpnp_iadc_show(struct device *dev,
735 struct device_attribute *devattr, char *buf)
736{
737 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700738 struct qpnp_iadc_result result;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700739 int rc = -1;
740
741 rc = qpnp_iadc_read(attr->index, &result);
742
743 if (rc)
744 return 0;
745
746 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700747 "Result:%d\n", result.result_ua);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700748}
749
750static struct sensor_device_attribute qpnp_adc_attr =
751 SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
752
753static int32_t qpnp_iadc_init_hwmon(struct spmi_device *spmi)
754{
755 struct qpnp_iadc_drv *iadc = qpnp_iadc;
756 struct device_node *child;
757 struct device_node *node = spmi->dev.of_node;
758 int rc = 0, i = 0, channel;
759
760 for_each_child_of_node(node, child) {
761 channel = iadc->adc->adc_channels[i].channel_num;
762 qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
763 qpnp_adc_attr.dev_attr.attr.name =
764 iadc->adc->adc_channels[i].name;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700765 memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
766 sizeof(qpnp_adc_attr));
Stephen Boyd8a5c4e42012-10-30 11:07:22 -0700767 sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700768 rc = device_create_file(&spmi->dev,
769 &iadc->sens_attr[i].dev_attr);
770 if (rc) {
771 dev_err(&spmi->dev,
772 "device_create_file failed for dev %s\n",
773 iadc->adc->adc_channels[i].name);
774 goto hwmon_err_sens;
775 }
776 i++;
777 }
778
779 return 0;
780hwmon_err_sens:
781 pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
782 return rc;
783}
784
785static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
786{
787 struct qpnp_iadc_drv *iadc;
788 struct qpnp_adc_drv *adc_qpnp;
789 struct device_node *node = spmi->dev.of_node;
790 struct device_node *child;
791 int rc, count_adc_channel_list = 0;
792
793 if (!node)
794 return -EINVAL;
795
796 if (qpnp_iadc) {
797 pr_err("IADC already in use\n");
798 return -EBUSY;
799 }
800
801 for_each_child_of_node(node, child)
802 count_adc_channel_list++;
803
804 if (!count_adc_channel_list) {
805 pr_err("No channel listing\n");
806 return -EINVAL;
807 }
808
809 iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_drv) +
810 (sizeof(struct sensor_device_attribute) *
811 count_adc_channel_list), GFP_KERNEL);
812 if (!iadc) {
813 dev_err(&spmi->dev, "Unable to allocate memory\n");
814 return -ENOMEM;
815 }
816
817 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
818 GFP_KERNEL);
819 if (!adc_qpnp) {
820 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800821 rc = -ENOMEM;
822 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700823 }
824
825 iadc->adc = adc_qpnp;
826
827 rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
828 if (rc) {
829 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800830 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700831 }
832
833 rc = of_property_read_u32(node, "qcom,rsense",
834 &iadc->rsense);
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700835 if (rc)
836 pr_debug("Defaulting to internal rsense\n");
837 else {
838 pr_debug("Use external rsense\n");
839 iadc->external_rsense = true;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700840 }
841
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800842 rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700843 qpnp_iadc_isr,
844 IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
845 if (rc) {
846 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800847 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700848 } else
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800849 enable_irq_wake(iadc->adc->adc_irq_eoc);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700850
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700851 dev_set_drvdata(&spmi->dev, iadc);
852 qpnp_iadc = iadc;
853
854 rc = qpnp_iadc_init_hwmon(spmi);
855 if (rc) {
856 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800857 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700858 }
859 iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
860
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700861 rc = qpnp_iadc_version_check();
862 if (rc) {
863 dev_err(&spmi->dev, "IADC version not supported\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800864 goto fail;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700865 }
866
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800867 mutex_init(&iadc->iadc_vadc_lock);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800868 INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
Siddartha Mohanadoss12a15ea2013-02-05 19:13:41 -0800869 iadc->iadc_initialized = true;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700870
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800871 rc = qpnp_iadc_calibrate_for_trim();
872 if (rc)
873 dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
874 schedule_delayed_work(&iadc->iadc_work,
875 round_jiffies_relative(msecs_to_jiffies
876 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700877 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800878fail:
Siddartha Mohanadoss32019b52012-12-23 17:05:45 -0800879 qpnp_iadc = NULL;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800880 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700881}
882
883static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
884{
885 struct qpnp_iadc_drv *iadc = dev_get_drvdata(&spmi->dev);
886 struct device_node *node = spmi->dev.of_node;
887 struct device_node *child;
888 int i = 0;
889
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800890 cancel_delayed_work(&iadc->iadc_work);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800891 mutex_destroy(&iadc->iadc_vadc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700892 for_each_child_of_node(node, child) {
893 device_remove_file(&spmi->dev,
894 &iadc->sens_attr[i].dev_attr);
895 i++;
896 }
897 dev_set_drvdata(&spmi->dev, NULL);
898
899 return 0;
900}
901
902static const struct of_device_id qpnp_iadc_match_table[] = {
903 { .compatible = "qcom,qpnp-iadc",
904 },
905 {}
906};
907
908static struct spmi_driver qpnp_iadc_driver = {
909 .driver = {
910 .name = "qcom,qpnp-iadc",
911 .of_match_table = qpnp_iadc_match_table,
912 },
913 .probe = qpnp_iadc_probe,
914 .remove = qpnp_iadc_remove,
915};
916
917static int __init qpnp_iadc_init(void)
918{
919 return spmi_driver_register(&qpnp_iadc_driver);
920}
921module_init(qpnp_iadc_init);
922
923static void __exit qpnp_iadc_exit(void)
924{
925 spmi_driver_unregister(&qpnp_iadc_driver);
926}
927module_exit(qpnp_iadc_exit);
928
929MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
930MODULE_LICENSE("GPL v2");