blob: 490a5cec7c3601f8608a9d6442edcf8faad57c7a [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>
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -070034#include <linux/wakelock.h>
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070035
36/* QPNP IADC register definition */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070037#define QPNP_IADC_REVISION1 0x0
38#define QPNP_IADC_REVISION2 0x1
39#define QPNP_IADC_REVISION3 0x2
40#define QPNP_IADC_REVISION4 0x3
41#define QPNP_IADC_PERPH_TYPE 0x4
42#define QPNP_IADC_PERH_SUBTYPE 0x5
43
44#define QPNP_IADC_SUPPORTED_REVISION2 1
45
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070046#define QPNP_STATUS1 0x8
47#define QPNP_STATUS1_OP_MODE 4
48#define QPNP_STATUS1_MULTI_MEAS_EN BIT(3)
49#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
50#define QPNP_STATUS1_REQ_STS BIT(1)
51#define QPNP_STATUS1_EOC BIT(0)
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -070052#define QPNP_STATUS1_REQ_STS_EOC_MASK 0x3
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070053#define QPNP_STATUS2 0x9
54#define QPNP_STATUS2_CONV_SEQ_STATE_SHIFT 4
55#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
56#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
57#define QPNP_CONV_TIMEOUT_ERR 2
58
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070059#define QPNP_IADC_MODE_CTL 0x40
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070060#define QPNP_OP_MODE_SHIFT 4
61#define QPNP_USE_BMS_DATA BIT(4)
62#define QPNP_VADC_SYNCH_EN BIT(2)
63#define QPNP_OFFSET_RMV_EN BIT(1)
64#define QPNP_ADC_TRIM_EN BIT(0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070065#define QPNP_IADC_EN_CTL1 0x46
66#define QPNP_IADC_ADC_EN BIT(7)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070067#define QPNP_ADC_CH_SEL_CTL 0x48
68#define QPNP_ADC_DIG_PARAM 0x50
69#define QPNP_ADC_CLK_SEL_MASK 0x3
70#define QPNP_ADC_DEC_RATIO_SEL_MASK 0xc
71#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 2
72
73#define QPNP_HW_SETTLE_DELAY 0x51
74#define QPNP_CONV_REQ 0x52
75#define QPNP_CONV_REQ_SET BIT(7)
76#define QPNP_CONV_SEQ_CTL 0x54
77#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
78#define QPNP_CONV_SEQ_TRIG_CTL 0x55
79#define QPNP_FAST_AVG_CTL 0x5a
80
81#define QPNP_M0_LOW_THR_LSB 0x5c
82#define QPNP_M0_LOW_THR_MSB 0x5d
83#define QPNP_M0_HIGH_THR_LSB 0x5e
84#define QPNP_M0_HIGH_THR_MSB 0x5f
85#define QPNP_M1_LOW_THR_LSB 0x69
86#define QPNP_M1_LOW_THR_MSB 0x6a
87#define QPNP_M1_HIGH_THR_LSB 0x6b
88#define QPNP_M1_HIGH_THR_MSB 0x6c
89
90#define QPNP_DATA0 0x60
91#define QPNP_DATA1 0x61
92#define QPNP_CONV_TIMEOUT_ERR 2
93
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -070094#define QPNP_IADC_SEC_ACCESS 0xD0
95#define QPNP_IADC_SEC_ACCESS_DATA 0xA5
96#define QPNP_IADC_MSB_OFFSET 0xF2
97#define QPNP_IADC_LSB_OFFSET 0xF3
98#define QPNP_IADC_NOMINAL_RSENSE 0xF4
99#define QPNP_IADC_ATE_GAIN_CALIB_OFFSET 0xF5
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700100#define QPNP_INT_TEST_VAL 0xE1
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700101
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700102#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
103#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
104
105#define QPNP_IADC_ADC_DIG_PARAM 0x50
106#define QPNP_IADC_CLK_SEL_SHIFT 1
107#define QPNP_IADC_DEC_RATIO_SEL 3
108
109#define QPNP_IADC_CONV_REQUEST 0x52
110#define QPNP_IADC_CONV_REQ BIT(7)
111
112#define QPNP_IADC_DATA0 0x60
113#define QPNP_IADC_DATA1 0x61
114
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700115#define QPNP_ADC_CONV_TIME_MIN 2000
116#define QPNP_ADC_CONV_TIME_MAX 2100
117#define QPNP_ADC_ERR_COUNT 20
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700118
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700119#define QPNP_ADC_GAIN_NV 17857
120#define QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL 0
121#define QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR 10000000
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700122#define QPNP_IADC_NANO_VOLTS_FACTOR 1000000
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700123#define QPNP_IADC_CALIB_SECONDS 300000
124#define QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT 15625
125#define QPNP_IADC_DIE_TEMP_CALIB_OFFSET 5000
126
127#define QPNP_RAW_CODE_16_BIT_MSB_MASK 0xff00
128#define QPNP_RAW_CODE_16_BIT_LSB_MASK 0xff
129#define QPNP_BIT_SHIFT_8 8
130#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700131#define QPNP_ADC_COMPLETION_TIMEOUT HZ
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700132
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700133struct qpnp_iadc_comp {
134 bool ext_rsense;
135 u8 id;
136 u8 sys_gain;
137 u8 revision;
138};
139
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700140struct qpnp_iadc_chip {
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700141 struct device *dev;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700142 struct qpnp_adc_drv *adc;
143 int32_t rsense;
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700144 bool external_rsense;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700145 struct device *iadc_hwmon;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700146 struct list_head list;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700147 int64_t die_temp;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700148 struct delayed_work iadc_work;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800149 struct mutex iadc_vadc_lock;
150 bool iadc_mode_sel;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700151 struct qpnp_iadc_comp iadc_comp;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700152 struct qpnp_vadc_chip *vadc_dev;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700153 struct work_struct trigger_completion_work;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700154 bool skip_auto_calibrations;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700155 bool iadc_poll_eoc;
156 struct sensor_device_attribute sens_attr[0];
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700157};
158
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700159LIST_HEAD(qpnp_iadc_device_list);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700160
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700161static int32_t qpnp_iadc_read_reg(struct qpnp_iadc_chip *iadc,
162 uint32_t reg, u8 *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700163{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700164 int rc;
165
166 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700167 (iadc->adc->offset + reg), data, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700168 if (rc < 0) {
169 pr_err("qpnp iadc read reg %d failed with %d\n", reg, rc);
170 return rc;
171 }
172
173 return 0;
174}
175
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700176static int32_t qpnp_iadc_write_reg(struct qpnp_iadc_chip *iadc,
177 uint32_t reg, u8 data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700178{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700179 int rc;
180 u8 *buf;
181
182 buf = &data;
183 rc = spmi_ext_register_writel(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700184 (iadc->adc->offset + reg), buf, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700185 if (rc < 0) {
186 pr_err("qpnp iadc write reg %d failed with %d\n", reg, rc);
187 return rc;
188 }
189
190 return 0;
191}
192
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700193static int qpnp_iadc_is_valid(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800194{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700195 struct qpnp_iadc_chip *iadc_chip = NULL;
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800196
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700197 list_for_each_entry(iadc_chip, &qpnp_iadc_device_list, list)
198 if (iadc == iadc_chip)
199 return 0;
200
201 return -EINVAL;
202}
203
204static void qpnp_iadc_trigger_completion(struct work_struct *work)
205{
206 struct qpnp_iadc_chip *iadc = container_of(work,
207 struct qpnp_iadc_chip, trigger_completion_work);
208
209 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800210 return;
211
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800212 complete(&iadc->adc->adc_rslt_completion);
213
214 return;
215}
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800216
217static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
218{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700219 struct qpnp_iadc_chip *iadc = dev_id;
220
221 schedule_work(&iadc->trigger_completion_work);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800222
223 return IRQ_HANDLED;
224}
225
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700226static int32_t qpnp_iadc_enable(struct qpnp_iadc_chip *dev, bool state)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800227{
228 int rc = 0;
229 u8 data = 0;
230
231 data = QPNP_IADC_ADC_EN;
232 if (state) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700233 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800234 data);
235 if (rc < 0) {
236 pr_err("IADC enable failed\n");
237 return rc;
238 }
239 } else {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700240 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800241 (~data & QPNP_IADC_ADC_EN));
242 if (rc < 0) {
243 pr_err("IADC disable failed\n");
244 return rc;
245 }
246 }
247
248 return 0;
249}
250
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700251static int32_t qpnp_iadc_status_debug(struct qpnp_iadc_chip *dev)
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800252{
253 int rc = 0;
254 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
255
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700256 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_MODE_CTL, &mode);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800257 if (rc < 0) {
258 pr_err("mode ctl register read failed with %d\n", rc);
259 return rc;
260 }
261
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700262 rc = qpnp_iadc_read_reg(dev, QPNP_ADC_DIG_PARAM, &dig);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800263 if (rc < 0) {
264 pr_err("digital param read failed with %d\n", rc);
265 return rc;
266 }
267
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700268 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_ADC_CH_SEL_CTL, &chan);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800269 if (rc < 0) {
270 pr_err("channel read failed with %d\n", rc);
271 return rc;
272 }
273
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700274 rc = qpnp_iadc_read_reg(dev, QPNP_STATUS1, &status1);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800275 if (rc < 0) {
276 pr_err("status1 read failed with %d\n", rc);
277 return rc;
278 }
279
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700280 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_EN_CTL1, &en);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800281 if (rc < 0) {
282 pr_err("en read failed with %d\n", rc);
283 return rc;
284 }
285
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700286 pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800287 status1, dig, chan, mode, en);
288
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700289 rc = qpnp_iadc_enable(dev, false);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800290 if (rc < 0) {
291 pr_err("IADC disable failed with %d\n", rc);
292 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700293 }
294
295 return 0;
296}
297
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700298static int32_t qpnp_iadc_read_conversion_result(struct qpnp_iadc_chip *iadc,
299 int16_t *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700300{
301 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700302 uint16_t rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700303 int32_t rc;
304
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700305 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA0, &rslt_lsb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700306 if (rc < 0) {
307 pr_err("qpnp adc result read failed with %d\n", rc);
308 return rc;
309 }
310
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700311 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA1, &rslt_msb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700312 if (rc < 0) {
313 pr_err("qpnp adc result read failed with %d\n", rc);
314 return rc;
315 }
316
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700317 rslt = (rslt_msb << 8) | rslt_lsb;
318 *data = rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700319
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700320 rc = qpnp_iadc_enable(iadc, false);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700321 if (rc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700322 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700323
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700324 return 0;
325}
326
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700327static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_comp comp,
328 int64_t die_temp)
329{
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700330 int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0, old;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700331
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700332 old = *result;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700333 *result = *result * 1000000;
334
335 if (comp.revision == QPNP_IADC_VER_3_1) {
336 /* revision 3.1 */
337 if (comp.sys_gain > 127)
338 sys_gain_coeff = -QPNP_COEFF_6 * (comp.sys_gain - 128);
339 else
340 sys_gain_coeff = QPNP_COEFF_6 * comp.sys_gain;
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700341 } else if (comp.revision != QPNP_IADC_VER_3_0) {
342 /* unsupported revision, do not compensate */
343 *result = old;
344 return 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700345 }
346
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700347 if (!comp.ext_rsense) {
348 /* internal rsense */
349 switch (comp.id) {
350 case COMP_ID_TSMC:
351 temp_var = ((QPNP_COEFF_2 * die_temp) -
352 QPNP_COEFF_3_TYPEB);
353 break;
354 case COMP_ID_GF:
355 default:
356 temp_var = ((QPNP_COEFF_2 * die_temp) -
357 QPNP_COEFF_3_TYPEA);
358 break;
359 }
360 temp_var = div64_s64(temp_var, QPNP_COEFF_4);
361 if (comp.revision == QPNP_IADC_VER_3_0)
362 temp_var = QPNP_COEFF_1 * (1000000 - temp_var);
363 else if (comp.revision == QPNP_IADC_VER_3_1)
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700364 temp_var = 1000000 * (1000000 - temp_var);
365 *result = div64_s64(*result * 1000000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700366 }
367
368 sign_coeff = *result < 0 ? QPNP_COEFF_7 : QPNP_COEFF_5;
369 if (comp.ext_rsense) {
370 /* external rsense and current charging */
371 temp_var = div64_s64((-sign_coeff * die_temp) + QPNP_COEFF_8,
372 QPNP_COEFF_4);
373 temp_var = 1000000000 - temp_var;
374 if (comp.revision == QPNP_IADC_VER_3_1) {
375 sys_gain_coeff = (1000000 +
376 div64_s64(sys_gain_coeff, QPNP_COEFF_4));
377 temp_var = div64_s64(temp_var * sys_gain_coeff,
378 1000000000);
379 }
380 *result = div64_s64(*result, temp_var);
381 }
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700382 pr_debug("%lld compensated into %lld\n", old, *result);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700383
384 return 0;
385}
386
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700387int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc, int64_t *result)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700388{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700389 return qpnp_iadc_comp(result, iadc->iadc_comp, iadc->die_temp);
390}
391EXPORT_SYMBOL(qpnp_iadc_comp_result);
392
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700393static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700394{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700395 int rc = 0;
396
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700397 rc = qpnp_iadc_read_reg(iadc, QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700398 if (rc < 0) {
399 pr_err("qpnp adc comp id failed with %d\n", rc);
400 return rc;
401 }
402
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700403 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2,
404 &iadc->iadc_comp.revision);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700405 if (rc < 0) {
406 pr_err("qpnp adc revision read failed with %d\n", rc);
407 return rc;
408 }
409
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700410 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700411 &iadc->iadc_comp.sys_gain);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700412 if (rc < 0) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700413 pr_err("full scale read failed with %d\n", rc);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700414 return rc;
415 }
416
417 if (iadc->external_rsense)
418 iadc->iadc_comp.ext_rsense = true;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700419
420 pr_debug("fab id = %u, revision = %u, sys gain = %u, external_rsense = %d\n",
421 iadc->iadc_comp.id,
422 iadc->iadc_comp.revision,
423 iadc->iadc_comp.sys_gain,
424 iadc->iadc_comp.ext_rsense);
425 return rc;
426}
427
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700428static int32_t qpnp_iadc_configure(struct qpnp_iadc_chip *iadc,
429 enum qpnp_iadc_channels channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800430 uint16_t *raw_code, uint32_t mode_sel)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700431{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700432 u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
433 u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700434 u8 status1 = 0;
435 uint32_t count = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700436 int32_t rc = 0;
437
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700438 qpnp_iadc_ch_sel_reg = channel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700439
440 qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
441 QPNP_IADC_DEC_RATIO_SEL;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800442 if (iadc->iadc_mode_sel)
443 qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN);
444 else
445 qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
446
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700447 qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
448
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700449 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700450 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_IADC_ADC_CH_SEL_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700456 qpnp_iadc_ch_sel_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_ADC_DIG_PARAM,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700463 qpnp_iadc_dig_param_reg);
464 if (rc) {
465 pr_err("qpnp adc read adc failed with %d\n", rc);
466 return rc;
467 }
468
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700469 rc = qpnp_iadc_write_reg(iadc, QPNP_HW_SETTLE_DELAY,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700470 iadc->adc->amux_prop->hw_settle_time);
471 if (rc < 0) {
472 pr_err("qpnp adc configure error for hw settling time setup\n");
473 return rc;
474 }
475
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700476 rc = qpnp_iadc_write_reg(iadc, QPNP_FAST_AVG_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700477 iadc->adc->amux_prop->fast_avg_setup);
478 if (rc < 0) {
479 pr_err("qpnp adc fast averaging configure error\n");
480 return rc;
481 }
482
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700483 if (!iadc->iadc_poll_eoc)
484 INIT_COMPLETION(iadc->adc->adc_rslt_completion);
Siddartha Mohanadoss3f219c42013-04-02 11:01:28 -0700485
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700486 rc = qpnp_iadc_enable(iadc, true);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700487 if (rc)
488 return rc;
489
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700490 rc = qpnp_iadc_write_reg(iadc, QPNP_CONV_REQ, qpnp_iadc_conv_req);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700491 if (rc) {
492 pr_err("qpnp adc read adc failed with %d\n", rc);
493 return rc;
494 }
495
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700496 if (iadc->iadc_poll_eoc) {
497 while (status1 != QPNP_STATUS1_EOC) {
498 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
499 if (rc < 0)
500 return rc;
501 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
502 usleep_range(QPNP_ADC_CONV_TIME_MIN,
503 QPNP_ADC_CONV_TIME_MAX);
504 count++;
505 if (count > QPNP_ADC_ERR_COUNT) {
506 pr_err("retry error exceeded\n");
507 rc = qpnp_iadc_status_debug(iadc);
508 if (rc < 0)
509 pr_err("IADC status debug failed\n");
510 rc = -EINVAL;
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800511 return rc;
512 }
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700513 }
514 } else {
515 rc = wait_for_completion_timeout(
516 &iadc->adc->adc_rslt_completion,
517 QPNP_ADC_COMPLETION_TIMEOUT);
518 if (!rc) {
519 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
520 if (rc < 0)
521 return rc;
522 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
523 if (status1 == QPNP_STATUS1_EOC)
524 pr_debug("End of conversion status set\n");
525 else {
526 rc = qpnp_iadc_status_debug(iadc);
527 if (rc < 0) {
528 pr_err("status debug failed %d\n", rc);
529 return rc;
530 }
531 return -EINVAL;
532 }
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700533 }
534 }
535
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700536 rc = qpnp_iadc_read_conversion_result(iadc, raw_code);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700537 if (rc) {
538 pr_err("qpnp adc read adc failed with %d\n", rc);
539 return rc;
540 }
541
542 return 0;
543}
544
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700545#define IADC_CENTER 0xC000
546#define IADC_READING_RESOLUTION_N 542535
547#define IADC_READING_RESOLUTION_D 100000
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700548static int32_t qpnp_convert_raw_offset_voltage(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700549{
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700550 s64 numerator;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700551
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800552 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
553 pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
554 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
555 return -EINVAL;
556 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700557
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700558 numerator = iadc->adc->calib.offset_raw - IADC_CENTER;
559 numerator *= IADC_READING_RESOLUTION_N;
560 iadc->adc->calib.offset_uv = div_s64(numerator,
561 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700562
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700563 numerator = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
564 numerator *= IADC_READING_RESOLUTION_N;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700565
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700566 iadc->adc->calib.gain_uv = div_s64(numerator,
567 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700568
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700569 pr_debug("gain_uv:%d offset_uv:%d\n",
570 iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700571 return 0;
572}
573
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700574int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
575 bool batfet_closed)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700576{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700577 uint8_t rslt_lsb, rslt_msb;
578 int32_t rc = 0;
579 uint16_t raw_data;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800580 uint32_t mode_sel = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700581
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700582 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700583 return -EPROBE_DEFER;
584
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800585 mutex_lock(&iadc->adc->adc_lock);
586
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700587 if (iadc->iadc_poll_eoc) {
588 pr_debug("acquiring iadc eoc wakelock\n");
589 pm_stay_awake(iadc->dev);
590 }
591
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700592 rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800593 &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700594 if (rc < 0) {
595 pr_err("qpnp adc result read failed with %d\n", rc);
596 goto fail;
597 }
598
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700599 iadc->adc->calib.gain_raw = raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700600
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700601 /*
602 * there is a features in the BMS where if the batfet is opened
603 * the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
604 * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
605 * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
606 * internal rsense.
607 */
608 if (!batfet_closed || iadc->external_rsense) {
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700609 /* external offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700610 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800611 &raw_data, mode_sel);
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700612 if (rc < 0) {
613 pr_err("qpnp adc result read failed with %d\n", rc);
614 goto fail;
615 }
616 } else {
617 /* internal offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700618 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2,
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700619 &raw_data, mode_sel);
620 if (rc < 0) {
621 pr_err("qpnp adc result read failed with %d\n", rc);
622 goto fail;
623 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700624 }
625
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700626 iadc->adc->calib.offset_raw = raw_data;
627 if (rc < 0) {
628 pr_err("qpnp adc offset/gain calculation failed\n");
629 goto fail;
630 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700631
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700632 pr_debug("raw gain:0x%x, raw offset:0x%x\n",
633 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
634
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700635 rc = qpnp_convert_raw_offset_voltage(iadc);
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800636 if (rc < 0) {
637 pr_err("qpnp raw_voltage conversion failed\n");
638 goto fail;
639 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700640
641 rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
642 QPNP_BIT_SHIFT_8;
643 rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
644
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700645 pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
646
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700647 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700648 QPNP_IADC_SEC_ACCESS_DATA);
649 if (rc < 0) {
650 pr_err("qpnp iadc configure error for sec access\n");
651 goto fail;
652 }
653
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700654 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700655 rslt_msb);
656 if (rc < 0) {
657 pr_err("qpnp iadc configure error for MSB write\n");
658 goto fail;
659 }
660
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700661 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700662 QPNP_IADC_SEC_ACCESS_DATA);
663 if (rc < 0) {
664 pr_err("qpnp iadc configure error for sec access\n");
665 goto fail;
666 }
667
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700668 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700669 rslt_lsb);
670 if (rc < 0) {
671 pr_err("qpnp iadc configure error for LSB write\n");
672 goto fail;
673 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700674fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700675 if (iadc->iadc_poll_eoc) {
676 pr_debug("releasing iadc eoc wakelock\n");
677 pm_relax(iadc->dev);
678 }
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800679 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700680 return rc;
681}
Siddartha Mohanadoss06673922013-03-27 11:14:19 -0700682EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700683
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700684static void qpnp_iadc_work(struct work_struct *work)
685{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700686 struct qpnp_iadc_chip *iadc = container_of(work,
687 struct qpnp_iadc_chip, iadc_work.work);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700688 int rc = 0;
689
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700690 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700691 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700692 if (rc)
693 pr_debug("periodic IADC calibration failed\n");
694 }
695
696 schedule_delayed_work(&iadc->iadc_work,
697 round_jiffies_relative(msecs_to_jiffies
698 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700699 return;
700}
701
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700702static int32_t qpnp_iadc_version_check(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700703{
704 uint8_t revision;
705 int rc;
706
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700707 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &revision);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700708 if (rc < 0) {
709 pr_err("qpnp adc result read failed with %d\n", rc);
710 return rc;
711 }
712
713 if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
714 pr_err("IADC Version not supported\n");
715 return -EINVAL;
716 }
717
718 return 0;
719}
720
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700721struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700722{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700723 struct qpnp_iadc_chip *iadc;
724 struct device_node *node = NULL;
725 char prop_name[QPNP_MAX_PROP_NAME_LEN];
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700726
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700727 snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-iadc", name);
728
729 node = of_parse_phandle(dev->of_node, prop_name, 0);
730 if (node == NULL)
731 return ERR_PTR(-ENODEV);
732
733 list_for_each_entry(iadc, &qpnp_iadc_device_list, list)
734 if (iadc->adc->spmi->dev.of_node == node)
735 return iadc;
736 return ERR_PTR(-EPROBE_DEFER);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700737}
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700738EXPORT_SYMBOL(qpnp_get_iadc);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700739
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700740int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700741{
742 uint8_t rslt_rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700743 int32_t rc = 0, sign_bit = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700744
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700745 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800746 return -EPROBE_DEFER;
747
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700748 if (iadc->external_rsense) {
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700749 *rsense = iadc->rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700750 return rc;
751 }
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700752
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700753 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700754 if (rc < 0) {
755 pr_err("qpnp adc rsense read failed with %d\n", rc);
756 return rc;
757 }
758
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700759 pr_debug("rsense:0%x\n", rslt_rsense);
760
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700761 if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
762 sign_bit = 1;
763
764 rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
765
766 if (sign_bit)
767 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
768 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
769 else
770 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
771 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
772
773 return rc;
774}
Xiaozhe Shi767fdb62013-01-10 15:09:08 -0800775EXPORT_SYMBOL(qpnp_iadc_get_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700776
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700777static int32_t qpnp_check_pmic_temp(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700778{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700779 struct qpnp_vadc_result result_pmic_therm;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700780 int64_t die_temp_offset;
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800781 int rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700782
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700783 rc = qpnp_vadc_read(iadc->vadc_dev, DIE_TEMP, &result_pmic_therm);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700784 if (rc < 0)
785 return rc;
786
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700787 die_temp_offset = result_pmic_therm.physical -
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700788 iadc->die_temp;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700789 if (die_temp_offset < 0)
790 die_temp_offset = -die_temp_offset;
791
792 if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700793 iadc->die_temp = result_pmic_therm.physical;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700794 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700795 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700796 if (rc)
797 pr_err("IADC calibration failed rc = %d\n", rc);
798 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700799 }
800
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800801 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700802}
803
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700804int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
805 enum qpnp_iadc_channels channel,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700806 struct qpnp_iadc_result *result)
807{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800808 int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700809 int32_t rsense_u_ohms = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700810 int64_t result_current;
811 uint16_t raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700812
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700813 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700814 return -EPROBE_DEFER;
815
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800816 if (!iadc->iadc_mode_sel) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700817 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800818 if (rc) {
819 pr_err("Error checking pmic therm temp\n");
820 return rc;
821 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700822 }
823
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700824 mutex_lock(&iadc->adc->adc_lock);
825
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700826 if (iadc->iadc_poll_eoc) {
827 pr_debug("acquiring iadc eoc wakelock\n");
828 pm_stay_awake(iadc->dev);
829 }
830
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700831 rc = qpnp_iadc_configure(iadc, channel, &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700832 if (rc < 0) {
833 pr_err("qpnp adc result read failed with %d\n", rc);
834 goto fail;
835 }
836
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700837 rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700838 pr_debug("current raw:0%x and rsense:%d\n",
839 raw_data, rsense_n_ohms);
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700840 rsense_u_ohms = rsense_n_ohms/1000;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700841 num = raw_data - iadc->adc->calib.offset_raw;
842 if (num < 0) {
843 sign = 1;
844 num = -num;
845 }
846
847 result->result_uv = (num * QPNP_ADC_GAIN_NV)/
848 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
849 result_current = result->result_uv;
850 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700851 /* Intentional fall through. Process the result w/o comp */
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700852 do_div(result_current, rsense_u_ohms);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700853
854 if (sign) {
855 result->result_uv = -result->result_uv;
856 result_current = -result_current;
857 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700858 rc = qpnp_iadc_comp_result(iadc, &result_current);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700859 if (rc < 0)
860 pr_err("Error during compensating the IADC\n");
861 rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700862
863 result->result_ua = (int32_t) result_current;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700864fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700865 if (iadc->iadc_poll_eoc) {
866 pr_debug("releasing iadc eoc wakelock\n");
867 pm_relax(iadc->dev);
868 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700869 mutex_unlock(&iadc->adc->adc_lock);
870
871 return rc;
872}
873EXPORT_SYMBOL(qpnp_iadc_read);
874
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700875int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
876 struct qpnp_iadc_calib *result)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700877{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700878 int rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700879
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700880 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700881 return -EPROBE_DEFER;
882
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700883 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700884 if (rc) {
885 pr_err("Error checking pmic therm temp\n");
886 return rc;
887 }
888
889 mutex_lock(&iadc->adc->adc_lock);
890 result->gain_raw = iadc->adc->calib.gain_raw;
891 result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
892 result->gain_uv = iadc->adc->calib.gain_uv;
893 result->offset_raw = iadc->adc->calib.offset_raw;
894 result->ideal_offset_uv =
895 QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
896 result->offset_uv = iadc->adc->calib.offset_uv;
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700897 pr_debug("raw gain:0%x, raw offset:0%x\n",
898 result->gain_raw, result->offset_raw);
899 pr_debug("gain_uv:%d offset_uv:%d\n",
900 result->gain_uv, result->offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700901 mutex_unlock(&iadc->adc->adc_lock);
902
903 return 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700904}
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700905EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700906
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700907int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700908{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700909 iadc->skip_auto_calibrations = true;
910 return 0;
911}
912EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
913
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700914int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700915{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700916 iadc->skip_auto_calibrations = false;
917 return 0;
918}
919EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
920
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700921int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800922 enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
923 enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
924{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800925 int rc = 0;
926
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700927 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800928 return -EPROBE_DEFER;
929
930 mutex_lock(&iadc->iadc_vadc_lock);
931
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700932 if (iadc->iadc_poll_eoc) {
933 pr_debug("acquiring iadc eoc wakelock\n");
934 pm_stay_awake(iadc->dev);
935 }
936
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700937 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800938 if (rc) {
939 pr_err("PMIC die temp check failed\n");
940 goto fail;
941 }
942
943 iadc->iadc_mode_sel = true;
944
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700945 rc = qpnp_vadc_iadc_sync_request(iadc->vadc_dev, v_channel);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800946 if (rc) {
947 pr_err("Configuring VADC failed\n");
948 goto fail;
949 }
950
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700951 rc = qpnp_iadc_read(iadc, i_channel, i_result);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800952 if (rc)
953 pr_err("Configuring IADC failed\n");
954 /* Intentional fall through to release VADC */
955
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700956 rc = qpnp_vadc_iadc_sync_complete_request(iadc->vadc_dev, v_channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800957 v_result);
958 if (rc)
959 pr_err("Releasing VADC failed\n");
960fail:
961 iadc->iadc_mode_sel = false;
962
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700963 if (iadc->iadc_poll_eoc) {
964 pr_debug("releasing iadc eoc wakelock\n");
965 pm_relax(iadc->dev);
966 }
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800967 mutex_unlock(&iadc->iadc_vadc_lock);
968
969 return rc;
970}
971EXPORT_SYMBOL(qpnp_iadc_vadc_sync_read);
972
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700973static ssize_t qpnp_iadc_show(struct device *dev,
974 struct device_attribute *devattr, char *buf)
975{
976 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700977 struct qpnp_iadc_chip *iadc = dev_get_drvdata(dev);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700978 struct qpnp_iadc_result result;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700979 int rc = -1;
980
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700981 rc = qpnp_iadc_read(iadc, attr->index, &result);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700982
983 if (rc)
984 return 0;
985
986 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700987 "Result:%d\n", result.result_ua);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700988}
989
990static struct sensor_device_attribute qpnp_adc_attr =
991 SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
992
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700993static int32_t qpnp_iadc_init_hwmon(struct qpnp_iadc_chip *iadc,
994 struct spmi_device *spmi)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700995{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700996 struct device_node *child;
997 struct device_node *node = spmi->dev.of_node;
998 int rc = 0, i = 0, channel;
999
1000 for_each_child_of_node(node, child) {
1001 channel = iadc->adc->adc_channels[i].channel_num;
1002 qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
1003 qpnp_adc_attr.dev_attr.attr.name =
1004 iadc->adc->adc_channels[i].name;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001005 memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
1006 sizeof(qpnp_adc_attr));
Stephen Boyd8a5c4e42012-10-30 11:07:22 -07001007 sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001008 rc = device_create_file(&spmi->dev,
1009 &iadc->sens_attr[i].dev_attr);
1010 if (rc) {
1011 dev_err(&spmi->dev,
1012 "device_create_file failed for dev %s\n",
1013 iadc->adc->adc_channels[i].name);
1014 goto hwmon_err_sens;
1015 }
1016 i++;
1017 }
1018
1019 return 0;
1020hwmon_err_sens:
1021 pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
1022 return rc;
1023}
1024
1025static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
1026{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001027 struct qpnp_iadc_chip *iadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001028 struct qpnp_adc_drv *adc_qpnp;
1029 struct device_node *node = spmi->dev.of_node;
1030 struct device_node *child;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001031 int rc, count_adc_channel_list = 0, i = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001032
1033 for_each_child_of_node(node, child)
1034 count_adc_channel_list++;
1035
1036 if (!count_adc_channel_list) {
1037 pr_err("No channel listing\n");
1038 return -EINVAL;
1039 }
1040
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001041 iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_chip) +
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001042 (sizeof(struct sensor_device_attribute) *
1043 count_adc_channel_list), GFP_KERNEL);
1044 if (!iadc) {
1045 dev_err(&spmi->dev, "Unable to allocate memory\n");
1046 return -ENOMEM;
1047 }
1048
1049 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1050 GFP_KERNEL);
1051 if (!adc_qpnp) {
1052 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001053 rc = -ENOMEM;
1054 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001055 }
1056
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001057 iadc->dev = &(spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001058 iadc->adc = adc_qpnp;
1059
1060 rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
1061 if (rc) {
1062 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001063 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001064 }
1065
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001066 iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
1067 if (IS_ERR(iadc->vadc_dev)) {
1068 rc = PTR_ERR(iadc->vadc_dev);
1069 if (rc != -EPROBE_DEFER)
1070 pr_err("vadc property missing, rc=%d\n", rc);
1071 goto fail;
1072 }
1073
Stephen Boydbeab4502013-04-25 10:18:17 -07001074 mutex_init(&iadc->adc->adc_lock);
1075
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001076 rc = of_property_read_u32(node, "qcom,rsense",
1077 &iadc->rsense);
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -07001078 if (rc)
1079 pr_debug("Defaulting to internal rsense\n");
1080 else {
1081 pr_debug("Use external rsense\n");
1082 iadc->external_rsense = true;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001083 }
1084
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001085 iadc->iadc_poll_eoc = of_property_read_bool(node,
1086 "qcom,iadc-poll-eoc");
1087 if (!iadc->iadc_poll_eoc) {
1088 rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
1089 qpnp_iadc_isr, IRQF_TRIGGER_RISING,
1090 "qpnp_iadc_interrupt", iadc);
1091 if (rc) {
1092 dev_err(&spmi->dev, "failed to request adc irq\n");
1093 return rc;
1094 } else
1095 enable_irq_wake(iadc->adc->adc_irq_eoc);
1096 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001097
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001098 rc = qpnp_iadc_init_hwmon(iadc, spmi);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001099 if (rc) {
1100 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001101 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001102 }
1103 iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
1104
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001105 rc = qpnp_iadc_version_check(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001106 if (rc) {
1107 dev_err(&spmi->dev, "IADC version not supported\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001108 goto fail;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001109 }
1110
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001111 mutex_init(&iadc->iadc_vadc_lock);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001112 INIT_WORK(&iadc->trigger_completion_work, qpnp_iadc_trigger_completion);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001113 INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001114 rc = qpnp_iadc_comp_info(iadc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001115 if (rc) {
1116 dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
1117 goto fail;
1118 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001119
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001120 dev_set_drvdata(&spmi->dev, iadc);
1121 list_add(&iadc->list, &qpnp_iadc_device_list);
1122 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001123 if (rc)
1124 dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001125
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001126 if (iadc->iadc_poll_eoc)
1127 device_init_wakeup(iadc->dev, 1);
1128
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001129 schedule_delayed_work(&iadc->iadc_work,
1130 round_jiffies_relative(msecs_to_jiffies
1131 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001132 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001133fail:
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001134 for_each_child_of_node(node, child) {
1135 device_remove_file(&spmi->dev,
1136 &iadc->sens_attr[i].dev_attr);
1137 i++;
1138 }
1139 hwmon_device_unregister(iadc->iadc_hwmon);
1140
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001141 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001142}
1143
1144static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
1145{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001146 struct qpnp_iadc_chip *iadc = dev_get_drvdata(&spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001147 struct device_node *node = spmi->dev.of_node;
1148 struct device_node *child;
1149 int i = 0;
1150
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001151 cancel_delayed_work(&iadc->iadc_work);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001152 mutex_destroy(&iadc->iadc_vadc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001153 for_each_child_of_node(node, child) {
1154 device_remove_file(&spmi->dev,
1155 &iadc->sens_attr[i].dev_attr);
1156 i++;
1157 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001158 hwmon_device_unregister(iadc->iadc_hwmon);
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001159 if (iadc->iadc_poll_eoc)
1160 pm_relax(iadc->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001161 dev_set_drvdata(&spmi->dev, NULL);
1162
1163 return 0;
1164}
1165
1166static const struct of_device_id qpnp_iadc_match_table[] = {
1167 { .compatible = "qcom,qpnp-iadc",
1168 },
1169 {}
1170};
1171
1172static struct spmi_driver qpnp_iadc_driver = {
1173 .driver = {
1174 .name = "qcom,qpnp-iadc",
1175 .of_match_table = qpnp_iadc_match_table,
1176 },
1177 .probe = qpnp_iadc_probe,
1178 .remove = qpnp_iadc_remove,
1179};
1180
1181static int __init qpnp_iadc_init(void)
1182{
1183 return spmi_driver_register(&qpnp_iadc_driver);
1184}
1185module_init(qpnp_iadc_init);
1186
1187static void __exit qpnp_iadc_exit(void)
1188{
1189 spmi_driver_unregister(&qpnp_iadc_driver);
1190}
1191module_exit(qpnp_iadc_exit);
1192
1193MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
1194MODULE_LICENSE("GPL v2");