blob: 606d8dd1f3b6ec94a8627da0dc6ecfbadce4327c [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 Mohanadossc4a6af12012-07-13 18:50:12 -0700137struct qpnp_iadc_drv {
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 Mohanadoss5e2988d2012-09-24 17:03:56 -0700142 bool iadc_initialized;
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 Mohanadossc4a6af12012-07-13 18:50:12 -0700149 struct sensor_device_attribute sens_attr[0];
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700150 bool skip_auto_calibrations;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700151};
152
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700153static struct qpnp_iadc_drv *qpnp_iadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700154
155static int32_t qpnp_iadc_read_reg(uint32_t reg, u8 *data)
156{
157 struct qpnp_iadc_drv *iadc = qpnp_iadc;
158 int rc;
159
160 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700161 (iadc->adc->offset + reg), data, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700162 if (rc < 0) {
163 pr_err("qpnp iadc read reg %d failed with %d\n", reg, rc);
164 return rc;
165 }
166
167 return 0;
168}
169
170static int32_t qpnp_iadc_write_reg(uint32_t reg, u8 data)
171{
172 struct qpnp_iadc_drv *iadc = qpnp_iadc;
173 int rc;
174 u8 *buf;
175
176 buf = &data;
177 rc = spmi_ext_register_writel(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700178 (iadc->adc->offset + reg), buf, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700179 if (rc < 0) {
180 pr_err("qpnp iadc write reg %d failed with %d\n", reg, rc);
181 return rc;
182 }
183
184 return 0;
185}
186
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800187static void trigger_iadc_completion(struct work_struct *work)
188{
189 struct qpnp_iadc_drv *iadc = qpnp_iadc;
190
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800191 if (!iadc || !iadc->iadc_initialized)
192 return;
193
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800194 complete(&iadc->adc->adc_rslt_completion);
195
196 return;
197}
198DECLARE_WORK(trigger_iadc_completion_work, trigger_iadc_completion);
199
200static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
201{
202 schedule_work(&trigger_iadc_completion_work);
203
204 return IRQ_HANDLED;
205}
206
207static int32_t qpnp_iadc_enable(bool state)
208{
209 int rc = 0;
210 u8 data = 0;
211
212 data = QPNP_IADC_ADC_EN;
213 if (state) {
214 rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
215 data);
216 if (rc < 0) {
217 pr_err("IADC enable failed\n");
218 return rc;
219 }
220 } else {
221 rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
222 (~data & QPNP_IADC_ADC_EN));
223 if (rc < 0) {
224 pr_err("IADC disable failed\n");
225 return rc;
226 }
227 }
228
229 return 0;
230}
231
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800232static int32_t qpnp_iadc_status_debug(void)
233{
234 int rc = 0;
235 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
236
237 rc = qpnp_iadc_read_reg(QPNP_IADC_MODE_CTL, &mode);
238 if (rc < 0) {
239 pr_err("mode ctl register read failed with %d\n", rc);
240 return rc;
241 }
242
243 rc = qpnp_iadc_read_reg(QPNP_ADC_DIG_PARAM, &dig);
244 if (rc < 0) {
245 pr_err("digital param read failed with %d\n", rc);
246 return rc;
247 }
248
249 rc = qpnp_iadc_read_reg(QPNP_IADC_ADC_CH_SEL_CTL, &chan);
250 if (rc < 0) {
251 pr_err("channel read failed with %d\n", rc);
252 return rc;
253 }
254
255 rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
256 if (rc < 0) {
257 pr_err("status1 read failed with %d\n", rc);
258 return rc;
259 }
260
261 rc = qpnp_iadc_read_reg(QPNP_IADC_EN_CTL1, &en);
262 if (rc < 0) {
263 pr_err("en read failed with %d\n", rc);
264 return rc;
265 }
266
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700267 pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800268 status1, dig, chan, mode, en);
269
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800270 rc = qpnp_iadc_enable(false);
271 if (rc < 0) {
272 pr_err("IADC disable failed with %d\n", rc);
273 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700274 }
275
276 return 0;
277}
278
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700279static int32_t qpnp_iadc_read_conversion_result(uint16_t *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700280{
281 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700282 uint16_t rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700283 int32_t rc;
284
285 rc = qpnp_iadc_read_reg(QPNP_IADC_DATA0, &rslt_lsb);
286 if (rc < 0) {
287 pr_err("qpnp adc result read failed with %d\n", rc);
288 return rc;
289 }
290
291 rc = qpnp_iadc_read_reg(QPNP_IADC_DATA1, &rslt_msb);
292 if (rc < 0) {
293 pr_err("qpnp adc result read failed with %d\n", rc);
294 return rc;
295 }
296
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700297 rslt = (rslt_msb << 8) | rslt_lsb;
298 *data = rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700299
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700300 rc = qpnp_iadc_enable(false);
301 if (rc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700302 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700303
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700304 return 0;
305}
306
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700307static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_comp comp,
308 int64_t die_temp)
309{
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700310 int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0, old;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700311
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700312 old = *result;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700313 *result = *result * 1000000;
314
315 if (comp.revision == QPNP_IADC_VER_3_1) {
316 /* revision 3.1 */
317 if (comp.sys_gain > 127)
318 sys_gain_coeff = -QPNP_COEFF_6 * (comp.sys_gain - 128);
319 else
320 sys_gain_coeff = QPNP_COEFF_6 * comp.sys_gain;
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700321 } else if (comp.revision != QPNP_IADC_VER_3_0) {
322 /* unsupported revision, do not compensate */
323 *result = old;
324 return 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700325 }
326
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700327 if (!comp.ext_rsense) {
328 /* internal rsense */
329 switch (comp.id) {
330 case COMP_ID_TSMC:
331 temp_var = ((QPNP_COEFF_2 * die_temp) -
332 QPNP_COEFF_3_TYPEB);
333 break;
334 case COMP_ID_GF:
335 default:
336 temp_var = ((QPNP_COEFF_2 * die_temp) -
337 QPNP_COEFF_3_TYPEA);
338 break;
339 }
340 temp_var = div64_s64(temp_var, QPNP_COEFF_4);
341 if (comp.revision == QPNP_IADC_VER_3_0)
342 temp_var = QPNP_COEFF_1 * (1000000 - temp_var);
343 else if (comp.revision == QPNP_IADC_VER_3_1)
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700344 temp_var = 1000000 * (1000000 - temp_var);
345 *result = div64_s64(*result * 1000000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700346 }
347
348 sign_coeff = *result < 0 ? QPNP_COEFF_7 : QPNP_COEFF_5;
349 if (comp.ext_rsense) {
350 /* external rsense and current charging */
351 temp_var = div64_s64((-sign_coeff * die_temp) + QPNP_COEFF_8,
352 QPNP_COEFF_4);
353 temp_var = 1000000000 - temp_var;
354 if (comp.revision == QPNP_IADC_VER_3_1) {
355 sys_gain_coeff = (1000000 +
356 div64_s64(sys_gain_coeff, QPNP_COEFF_4));
357 temp_var = div64_s64(temp_var * sys_gain_coeff,
358 1000000000);
359 }
360 *result = div64_s64(*result, temp_var);
361 }
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700362 pr_debug("%lld compensated into %lld\n", old, *result);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700363
364 return 0;
365}
366
367int32_t qpnp_iadc_comp_result(int64_t *result)
368{
369 struct qpnp_iadc_drv *iadc = qpnp_iadc;
370
371 return qpnp_iadc_comp(result, iadc->iadc_comp, iadc->die_temp);
372}
373EXPORT_SYMBOL(qpnp_iadc_comp_result);
374
375static int32_t qpnp_iadc_comp_info(void)
376{
377 struct qpnp_iadc_drv *iadc = qpnp_iadc;
378 int rc = 0;
379
380 rc = qpnp_iadc_read_reg(QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
381 if (rc < 0) {
382 pr_err("qpnp adc comp id failed with %d\n", rc);
383 return rc;
384 }
385
386 rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &iadc->iadc_comp.revision);
387 if (rc < 0) {
388 pr_err("qpnp adc revision read failed with %d\n", rc);
389 return rc;
390 }
391
392 rc = qpnp_iadc_read_reg(QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
393 &iadc->iadc_comp.sys_gain);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700394 if (rc < 0) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700395 pr_err("full scale read failed with %d\n", rc);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700396 return rc;
397 }
398
399 if (iadc->external_rsense)
400 iadc->iadc_comp.ext_rsense = true;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700401
402 pr_debug("fab id = %u, revision = %u, sys gain = %u, external_rsense = %d\n",
403 iadc->iadc_comp.id,
404 iadc->iadc_comp.revision,
405 iadc->iadc_comp.sys_gain,
406 iadc->iadc_comp.ext_rsense);
407 return rc;
408}
409
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700410static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800411 uint16_t *raw_code, uint32_t mode_sel)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700412{
413 struct qpnp_iadc_drv *iadc = qpnp_iadc;
414 u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
415 u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
416 int32_t rc = 0;
417
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700418 qpnp_iadc_ch_sel_reg = channel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700419
420 qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
421 QPNP_IADC_DEC_RATIO_SEL;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800422 if (iadc->iadc_mode_sel)
423 qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN);
424 else
425 qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
426
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700427 qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
428
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700429 rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
430 if (rc) {
431 pr_err("qpnp adc read adc failed with %d\n", rc);
432 return rc;
433 }
434
435 rc = qpnp_iadc_write_reg(QPNP_IADC_ADC_CH_SEL_CTL,
436 qpnp_iadc_ch_sel_reg);
437 if (rc) {
438 pr_err("qpnp adc read adc failed with %d\n", rc);
439 return rc;
440 }
441
442 rc = qpnp_iadc_write_reg(QPNP_ADC_DIG_PARAM,
443 qpnp_iadc_dig_param_reg);
444 if (rc) {
445 pr_err("qpnp adc read adc failed with %d\n", rc);
446 return rc;
447 }
448
449 rc = qpnp_iadc_write_reg(QPNP_HW_SETTLE_DELAY,
450 iadc->adc->amux_prop->hw_settle_time);
451 if (rc < 0) {
452 pr_err("qpnp adc configure error for hw settling time setup\n");
453 return rc;
454 }
455
456 rc = qpnp_iadc_write_reg(QPNP_FAST_AVG_CTL,
457 iadc->adc->amux_prop->fast_avg_setup);
458 if (rc < 0) {
459 pr_err("qpnp adc fast averaging configure error\n");
460 return rc;
461 }
462
Siddartha Mohanadoss3f219c42013-04-02 11:01:28 -0700463 INIT_COMPLETION(iadc->adc->adc_rslt_completion);
464
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700465 rc = qpnp_iadc_enable(true);
466 if (rc)
467 return rc;
468
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700469 rc = qpnp_iadc_write_reg(QPNP_CONV_REQ, qpnp_iadc_conv_req);
470 if (rc) {
471 pr_err("qpnp adc read adc failed with %d\n", rc);
472 return rc;
473 }
474
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700475 rc = wait_for_completion_timeout(&iadc->adc->adc_rslt_completion,
476 QPNP_ADC_COMPLETION_TIMEOUT);
477 if (!rc) {
478 u8 status1 = 0;
479 rc = qpnp_iadc_read_reg(QPNP_STATUS1, &status1);
480 if (rc < 0)
481 return rc;
482 status1 &= (QPNP_STATUS1_REQ_STS | QPNP_STATUS1_EOC);
483 if (status1 == QPNP_STATUS1_EOC)
484 pr_debug("End of conversion status set\n");
485 else {
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800486 rc = qpnp_iadc_status_debug();
487 if (rc < 0) {
488 pr_err("status1 read failed with %d\n", rc);
489 return rc;
490 }
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700491 return -EINVAL;
492 }
493 }
494
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700495 rc = qpnp_iadc_read_conversion_result(raw_code);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700496 if (rc) {
497 pr_err("qpnp adc read adc failed with %d\n", rc);
498 return rc;
499 }
500
501 return 0;
502}
503
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700504#define IADC_CENTER 0xC000
505#define IADC_READING_RESOLUTION_N 542535
506#define IADC_READING_RESOLUTION_D 100000
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700507static int32_t qpnp_convert_raw_offset_voltage(void)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700508{
509 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700510 s64 numerator;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700511
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800512 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
513 pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
514 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
515 return -EINVAL;
516 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700517
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700518 numerator = iadc->adc->calib.offset_raw - IADC_CENTER;
519 numerator *= IADC_READING_RESOLUTION_N;
520 iadc->adc->calib.offset_uv = div_s64(numerator,
521 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700522
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700523 numerator = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
524 numerator *= IADC_READING_RESOLUTION_N;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700525
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700526 iadc->adc->calib.gain_uv = div_s64(numerator,
527 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700528
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700529 pr_debug("gain_uv:%d offset_uv:%d\n",
530 iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700531 return 0;
532}
533
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700534int32_t qpnp_iadc_calibrate_for_trim(bool batfet_closed)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700535{
536 struct qpnp_iadc_drv *iadc = qpnp_iadc;
537 uint8_t rslt_lsb, rslt_msb;
538 int32_t rc = 0;
539 uint16_t raw_data;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800540 uint32_t mode_sel = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700541
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700542 if (!iadc || !iadc->iadc_initialized)
543 return -EPROBE_DEFER;
544
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800545 mutex_lock(&iadc->adc->adc_lock);
546
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800547 rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV,
548 &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700549 if (rc < 0) {
550 pr_err("qpnp adc result read failed with %d\n", rc);
551 goto fail;
552 }
553
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700554 iadc->adc->calib.gain_raw = raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700555
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700556 /*
557 * there is a features in the BMS where if the batfet is opened
558 * the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
559 * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
560 * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
561 * internal rsense.
562 */
563 if (!batfet_closed || iadc->external_rsense) {
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700564 /* external offset calculation */
565 rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP_CSN,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800566 &raw_data, mode_sel);
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700567 if (rc < 0) {
568 pr_err("qpnp adc result read failed with %d\n", rc);
569 goto fail;
570 }
571 } else {
572 /* internal offset calculation */
573 rc = qpnp_iadc_configure(OFFSET_CALIBRATION_CSP2_CSN2,
574 &raw_data, mode_sel);
575 if (rc < 0) {
576 pr_err("qpnp adc result read failed with %d\n", rc);
577 goto fail;
578 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700579 }
580
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700581 iadc->adc->calib.offset_raw = raw_data;
582 if (rc < 0) {
583 pr_err("qpnp adc offset/gain calculation failed\n");
584 goto fail;
585 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700586
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700587 pr_debug("raw gain:0x%x, raw offset:0x%x\n",
588 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
589
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700590 rc = qpnp_convert_raw_offset_voltage();
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800591 if (rc < 0) {
592 pr_err("qpnp raw_voltage conversion failed\n");
593 goto fail;
594 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700595
596 rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
597 QPNP_BIT_SHIFT_8;
598 rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
599
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700600 pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
601
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700602 rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
603 QPNP_IADC_SEC_ACCESS_DATA);
604 if (rc < 0) {
605 pr_err("qpnp iadc configure error for sec access\n");
606 goto fail;
607 }
608
609 rc = qpnp_iadc_write_reg(QPNP_IADC_MSB_OFFSET,
610 rslt_msb);
611 if (rc < 0) {
612 pr_err("qpnp iadc configure error for MSB write\n");
613 goto fail;
614 }
615
616 rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
617 QPNP_IADC_SEC_ACCESS_DATA);
618 if (rc < 0) {
619 pr_err("qpnp iadc configure error for sec access\n");
620 goto fail;
621 }
622
623 rc = qpnp_iadc_write_reg(QPNP_IADC_LSB_OFFSET,
624 rslt_lsb);
625 if (rc < 0) {
626 pr_err("qpnp iadc configure error for LSB write\n");
627 goto fail;
628 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700629fail:
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800630 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700631 return rc;
632}
Siddartha Mohanadoss06673922013-03-27 11:14:19 -0700633EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700634
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700635static void qpnp_iadc_work(struct work_struct *work)
636{
637 struct qpnp_iadc_drv *iadc = qpnp_iadc;
638 int rc = 0;
639
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700640 if (!iadc->skip_auto_calibrations) {
641 rc = qpnp_iadc_calibrate_for_trim(true);
642 if (rc)
643 pr_debug("periodic IADC calibration failed\n");
644 }
645
646 schedule_delayed_work(&iadc->iadc_work,
647 round_jiffies_relative(msecs_to_jiffies
648 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700649 return;
650}
651
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700652static int32_t qpnp_iadc_version_check(void)
653{
654 uint8_t revision;
655 int rc;
656
657 rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &revision);
658 if (rc < 0) {
659 pr_err("qpnp adc result read failed with %d\n", rc);
660 return rc;
661 }
662
663 if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
664 pr_err("IADC Version not supported\n");
665 return -EINVAL;
666 }
667
668 return 0;
669}
670
671int32_t qpnp_iadc_is_ready(void)
672{
673 struct qpnp_iadc_drv *iadc = qpnp_iadc;
674
675 if (!iadc || !iadc->iadc_initialized)
676 return -EPROBE_DEFER;
677 else
678 return 0;
679}
680EXPORT_SYMBOL(qpnp_iadc_is_ready);
681
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700682int32_t qpnp_iadc_get_rsense(int32_t *rsense)
683{
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800684 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700685 uint8_t rslt_rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700686 int32_t rc = 0, sign_bit = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700687
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800688 if (!iadc || !iadc->iadc_initialized)
689 return -EPROBE_DEFER;
690
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700691 if (iadc->external_rsense) {
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700692 *rsense = iadc->rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700693 return rc;
694 }
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700695
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700696 rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
697 if (rc < 0) {
698 pr_err("qpnp adc rsense read failed with %d\n", rc);
699 return rc;
700 }
701
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700702 pr_debug("rsense:0%x\n", rslt_rsense);
703
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700704 if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
705 sign_bit = 1;
706
707 rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
708
709 if (sign_bit)
710 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
711 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
712 else
713 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
714 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
715
716 return rc;
717}
Xiaozhe Shi767fdb62013-01-10 15:09:08 -0800718EXPORT_SYMBOL(qpnp_iadc_get_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700719
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800720static int32_t qpnp_check_pmic_temp(void)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700721{
722 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700723 struct qpnp_vadc_result result_pmic_therm;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700724 int64_t die_temp_offset;
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800725 int rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700726
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700727 rc = qpnp_vadc_read(iadc->vadc_dev, DIE_TEMP, &result_pmic_therm);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700728 if (rc < 0)
729 return rc;
730
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700731 die_temp_offset = result_pmic_therm.physical -
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700732 iadc->die_temp;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700733 if (die_temp_offset < 0)
734 die_temp_offset = -die_temp_offset;
735
736 if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700737 iadc->die_temp = result_pmic_therm.physical;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700738 if (!iadc->skip_auto_calibrations) {
739 rc = qpnp_iadc_calibrate_for_trim(true);
740 if (rc)
741 pr_err("IADC calibration failed rc = %d\n", rc);
742 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700743 }
744
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800745 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700746}
747
748int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
749 struct qpnp_iadc_result *result)
750{
751 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800752 int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700753 int32_t rsense_u_ohms = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700754 int64_t result_current;
755 uint16_t raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700756
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700757 if (!iadc || !iadc->iadc_initialized)
758 return -EPROBE_DEFER;
759
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800760 if (!iadc->iadc_mode_sel) {
761 rc = qpnp_check_pmic_temp();
762 if (rc) {
763 pr_err("Error checking pmic therm temp\n");
764 return rc;
765 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700766 }
767
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700768 mutex_lock(&iadc->adc->adc_lock);
769
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800770 rc = qpnp_iadc_configure(channel, &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700771 if (rc < 0) {
772 pr_err("qpnp adc result read failed with %d\n", rc);
773 goto fail;
774 }
775
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700776 rc = qpnp_iadc_get_rsense(&rsense_n_ohms);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700777 pr_debug("current raw:0%x and rsense:%d\n",
778 raw_data, rsense_n_ohms);
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700779 rsense_u_ohms = rsense_n_ohms/1000;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700780 num = raw_data - iadc->adc->calib.offset_raw;
781 if (num < 0) {
782 sign = 1;
783 num = -num;
784 }
785
786 result->result_uv = (num * QPNP_ADC_GAIN_NV)/
787 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
788 result_current = result->result_uv;
789 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700790 /* Intentional fall through. Process the result w/o comp */
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700791 do_div(result_current, rsense_u_ohms);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700792
793 if (sign) {
794 result->result_uv = -result->result_uv;
795 result_current = -result_current;
796 }
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700797 rc = qpnp_iadc_comp_result(&result_current);
798 if (rc < 0)
799 pr_err("Error during compensating the IADC\n");
800 rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700801
802 result->result_ua = (int32_t) result_current;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700803fail:
804 mutex_unlock(&iadc->adc->adc_lock);
805
806 return rc;
807}
808EXPORT_SYMBOL(qpnp_iadc_read);
809
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700810int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700811{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700812 struct qpnp_iadc_drv *iadc = qpnp_iadc;
813 int rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700814
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700815 if (!iadc || !iadc->iadc_initialized)
816 return -EPROBE_DEFER;
817
818 rc = qpnp_check_pmic_temp();
819 if (rc) {
820 pr_err("Error checking pmic therm temp\n");
821 return rc;
822 }
823
824 mutex_lock(&iadc->adc->adc_lock);
825 result->gain_raw = iadc->adc->calib.gain_raw;
826 result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
827 result->gain_uv = iadc->adc->calib.gain_uv;
828 result->offset_raw = iadc->adc->calib.offset_raw;
829 result->ideal_offset_uv =
830 QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
831 result->offset_uv = iadc->adc->calib.offset_uv;
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700832 pr_debug("raw gain:0%x, raw offset:0%x\n",
833 result->gain_raw, result->offset_raw);
834 pr_debug("gain_uv:%d offset_uv:%d\n",
835 result->gain_uv, result->offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700836 mutex_unlock(&iadc->adc->adc_lock);
837
838 return 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700839}
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700840EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700841
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700842int qpnp_iadc_skip_calibration(void)
843{
844 struct qpnp_iadc_drv *iadc = qpnp_iadc;
845
846 if (!iadc || !iadc->iadc_initialized)
847 return -EPROBE_DEFER;
848
849 iadc->skip_auto_calibrations = true;
850 return 0;
851}
852EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
853
854int qpnp_iadc_resume_calibration(void)
855{
856 struct qpnp_iadc_drv *iadc = qpnp_iadc;
857
858 if (!iadc || !iadc->iadc_initialized)
859 return -EPROBE_DEFER;
860
861 iadc->skip_auto_calibrations = false;
862 return 0;
863}
864EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
865
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800866int32_t qpnp_iadc_vadc_sync_read(
867 enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
868 enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
869{
870 struct qpnp_iadc_drv *iadc = qpnp_iadc;
871 int rc = 0;
872
873 if (!iadc || !iadc->iadc_initialized)
874 return -EPROBE_DEFER;
875
876 mutex_lock(&iadc->iadc_vadc_lock);
877
878 rc = qpnp_check_pmic_temp();
879 if (rc) {
880 pr_err("PMIC die temp check failed\n");
881 goto fail;
882 }
883
884 iadc->iadc_mode_sel = true;
885
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700886 rc = qpnp_vadc_iadc_sync_request(iadc->vadc_dev, v_channel);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800887 if (rc) {
888 pr_err("Configuring VADC failed\n");
889 goto fail;
890 }
891
892 rc = qpnp_iadc_read(i_channel, i_result);
893 if (rc)
894 pr_err("Configuring IADC failed\n");
895 /* Intentional fall through to release VADC */
896
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700897 rc = qpnp_vadc_iadc_sync_complete_request(iadc->vadc_dev, v_channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800898 v_result);
899 if (rc)
900 pr_err("Releasing VADC failed\n");
901fail:
902 iadc->iadc_mode_sel = false;
903
904 mutex_unlock(&iadc->iadc_vadc_lock);
905
906 return rc;
907}
908EXPORT_SYMBOL(qpnp_iadc_vadc_sync_read);
909
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700910static ssize_t qpnp_iadc_show(struct device *dev,
911 struct device_attribute *devattr, char *buf)
912{
913 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700914 struct qpnp_iadc_result result;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700915 int rc = -1;
916
917 rc = qpnp_iadc_read(attr->index, &result);
918
919 if (rc)
920 return 0;
921
922 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700923 "Result:%d\n", result.result_ua);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700924}
925
926static struct sensor_device_attribute qpnp_adc_attr =
927 SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
928
929static int32_t qpnp_iadc_init_hwmon(struct spmi_device *spmi)
930{
931 struct qpnp_iadc_drv *iadc = qpnp_iadc;
932 struct device_node *child;
933 struct device_node *node = spmi->dev.of_node;
934 int rc = 0, i = 0, channel;
935
936 for_each_child_of_node(node, child) {
937 channel = iadc->adc->adc_channels[i].channel_num;
938 qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
939 qpnp_adc_attr.dev_attr.attr.name =
940 iadc->adc->adc_channels[i].name;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700941 memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
942 sizeof(qpnp_adc_attr));
Stephen Boyd8a5c4e42012-10-30 11:07:22 -0700943 sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700944 rc = device_create_file(&spmi->dev,
945 &iadc->sens_attr[i].dev_attr);
946 if (rc) {
947 dev_err(&spmi->dev,
948 "device_create_file failed for dev %s\n",
949 iadc->adc->adc_channels[i].name);
950 goto hwmon_err_sens;
951 }
952 i++;
953 }
954
955 return 0;
956hwmon_err_sens:
957 pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
958 return rc;
959}
960
961static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
962{
963 struct qpnp_iadc_drv *iadc;
964 struct qpnp_adc_drv *adc_qpnp;
965 struct device_node *node = spmi->dev.of_node;
966 struct device_node *child;
967 int rc, count_adc_channel_list = 0;
968
969 if (!node)
970 return -EINVAL;
971
972 if (qpnp_iadc) {
973 pr_err("IADC already in use\n");
974 return -EBUSY;
975 }
976
977 for_each_child_of_node(node, child)
978 count_adc_channel_list++;
979
980 if (!count_adc_channel_list) {
981 pr_err("No channel listing\n");
982 return -EINVAL;
983 }
984
985 iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_drv) +
986 (sizeof(struct sensor_device_attribute) *
987 count_adc_channel_list), GFP_KERNEL);
988 if (!iadc) {
989 dev_err(&spmi->dev, "Unable to allocate memory\n");
990 return -ENOMEM;
991 }
992
993 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
994 GFP_KERNEL);
995 if (!adc_qpnp) {
996 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800997 rc = -ENOMEM;
998 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700999 }
1000
1001 iadc->adc = adc_qpnp;
1002
1003 rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
1004 if (rc) {
1005 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001006 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001007 }
1008
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001009 iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
1010 if (IS_ERR(iadc->vadc_dev)) {
1011 rc = PTR_ERR(iadc->vadc_dev);
1012 if (rc != -EPROBE_DEFER)
1013 pr_err("vadc property missing, rc=%d\n", rc);
1014 goto fail;
1015 }
1016
Stephen Boydbeab4502013-04-25 10:18:17 -07001017 mutex_init(&iadc->adc->adc_lock);
1018
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001019 rc = of_property_read_u32(node, "qcom,rsense",
1020 &iadc->rsense);
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -07001021 if (rc)
1022 pr_debug("Defaulting to internal rsense\n");
1023 else {
1024 pr_debug("Use external rsense\n");
1025 iadc->external_rsense = true;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001026 }
1027
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001028 rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001029 qpnp_iadc_isr,
1030 IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
1031 if (rc) {
1032 dev_err(&spmi->dev, "failed to request adc irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001033 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001034 } else
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001035 enable_irq_wake(iadc->adc->adc_irq_eoc);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001036
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001037 dev_set_drvdata(&spmi->dev, iadc);
1038 qpnp_iadc = iadc;
1039
1040 rc = qpnp_iadc_init_hwmon(spmi);
1041 if (rc) {
1042 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001043 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001044 }
1045 iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
1046
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001047 rc = qpnp_iadc_version_check();
1048 if (rc) {
1049 dev_err(&spmi->dev, "IADC version not supported\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001050 goto fail;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001051 }
1052
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001053 mutex_init(&iadc->iadc_vadc_lock);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001054 INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001055 rc = qpnp_iadc_comp_info();
1056 if (rc) {
1057 dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
1058 goto fail;
1059 }
Siddartha Mohanadoss12a15ea2013-02-05 19:13:41 -08001060 iadc->iadc_initialized = true;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001061
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -07001062 rc = qpnp_iadc_calibrate_for_trim(true);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001063 if (rc)
1064 dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
1065 schedule_delayed_work(&iadc->iadc_work,
1066 round_jiffies_relative(msecs_to_jiffies
1067 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001068 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001069fail:
Siddartha Mohanadoss32019b52012-12-23 17:05:45 -08001070 qpnp_iadc = NULL;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001071 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001072}
1073
1074static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
1075{
1076 struct qpnp_iadc_drv *iadc = dev_get_drvdata(&spmi->dev);
1077 struct device_node *node = spmi->dev.of_node;
1078 struct device_node *child;
1079 int i = 0;
1080
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001081 cancel_delayed_work(&iadc->iadc_work);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001082 mutex_destroy(&iadc->iadc_vadc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001083 for_each_child_of_node(node, child) {
1084 device_remove_file(&spmi->dev,
1085 &iadc->sens_attr[i].dev_attr);
1086 i++;
1087 }
1088 dev_set_drvdata(&spmi->dev, NULL);
1089
1090 return 0;
1091}
1092
1093static const struct of_device_id qpnp_iadc_match_table[] = {
1094 { .compatible = "qcom,qpnp-iadc",
1095 },
1096 {}
1097};
1098
1099static struct spmi_driver qpnp_iadc_driver = {
1100 .driver = {
1101 .name = "qcom,qpnp-iadc",
1102 .of_match_table = qpnp_iadc_match_table,
1103 },
1104 .probe = qpnp_iadc_probe,
1105 .remove = qpnp_iadc_remove,
1106};
1107
1108static int __init qpnp_iadc_init(void)
1109{
1110 return spmi_driver_register(&qpnp_iadc_driver);
1111}
1112module_init(qpnp_iadc_init);
1113
1114static void __exit qpnp_iadc_exit(void)
1115{
1116 spmi_driver_unregister(&qpnp_iadc_driver);
1117}
1118module_exit(qpnp_iadc_exit);
1119
1120MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
1121MODULE_LICENSE("GPL v2");