blob: 8e6afc12dd0676e3f6f8dfea0b3bc6b6e3ed57ac [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
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -070098#define QPNP_INT_TEST_VAL 0xE1
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -070099
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700100#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
101#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
102
103#define QPNP_IADC_ADC_DIG_PARAM 0x50
104#define QPNP_IADC_CLK_SEL_SHIFT 1
105#define QPNP_IADC_DEC_RATIO_SEL 3
106
107#define QPNP_IADC_CONV_REQUEST 0x52
108#define QPNP_IADC_CONV_REQ BIT(7)
109
110#define QPNP_IADC_DATA0 0x60
111#define QPNP_IADC_DATA1 0x61
112
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700113#define QPNP_ADC_CONV_TIME_MIN 8000
114#define QPNP_ADC_CONV_TIME_MAX 8200
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700115
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700116#define QPNP_ADC_GAIN_NV 17857
117#define QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL 0
118#define QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR 10000000
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700119#define QPNP_IADC_NANO_VOLTS_FACTOR 1000000
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700120#define QPNP_IADC_CALIB_SECONDS 300000
121#define QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT 15625
122#define QPNP_IADC_DIE_TEMP_CALIB_OFFSET 5000
123
124#define QPNP_RAW_CODE_16_BIT_MSB_MASK 0xff00
125#define QPNP_RAW_CODE_16_BIT_LSB_MASK 0xff
126#define QPNP_BIT_SHIFT_8 8
127#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700128#define QPNP_ADC_COMPLETION_TIMEOUT HZ
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700129
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700130struct qpnp_iadc_comp {
131 bool ext_rsense;
132 u8 id;
133 u8 sys_gain;
134 u8 revision;
135};
136
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700137struct qpnp_iadc_chip {
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700138 struct qpnp_adc_drv *adc;
139 int32_t rsense;
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700140 bool external_rsense;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700141 struct device *iadc_hwmon;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700142 struct list_head list;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700143 int64_t die_temp;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700144 struct delayed_work iadc_work;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800145 struct mutex iadc_vadc_lock;
146 bool iadc_mode_sel;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700147 struct qpnp_iadc_comp iadc_comp;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700148 struct qpnp_vadc_chip *vadc_dev;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700149 struct work_struct trigger_completion_work;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700150 struct sensor_device_attribute sens_attr[0];
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700151 bool skip_auto_calibrations;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700152};
153
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700154LIST_HEAD(qpnp_iadc_device_list);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700155
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700156static int32_t qpnp_iadc_read_reg(struct qpnp_iadc_chip *iadc,
157 uint32_t reg, u8 *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700158{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700159 int rc;
160
161 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700162 (iadc->adc->offset + reg), data, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700163 if (rc < 0) {
164 pr_err("qpnp iadc read reg %d failed with %d\n", reg, rc);
165 return rc;
166 }
167
168 return 0;
169}
170
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700171static int32_t qpnp_iadc_write_reg(struct qpnp_iadc_chip *iadc,
172 uint32_t reg, u8 data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700173{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700174 int rc;
175 u8 *buf;
176
177 buf = &data;
178 rc = spmi_ext_register_writel(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700179 (iadc->adc->offset + reg), buf, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700180 if (rc < 0) {
181 pr_err("qpnp iadc write reg %d failed with %d\n", reg, rc);
182 return rc;
183 }
184
185 return 0;
186}
187
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700188static int qpnp_iadc_is_valid(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800189{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700190 struct qpnp_iadc_chip *iadc_chip = NULL;
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800191
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700192 list_for_each_entry(iadc_chip, &qpnp_iadc_device_list, list)
193 if (iadc == iadc_chip)
194 return 0;
195
196 return -EINVAL;
197}
198
199static void qpnp_iadc_trigger_completion(struct work_struct *work)
200{
201 struct qpnp_iadc_chip *iadc = container_of(work,
202 struct qpnp_iadc_chip, trigger_completion_work);
203
204 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800205 return;
206
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800207 complete(&iadc->adc->adc_rslt_completion);
208
209 return;
210}
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800211
212static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
213{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700214 struct qpnp_iadc_chip *iadc = dev_id;
215
216 schedule_work(&iadc->trigger_completion_work);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800217
218 return IRQ_HANDLED;
219}
220
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700221static int32_t qpnp_iadc_enable(struct qpnp_iadc_chip *dev, bool state)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800222{
223 int rc = 0;
224 u8 data = 0;
225
226 data = QPNP_IADC_ADC_EN;
227 if (state) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700228 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800229 data);
230 if (rc < 0) {
231 pr_err("IADC enable failed\n");
232 return rc;
233 }
234 } else {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700235 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800236 (~data & QPNP_IADC_ADC_EN));
237 if (rc < 0) {
238 pr_err("IADC disable failed\n");
239 return rc;
240 }
241 }
242
243 return 0;
244}
245
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700246static int32_t qpnp_iadc_status_debug(struct qpnp_iadc_chip *dev)
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800247{
248 int rc = 0;
249 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
250
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700251 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_MODE_CTL, &mode);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800252 if (rc < 0) {
253 pr_err("mode ctl register read failed with %d\n", rc);
254 return rc;
255 }
256
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700257 rc = qpnp_iadc_read_reg(dev, QPNP_ADC_DIG_PARAM, &dig);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800258 if (rc < 0) {
259 pr_err("digital param read failed with %d\n", rc);
260 return rc;
261 }
262
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700263 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_ADC_CH_SEL_CTL, &chan);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800264 if (rc < 0) {
265 pr_err("channel read failed with %d\n", rc);
266 return rc;
267 }
268
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700269 rc = qpnp_iadc_read_reg(dev, QPNP_STATUS1, &status1);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800270 if (rc < 0) {
271 pr_err("status1 read failed with %d\n", rc);
272 return rc;
273 }
274
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700275 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_EN_CTL1, &en);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800276 if (rc < 0) {
277 pr_err("en read failed with %d\n", rc);
278 return rc;
279 }
280
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700281 pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800282 status1, dig, chan, mode, en);
283
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700284 rc = qpnp_iadc_enable(dev, false);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800285 if (rc < 0) {
286 pr_err("IADC disable failed with %d\n", rc);
287 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700288 }
289
290 return 0;
291}
292
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700293static int32_t qpnp_iadc_read_conversion_result(struct qpnp_iadc_chip *iadc,
294 int16_t *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700295{
296 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700297 uint16_t rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700298 int32_t rc;
299
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700300 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA0, &rslt_lsb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700301 if (rc < 0) {
302 pr_err("qpnp adc result read failed with %d\n", rc);
303 return rc;
304 }
305
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700306 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA1, &rslt_msb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700307 if (rc < 0) {
308 pr_err("qpnp adc result read failed with %d\n", rc);
309 return rc;
310 }
311
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700312 rslt = (rslt_msb << 8) | rslt_lsb;
313 *data = rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700314
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700315 rc = qpnp_iadc_enable(iadc, false);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700316 if (rc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700317 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700318
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700319 return 0;
320}
321
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700322static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_comp comp,
323 int64_t die_temp)
324{
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700325 int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0, old;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700326
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700327 old = *result;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700328 *result = *result * 1000000;
329
330 if (comp.revision == QPNP_IADC_VER_3_1) {
331 /* revision 3.1 */
332 if (comp.sys_gain > 127)
333 sys_gain_coeff = -QPNP_COEFF_6 * (comp.sys_gain - 128);
334 else
335 sys_gain_coeff = QPNP_COEFF_6 * comp.sys_gain;
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700336 } else if (comp.revision != QPNP_IADC_VER_3_0) {
337 /* unsupported revision, do not compensate */
338 *result = old;
339 return 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700340 }
341
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700342 if (!comp.ext_rsense) {
343 /* internal rsense */
344 switch (comp.id) {
345 case COMP_ID_TSMC:
346 temp_var = ((QPNP_COEFF_2 * die_temp) -
347 QPNP_COEFF_3_TYPEB);
348 break;
349 case COMP_ID_GF:
350 default:
351 temp_var = ((QPNP_COEFF_2 * die_temp) -
352 QPNP_COEFF_3_TYPEA);
353 break;
354 }
355 temp_var = div64_s64(temp_var, QPNP_COEFF_4);
356 if (comp.revision == QPNP_IADC_VER_3_0)
357 temp_var = QPNP_COEFF_1 * (1000000 - temp_var);
358 else if (comp.revision == QPNP_IADC_VER_3_1)
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700359 temp_var = 1000000 * (1000000 - temp_var);
360 *result = div64_s64(*result * 1000000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700361 }
362
363 sign_coeff = *result < 0 ? QPNP_COEFF_7 : QPNP_COEFF_5;
364 if (comp.ext_rsense) {
365 /* external rsense and current charging */
366 temp_var = div64_s64((-sign_coeff * die_temp) + QPNP_COEFF_8,
367 QPNP_COEFF_4);
368 temp_var = 1000000000 - temp_var;
369 if (comp.revision == QPNP_IADC_VER_3_1) {
370 sys_gain_coeff = (1000000 +
371 div64_s64(sys_gain_coeff, QPNP_COEFF_4));
372 temp_var = div64_s64(temp_var * sys_gain_coeff,
373 1000000000);
374 }
375 *result = div64_s64(*result, temp_var);
376 }
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700377 pr_debug("%lld compensated into %lld\n", old, *result);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700378
379 return 0;
380}
381
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700382int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc, int64_t *result)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700383{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700384 return qpnp_iadc_comp(result, iadc->iadc_comp, iadc->die_temp);
385}
386EXPORT_SYMBOL(qpnp_iadc_comp_result);
387
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700388static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700389{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700390 int rc = 0;
391
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700392 rc = qpnp_iadc_read_reg(iadc, QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700393 if (rc < 0) {
394 pr_err("qpnp adc comp id failed with %d\n", rc);
395 return rc;
396 }
397
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700398 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2,
399 &iadc->iadc_comp.revision);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700400 if (rc < 0) {
401 pr_err("qpnp adc revision read failed with %d\n", rc);
402 return rc;
403 }
404
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700405 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700406 &iadc->iadc_comp.sys_gain);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700407 if (rc < 0) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700408 pr_err("full scale read failed with %d\n", rc);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700409 return rc;
410 }
411
412 if (iadc->external_rsense)
413 iadc->iadc_comp.ext_rsense = true;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700414
415 pr_debug("fab id = %u, revision = %u, sys gain = %u, external_rsense = %d\n",
416 iadc->iadc_comp.id,
417 iadc->iadc_comp.revision,
418 iadc->iadc_comp.sys_gain,
419 iadc->iadc_comp.ext_rsense);
420 return rc;
421}
422
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700423static int32_t qpnp_iadc_configure(struct qpnp_iadc_chip *iadc,
424 enum qpnp_iadc_channels channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800425 uint16_t *raw_code, uint32_t mode_sel)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700426{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700427 u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
428 u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
429 int32_t rc = 0;
430
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700431 qpnp_iadc_ch_sel_reg = channel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700432
433 qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
434 QPNP_IADC_DEC_RATIO_SEL;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800435 if (iadc->iadc_mode_sel)
436 qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN);
437 else
438 qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
439
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700440 qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
441
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700442 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700443 if (rc) {
444 pr_err("qpnp adc read adc failed with %d\n", rc);
445 return rc;
446 }
447
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700448 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_ADC_CH_SEL_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700449 qpnp_iadc_ch_sel_reg);
450 if (rc) {
451 pr_err("qpnp adc read adc failed with %d\n", rc);
452 return rc;
453 }
454
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700455 rc = qpnp_iadc_write_reg(iadc, QPNP_ADC_DIG_PARAM,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700456 qpnp_iadc_dig_param_reg);
457 if (rc) {
458 pr_err("qpnp adc read adc failed with %d\n", rc);
459 return rc;
460 }
461
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700462 rc = qpnp_iadc_write_reg(iadc, QPNP_HW_SETTLE_DELAY,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700463 iadc->adc->amux_prop->hw_settle_time);
464 if (rc < 0) {
465 pr_err("qpnp adc configure error for hw settling time setup\n");
466 return rc;
467 }
468
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700469 rc = qpnp_iadc_write_reg(iadc, QPNP_FAST_AVG_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700470 iadc->adc->amux_prop->fast_avg_setup);
471 if (rc < 0) {
472 pr_err("qpnp adc fast averaging configure error\n");
473 return rc;
474 }
475
Siddartha Mohanadoss3f219c42013-04-02 11:01:28 -0700476 INIT_COMPLETION(iadc->adc->adc_rslt_completion);
477
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700478 rc = qpnp_iadc_enable(iadc, true);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700479 if (rc)
480 return rc;
481
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700482 rc = qpnp_iadc_write_reg(iadc, QPNP_CONV_REQ, qpnp_iadc_conv_req);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700483 if (rc) {
484 pr_err("qpnp adc read adc failed with %d\n", rc);
485 return rc;
486 }
487
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700488 rc = wait_for_completion_timeout(&iadc->adc->adc_rslt_completion,
489 QPNP_ADC_COMPLETION_TIMEOUT);
490 if (!rc) {
491 u8 status1 = 0;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700492 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700493 if (rc < 0)
494 return rc;
495 status1 &= (QPNP_STATUS1_REQ_STS | QPNP_STATUS1_EOC);
496 if (status1 == QPNP_STATUS1_EOC)
497 pr_debug("End of conversion status set\n");
498 else {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700499 rc = qpnp_iadc_status_debug(iadc);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800500 if (rc < 0) {
501 pr_err("status1 read failed with %d\n", rc);
502 return rc;
503 }
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700504 return -EINVAL;
505 }
506 }
507
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700508 rc = qpnp_iadc_read_conversion_result(iadc, raw_code);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700509 if (rc) {
510 pr_err("qpnp adc read adc failed with %d\n", rc);
511 return rc;
512 }
513
514 return 0;
515}
516
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700517#define IADC_CENTER 0xC000
518#define IADC_READING_RESOLUTION_N 542535
519#define IADC_READING_RESOLUTION_D 100000
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700520static int32_t qpnp_convert_raw_offset_voltage(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700521{
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700522 s64 numerator;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700523
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800524 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
525 pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
526 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
527 return -EINVAL;
528 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700529
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700530 numerator = iadc->adc->calib.offset_raw - IADC_CENTER;
531 numerator *= IADC_READING_RESOLUTION_N;
532 iadc->adc->calib.offset_uv = div_s64(numerator,
533 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700534
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700535 numerator = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
536 numerator *= IADC_READING_RESOLUTION_N;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700537
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700538 iadc->adc->calib.gain_uv = div_s64(numerator,
539 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700540
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700541 pr_debug("gain_uv:%d offset_uv:%d\n",
542 iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700543 return 0;
544}
545
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700546int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
547 bool batfet_closed)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700548{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700549 uint8_t rslt_lsb, rslt_msb;
550 int32_t rc = 0;
551 uint16_t raw_data;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800552 uint32_t mode_sel = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700553
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700554 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700555 return -EPROBE_DEFER;
556
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800557 mutex_lock(&iadc->adc->adc_lock);
558
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700559 rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800560 &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700561 if (rc < 0) {
562 pr_err("qpnp adc result read failed with %d\n", rc);
563 goto fail;
564 }
565
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700566 iadc->adc->calib.gain_raw = raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700567
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700568 /*
569 * there is a features in the BMS where if the batfet is opened
570 * the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
571 * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
572 * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
573 * internal rsense.
574 */
575 if (!batfet_closed || iadc->external_rsense) {
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700576 /* external offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700577 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800578 &raw_data, mode_sel);
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700579 if (rc < 0) {
580 pr_err("qpnp adc result read failed with %d\n", rc);
581 goto fail;
582 }
583 } else {
584 /* internal offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700585 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2,
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700586 &raw_data, mode_sel);
587 if (rc < 0) {
588 pr_err("qpnp adc result read failed with %d\n", rc);
589 goto fail;
590 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700591 }
592
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700593 iadc->adc->calib.offset_raw = raw_data;
594 if (rc < 0) {
595 pr_err("qpnp adc offset/gain calculation failed\n");
596 goto fail;
597 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700598
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700599 pr_debug("raw gain:0x%x, raw offset:0x%x\n",
600 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
601
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700602 rc = qpnp_convert_raw_offset_voltage(iadc);
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800603 if (rc < 0) {
604 pr_err("qpnp raw_voltage conversion failed\n");
605 goto fail;
606 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700607
608 rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
609 QPNP_BIT_SHIFT_8;
610 rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
611
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700612 pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
613
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700614 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700615 QPNP_IADC_SEC_ACCESS_DATA);
616 if (rc < 0) {
617 pr_err("qpnp iadc configure error for sec access\n");
618 goto fail;
619 }
620
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700621 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700622 rslt_msb);
623 if (rc < 0) {
624 pr_err("qpnp iadc configure error for MSB write\n");
625 goto fail;
626 }
627
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700628 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700629 QPNP_IADC_SEC_ACCESS_DATA);
630 if (rc < 0) {
631 pr_err("qpnp iadc configure error for sec access\n");
632 goto fail;
633 }
634
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700635 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700636 rslt_lsb);
637 if (rc < 0) {
638 pr_err("qpnp iadc configure error for LSB write\n");
639 goto fail;
640 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700641fail:
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800642 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700643 return rc;
644}
Siddartha Mohanadoss06673922013-03-27 11:14:19 -0700645EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700646
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700647static void qpnp_iadc_work(struct work_struct *work)
648{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700649 struct qpnp_iadc_chip *iadc = container_of(work,
650 struct qpnp_iadc_chip, iadc_work.work);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700651 int rc = 0;
652
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700653 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700654 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700655 if (rc)
656 pr_debug("periodic IADC calibration failed\n");
657 }
658
659 schedule_delayed_work(&iadc->iadc_work,
660 round_jiffies_relative(msecs_to_jiffies
661 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700662 return;
663}
664
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700665static int32_t qpnp_iadc_version_check(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700666{
667 uint8_t revision;
668 int rc;
669
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700670 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &revision);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700671 if (rc < 0) {
672 pr_err("qpnp adc result read failed with %d\n", rc);
673 return rc;
674 }
675
676 if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
677 pr_err("IADC Version not supported\n");
678 return -EINVAL;
679 }
680
681 return 0;
682}
683
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700684struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700685{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700686 struct qpnp_iadc_chip *iadc;
687 struct device_node *node = NULL;
688 char prop_name[QPNP_MAX_PROP_NAME_LEN];
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700689
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700690 snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-iadc", name);
691
692 node = of_parse_phandle(dev->of_node, prop_name, 0);
693 if (node == NULL)
694 return ERR_PTR(-ENODEV);
695
696 list_for_each_entry(iadc, &qpnp_iadc_device_list, list)
697 if (iadc->adc->spmi->dev.of_node == node)
698 return iadc;
699 return ERR_PTR(-EPROBE_DEFER);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700700}
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700701EXPORT_SYMBOL(qpnp_get_iadc);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700702
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700703int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700704{
705 uint8_t rslt_rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700706 int32_t rc = 0, sign_bit = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700707
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700708 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800709 return -EPROBE_DEFER;
710
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700711 if (iadc->external_rsense) {
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700712 *rsense = iadc->rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700713 return rc;
714 }
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700715
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700716 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700717 if (rc < 0) {
718 pr_err("qpnp adc rsense read failed with %d\n", rc);
719 return rc;
720 }
721
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700722 pr_debug("rsense:0%x\n", rslt_rsense);
723
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700724 if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
725 sign_bit = 1;
726
727 rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
728
729 if (sign_bit)
730 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
731 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
732 else
733 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
734 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
735
736 return rc;
737}
Xiaozhe Shi767fdb62013-01-10 15:09:08 -0800738EXPORT_SYMBOL(qpnp_iadc_get_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700739
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700740static int32_t qpnp_check_pmic_temp(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700741{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700742 struct qpnp_vadc_result result_pmic_therm;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700743 int64_t die_temp_offset;
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800744 int rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700745
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700746 rc = qpnp_vadc_read(iadc->vadc_dev, DIE_TEMP, &result_pmic_therm);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700747 if (rc < 0)
748 return rc;
749
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700750 die_temp_offset = result_pmic_therm.physical -
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700751 iadc->die_temp;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700752 if (die_temp_offset < 0)
753 die_temp_offset = -die_temp_offset;
754
755 if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700756 iadc->die_temp = result_pmic_therm.physical;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700757 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700758 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700759 if (rc)
760 pr_err("IADC calibration failed rc = %d\n", rc);
761 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700762 }
763
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800764 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700765}
766
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700767int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
768 enum qpnp_iadc_channels channel,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700769 struct qpnp_iadc_result *result)
770{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800771 int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700772 int32_t rsense_u_ohms = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700773 int64_t result_current;
774 uint16_t raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700775
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700776 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700777 return -EPROBE_DEFER;
778
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800779 if (!iadc->iadc_mode_sel) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700780 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800781 if (rc) {
782 pr_err("Error checking pmic therm temp\n");
783 return rc;
784 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700785 }
786
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700787 mutex_lock(&iadc->adc->adc_lock);
788
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700789 rc = qpnp_iadc_configure(iadc, channel, &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700790 if (rc < 0) {
791 pr_err("qpnp adc result read failed with %d\n", rc);
792 goto fail;
793 }
794
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700795 rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700796 pr_debug("current raw:0%x and rsense:%d\n",
797 raw_data, rsense_n_ohms);
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700798 rsense_u_ohms = rsense_n_ohms/1000;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700799 num = raw_data - iadc->adc->calib.offset_raw;
800 if (num < 0) {
801 sign = 1;
802 num = -num;
803 }
804
805 result->result_uv = (num * QPNP_ADC_GAIN_NV)/
806 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
807 result_current = result->result_uv;
808 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700809 /* Intentional fall through. Process the result w/o comp */
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700810 do_div(result_current, rsense_u_ohms);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700811
812 if (sign) {
813 result->result_uv = -result->result_uv;
814 result_current = -result_current;
815 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700816 rc = qpnp_iadc_comp_result(iadc, &result_current);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700817 if (rc < 0)
818 pr_err("Error during compensating the IADC\n");
819 rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700820
821 result->result_ua = (int32_t) result_current;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700822fail:
823 mutex_unlock(&iadc->adc->adc_lock);
824
825 return rc;
826}
827EXPORT_SYMBOL(qpnp_iadc_read);
828
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700829int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
830 struct qpnp_iadc_calib *result)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700831{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700832 int rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700833
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700834 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700835 return -EPROBE_DEFER;
836
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700837 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700838 if (rc) {
839 pr_err("Error checking pmic therm temp\n");
840 return rc;
841 }
842
843 mutex_lock(&iadc->adc->adc_lock);
844 result->gain_raw = iadc->adc->calib.gain_raw;
845 result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
846 result->gain_uv = iadc->adc->calib.gain_uv;
847 result->offset_raw = iadc->adc->calib.offset_raw;
848 result->ideal_offset_uv =
849 QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
850 result->offset_uv = iadc->adc->calib.offset_uv;
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700851 pr_debug("raw gain:0%x, raw offset:0%x\n",
852 result->gain_raw, result->offset_raw);
853 pr_debug("gain_uv:%d offset_uv:%d\n",
854 result->gain_uv, result->offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700855 mutex_unlock(&iadc->adc->adc_lock);
856
857 return 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700858}
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700859EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700860
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700861int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700862{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700863 iadc->skip_auto_calibrations = true;
864 return 0;
865}
866EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
867
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700868int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700869{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700870 iadc->skip_auto_calibrations = false;
871 return 0;
872}
873EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
874
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700875int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800876 enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
877 enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
878{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800879 int rc = 0;
880
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700881 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800882 return -EPROBE_DEFER;
883
884 mutex_lock(&iadc->iadc_vadc_lock);
885
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700886 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800887 if (rc) {
888 pr_err("PMIC die temp check failed\n");
889 goto fail;
890 }
891
892 iadc->iadc_mode_sel = true;
893
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700894 rc = qpnp_vadc_iadc_sync_request(iadc->vadc_dev, v_channel);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800895 if (rc) {
896 pr_err("Configuring VADC failed\n");
897 goto fail;
898 }
899
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700900 rc = qpnp_iadc_read(iadc, i_channel, i_result);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800901 if (rc)
902 pr_err("Configuring IADC failed\n");
903 /* Intentional fall through to release VADC */
904
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700905 rc = qpnp_vadc_iadc_sync_complete_request(iadc->vadc_dev, v_channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800906 v_result);
907 if (rc)
908 pr_err("Releasing VADC failed\n");
909fail:
910 iadc->iadc_mode_sel = false;
911
912 mutex_unlock(&iadc->iadc_vadc_lock);
913
914 return rc;
915}
916EXPORT_SYMBOL(qpnp_iadc_vadc_sync_read);
917
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700918static ssize_t qpnp_iadc_show(struct device *dev,
919 struct device_attribute *devattr, char *buf)
920{
921 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700922 struct qpnp_iadc_chip *iadc = dev_get_drvdata(dev);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700923 struct qpnp_iadc_result result;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700924 int rc = -1;
925
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700926 rc = qpnp_iadc_read(iadc, attr->index, &result);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700927
928 if (rc)
929 return 0;
930
931 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700932 "Result:%d\n", result.result_ua);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700933}
934
935static struct sensor_device_attribute qpnp_adc_attr =
936 SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
937
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700938static int32_t qpnp_iadc_init_hwmon(struct qpnp_iadc_chip *iadc,
939 struct spmi_device *spmi)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700940{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700941 struct device_node *child;
942 struct device_node *node = spmi->dev.of_node;
943 int rc = 0, i = 0, channel;
944
945 for_each_child_of_node(node, child) {
946 channel = iadc->adc->adc_channels[i].channel_num;
947 qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
948 qpnp_adc_attr.dev_attr.attr.name =
949 iadc->adc->adc_channels[i].name;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700950 memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
951 sizeof(qpnp_adc_attr));
Stephen Boyd8a5c4e42012-10-30 11:07:22 -0700952 sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700953 rc = device_create_file(&spmi->dev,
954 &iadc->sens_attr[i].dev_attr);
955 if (rc) {
956 dev_err(&spmi->dev,
957 "device_create_file failed for dev %s\n",
958 iadc->adc->adc_channels[i].name);
959 goto hwmon_err_sens;
960 }
961 i++;
962 }
963
964 return 0;
965hwmon_err_sens:
966 pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
967 return rc;
968}
969
970static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
971{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700972 struct qpnp_iadc_chip *iadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700973 struct qpnp_adc_drv *adc_qpnp;
974 struct device_node *node = spmi->dev.of_node;
975 struct device_node *child;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700976 int rc, count_adc_channel_list = 0, i = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700977
978 for_each_child_of_node(node, child)
979 count_adc_channel_list++;
980
981 if (!count_adc_channel_list) {
982 pr_err("No channel listing\n");
983 return -EINVAL;
984 }
985
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700986 iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_chip) +
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700987 (sizeof(struct sensor_device_attribute) *
988 count_adc_channel_list), GFP_KERNEL);
989 if (!iadc) {
990 dev_err(&spmi->dev, "Unable to allocate memory\n");
991 return -ENOMEM;
992 }
993
994 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
995 GFP_KERNEL);
996 if (!adc_qpnp) {
997 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800998 rc = -ENOMEM;
999 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001000 }
1001
1002 iadc->adc = adc_qpnp;
1003
1004 rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
1005 if (rc) {
1006 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001007 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001008 }
1009
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001010 iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
1011 if (IS_ERR(iadc->vadc_dev)) {
1012 rc = PTR_ERR(iadc->vadc_dev);
1013 if (rc != -EPROBE_DEFER)
1014 pr_err("vadc property missing, rc=%d\n", rc);
1015 goto fail;
1016 }
1017
Stephen Boydbeab4502013-04-25 10:18:17 -07001018 mutex_init(&iadc->adc->adc_lock);
1019
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001020 rc = of_property_read_u32(node, "qcom,rsense",
1021 &iadc->rsense);
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -07001022 if (rc)
1023 pr_debug("Defaulting to internal rsense\n");
1024 else {
1025 pr_debug("Use external rsense\n");
1026 iadc->external_rsense = true;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001027 }
1028
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001029 rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001030 qpnp_iadc_isr,
1031 IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
1032 if (rc) {
1033 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001034 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001035 } else
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001036 enable_irq_wake(iadc->adc->adc_irq_eoc);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001037
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001038 rc = qpnp_iadc_init_hwmon(iadc, spmi);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001039 if (rc) {
1040 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001041 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001042 }
1043 iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
1044
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001045 rc = qpnp_iadc_version_check(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001046 if (rc) {
1047 dev_err(&spmi->dev, "IADC version not supported\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001048 goto fail;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001049 }
1050
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001051 mutex_init(&iadc->iadc_vadc_lock);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001052 INIT_WORK(&iadc->trigger_completion_work, qpnp_iadc_trigger_completion);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001053 INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001054 rc = qpnp_iadc_comp_info(iadc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001055 if (rc) {
1056 dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
1057 goto fail;
1058 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001059
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001060 dev_set_drvdata(&spmi->dev, iadc);
1061 list_add(&iadc->list, &qpnp_iadc_device_list);
1062 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001063 if (rc)
1064 dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001065
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001066 schedule_delayed_work(&iadc->iadc_work,
1067 round_jiffies_relative(msecs_to_jiffies
1068 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001069 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001070fail:
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001071 for_each_child_of_node(node, child) {
1072 device_remove_file(&spmi->dev,
1073 &iadc->sens_attr[i].dev_attr);
1074 i++;
1075 }
1076 hwmon_device_unregister(iadc->iadc_hwmon);
1077
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001078 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001079}
1080
1081static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
1082{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001083 struct qpnp_iadc_chip *iadc = dev_get_drvdata(&spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001084 struct device_node *node = spmi->dev.of_node;
1085 struct device_node *child;
1086 int i = 0;
1087
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001088 cancel_delayed_work(&iadc->iadc_work);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001089 mutex_destroy(&iadc->iadc_vadc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001090 for_each_child_of_node(node, child) {
1091 device_remove_file(&spmi->dev,
1092 &iadc->sens_attr[i].dev_attr);
1093 i++;
1094 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001095 hwmon_device_unregister(iadc->iadc_hwmon);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001096 dev_set_drvdata(&spmi->dev, NULL);
1097
1098 return 0;
1099}
1100
1101static const struct of_device_id qpnp_iadc_match_table[] = {
1102 { .compatible = "qcom,qpnp-iadc",
1103 },
1104 {}
1105};
1106
1107static struct spmi_driver qpnp_iadc_driver = {
1108 .driver = {
1109 .name = "qcom,qpnp-iadc",
1110 .of_match_table = qpnp_iadc_match_table,
1111 },
1112 .probe = qpnp_iadc_probe,
1113 .remove = qpnp_iadc_remove,
1114};
1115
1116static int __init qpnp_iadc_init(void)
1117{
1118 return spmi_driver_register(&qpnp_iadc_driver);
1119}
1120module_init(qpnp_iadc_init);
1121
1122static void __exit qpnp_iadc_exit(void)
1123{
1124 spmi_driver_unregister(&qpnp_iadc_driver);
1125}
1126module_exit(qpnp_iadc_exit);
1127
1128MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
1129MODULE_LICENSE("GPL v2");