blob: 98395954488e9cbc784618fd7618b3d6ffb20b12 [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;
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700137 u8 revision_dig_major;
138 u8 revision_ana_minor;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700139};
140
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700141struct qpnp_iadc_chip {
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700142 struct device *dev;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700143 struct qpnp_adc_drv *adc;
144 int32_t rsense;
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700145 bool external_rsense;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700146 struct device *iadc_hwmon;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700147 struct list_head list;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700148 int64_t die_temp;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700149 struct delayed_work iadc_work;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800150 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 Mohanadossc6921682013-08-07 08:45:41 -0700327#define QPNP_IADC_PM8941_3_1_REV2 3
328#define QPNP_IADC_PM8941_3_1_REV3 2
329#define QPNP_IADC_PM8026_1_REV2 1
330#define QPNP_IADC_PM8026_1_REV3 2
331#define QPNP_IADC_PM8026_2_REV2 4
332#define QPNP_IADC_PM8026_2_REV3 2
333#define QPNP_IADC_PM8110_1_REV2 2
334#define QPNP_IADC_PM8110_1_REV3 2
335
336#define QPNP_IADC_REV_ID_8941_3_1 1
337#define QPNP_IADC_REV_ID_8026_1_0 2
338#define QPNP_IADC_REV_ID_8026_2_0 3
339#define QPNP_IADC_REV_ID_8110_1_0 4
340
341static void qpnp_temp_comp_version_check(struct qpnp_iadc_chip *iadc,
342 int32_t *version)
343{
344 if ((iadc->iadc_comp.revision_dig_major ==
345 QPNP_IADC_PM8941_3_1_REV2) &&
346 (iadc->iadc_comp.revision_ana_minor ==
347 QPNP_IADC_PM8941_3_1_REV3))
348 *version = QPNP_IADC_REV_ID_8941_3_1;
349 else if ((iadc->iadc_comp.revision_dig_major ==
350 QPNP_IADC_PM8026_1_REV2) &&
351 (iadc->iadc_comp.revision_ana_minor ==
352 QPNP_IADC_PM8026_1_REV3))
353 *version = QPNP_IADC_REV_ID_8026_1_0;
354 else if ((iadc->iadc_comp.revision_dig_major ==
355 QPNP_IADC_PM8026_2_REV2) &&
356 (iadc->iadc_comp.revision_ana_minor ==
357 QPNP_IADC_PM8026_2_REV3))
358 *version = QPNP_IADC_REV_ID_8026_2_0;
359 else if ((iadc->iadc_comp.revision_dig_major ==
360 QPNP_IADC_PM8110_1_REV2) &&
361 (iadc->iadc_comp.revision_ana_minor ==
362 QPNP_IADC_PM8110_1_REV3))
363 *version = QPNP_IADC_REV_ID_8110_1_0;
364 else
365 *version = -EINVAL;
366
367 return;
368}
369
370#define QPNP_COEFF_1 969000
371#define QPNP_COEFF_2 32
372#define QPNP_COEFF_3_TYPEA 1700000
373#define QPNP_COEFF_3_TYPEB 1000000
374#define QPNP_COEFF_4 100
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700375#define QPNP_COEFF_5 15
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700376#define QPNP_COEFF_6 100000
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700377#define QPNP_COEFF_7 21
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700378#define QPNP_COEFF_8 100000000
379#define QPNP_COEFF_9 38
380#define QPNP_COEFF_10 40
381#define QPNP_COEFF_11 7
382#define QPNP_COEFF_12 11
383#define QPNP_COEFF_13 37
384#define QPNP_COEFF_14 39
385#define QPNP_COEFF_15 9
386#define QPNP_COEFF_16 11
387#define QPNP_COEFF_17 851200
388#define QPNP_COEFF_18 296500
389#define QPNP_COEFF_19 222400
390#define QPNP_COEFF_20 813800
391#define QPNP_COEFF_21 1059100
392#define QPNP_COEFF_22 5000000
393#define QPNP_COEFF_23 3722500
394#define QPNP_COEFF_24 84
395
396static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700397 int64_t die_temp)
398{
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700399 int64_t temp_var = 0, sys_gain_coeff = 0, old;
400 int32_t coeff_a = 0, coeff_b = 0;
401 int32_t version;
402
403 qpnp_temp_comp_version_check(iadc, &version);
404 if (version == -EINVAL)
405 return 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700406
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700407 old = *result;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700408 *result = *result * 1000000;
409
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700410 if (iadc->iadc_comp.sys_gain > 127)
411 sys_gain_coeff = -QPNP_COEFF_6 *
412 (iadc->iadc_comp.sys_gain - 128);
413 else
414 sys_gain_coeff = QPNP_COEFF_6 *
415 iadc->iadc_comp.sys_gain;
416
417 switch (version) {
418 case QPNP_IADC_REV_ID_8941_3_1:
419 switch (iadc->iadc_comp.id) {
420 case COMP_ID_GF:
421 if (!iadc->iadc_comp.ext_rsense) {
422 /* internal rsense */
423 coeff_a = QPNP_COEFF_2;
424 coeff_b = -QPNP_COEFF_3_TYPEA;
425 } else {
426 if (*result < 0) {
427 /* charge */
428 coeff_a = QPNP_COEFF_5;
429 coeff_b = QPNP_COEFF_6;
430 } else {
431 /* discharge */
432 coeff_a = -QPNP_COEFF_7;
433 coeff_b = QPNP_COEFF_6;
434 }
435 }
436 break;
437 case COMP_ID_TSMC:
438 default:
439 if (!iadc->iadc_comp.ext_rsense) {
440 /* internal rsense */
441 coeff_a = QPNP_COEFF_2;
442 coeff_b = -QPNP_COEFF_3_TYPEB;
443 } else {
444 if (*result < 0) {
445 /* charge */
446 coeff_a = QPNP_COEFF_5;
447 coeff_b = QPNP_COEFF_6;
448 } else {
449 /* discharge */
450 coeff_a = -QPNP_COEFF_7;
451 coeff_b = QPNP_COEFF_6;
452 }
453 }
454 break;
455 }
456 break;
457 case QPNP_IADC_REV_ID_8026_1_0:
458 /* pm8026 rev 1.0 */
459 switch (iadc->iadc_comp.id) {
460 case COMP_ID_GF:
461 if (!iadc->iadc_comp.ext_rsense) {
462 /* internal rsense */
463 if (*result < 0) {
464 /* charge */
465 coeff_a = QPNP_COEFF_9;
466 coeff_b = -QPNP_COEFF_17;
467 } else {
468 coeff_a = QPNP_COEFF_10;
469 coeff_b = QPNP_COEFF_18;
470 }
471 } else {
472 if (*result < 0) {
473 /* charge */
474 coeff_a = -QPNP_COEFF_11;
475 coeff_b = 0;
476 } else {
477 /* discharge */
478 coeff_a = -QPNP_COEFF_17;
479 coeff_b = -QPNP_COEFF_19;
480 }
481 }
482 break;
483 case COMP_ID_TSMC:
484 default:
485 if (!iadc->iadc_comp.ext_rsense) {
486 /* internal rsense */
487 if (*result < 0) {
488 /* charge */
489 coeff_a = QPNP_COEFF_13;
490 coeff_b = -QPNP_COEFF_20;
491 } else {
492 coeff_a = QPNP_COEFF_14;
493 coeff_b = QPNP_COEFF_21;
494 }
495 } else {
496 if (*result < 0) {
497 /* charge */
498 coeff_a = -QPNP_COEFF_15;
499 coeff_b = 0;
500 } else {
501 /* discharge */
502 coeff_a = -QPNP_COEFF_12;
503 coeff_b = -QPNP_COEFF_19;
504 }
505 }
506 break;
507 }
508 break;
509 case QPNP_IADC_REV_ID_8110_1_0:
510 /* pm8110 rev 1.0 */
511 switch (iadc->iadc_comp.id) {
512 case COMP_ID_GF:
513 if (!iadc->iadc_comp.ext_rsense) {
514 /* internal rsense */
515 if (*result < 0) {
516 /* charge */
517 coeff_a = QPNP_COEFF_24;
518 coeff_b = -QPNP_COEFF_22;
519 } else {
520 coeff_a = QPNP_COEFF_24;
521 coeff_b = -QPNP_COEFF_23;
522 }
523 }
524 break;
525 case COMP_ID_SMIC:
526 default:
527 if (!iadc->iadc_comp.ext_rsense) {
528 /* internal rsense */
529 if (*result < 0) {
530 /* charge */
531 coeff_a = QPNP_COEFF_24;
532 coeff_b = -QPNP_COEFF_22;
533 } else {
534 coeff_a = QPNP_COEFF_24;
535 coeff_b = -QPNP_COEFF_23;
536 }
537 }
538 break;
539 }
540 break;
541 default:
542 case QPNP_IADC_REV_ID_8026_2_0:
543 /* pm8026 rev 1.0 */
544 coeff_a = 0;
545 coeff_b = 0;
546 break;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700547 }
548
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700549 temp_var = (coeff_a * die_temp) + coeff_b;
550 temp_var = div64_s64(temp_var, QPNP_COEFF_4);
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700551 temp_var = 1000 * (1000000 - temp_var);
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700552
553 if (!iadc->iadc_comp.ext_rsense) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700554 /* internal rsense */
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700555 *result = div64_s64(*result * 1000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700556 }
557
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700558 if (iadc->iadc_comp.ext_rsense) {
559 /* external rsense */
560 sys_gain_coeff = (1000000 +
561 div64_s64(sys_gain_coeff, QPNP_COEFF_4));
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700562 temp_var = div64_s64(temp_var * sys_gain_coeff, 1000000);
Siddartha Mohanadoss54bbfce2013-08-21 22:02:51 -0700563 *result = div64_s64(*result * 1000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700564 }
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700565 pr_debug("%lld compensated into %lld\n", old, *result);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700566
567 return 0;
568}
569
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700570int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc, int64_t *result)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700571{
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700572 return qpnp_iadc_comp(result, iadc, iadc->die_temp);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700573}
574EXPORT_SYMBOL(qpnp_iadc_comp_result);
575
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700576static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700577{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700578 int rc = 0;
579
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700580 rc = qpnp_iadc_read_reg(iadc, QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700581 if (rc < 0) {
582 pr_err("qpnp adc comp id failed with %d\n", rc);
583 return rc;
584 }
585
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700586 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2,
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700587 &iadc->iadc_comp.revision_dig_major);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700588 if (rc < 0) {
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700589 pr_err("qpnp adc revision2 read failed with %d\n", rc);
590 return rc;
591 }
592
593 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION3,
594 &iadc->iadc_comp.revision_ana_minor);
595 if (rc < 0) {
596 pr_err("qpnp adc revision3 read failed with %d\n", rc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700597 return rc;
598 }
599
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700600 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700601 &iadc->iadc_comp.sys_gain);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700602 if (rc < 0) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700603 pr_err("full scale read failed with %d\n", rc);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700604 return rc;
605 }
606
607 if (iadc->external_rsense)
608 iadc->iadc_comp.ext_rsense = true;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700609
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700610 pr_debug("fab id = %u, revision_dig_major = %u, revision_ana_minor = %u sys gain = %u, external_rsense = %d\n",
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700611 iadc->iadc_comp.id,
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700612 iadc->iadc_comp.revision_dig_major,
613 iadc->iadc_comp.revision_ana_minor,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700614 iadc->iadc_comp.sys_gain,
615 iadc->iadc_comp.ext_rsense);
616 return rc;
617}
618
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700619static int32_t qpnp_iadc_configure(struct qpnp_iadc_chip *iadc,
620 enum qpnp_iadc_channels channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800621 uint16_t *raw_code, uint32_t mode_sel)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700622{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700623 u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
624 u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700625 u8 status1 = 0;
626 uint32_t count = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700627 int32_t rc = 0;
628
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700629 qpnp_iadc_ch_sel_reg = channel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700630
631 qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
632 QPNP_IADC_DEC_RATIO_SEL;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800633 if (iadc->iadc_mode_sel)
634 qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN);
635 else
636 qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
637
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700638 qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
639
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700640 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700641 if (rc) {
642 pr_err("qpnp adc read adc failed with %d\n", rc);
643 return rc;
644 }
645
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700646 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_ADC_CH_SEL_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700647 qpnp_iadc_ch_sel_reg);
648 if (rc) {
649 pr_err("qpnp adc read adc failed with %d\n", rc);
650 return rc;
651 }
652
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700653 rc = qpnp_iadc_write_reg(iadc, QPNP_ADC_DIG_PARAM,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700654 qpnp_iadc_dig_param_reg);
655 if (rc) {
656 pr_err("qpnp adc read adc failed with %d\n", rc);
657 return rc;
658 }
659
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700660 rc = qpnp_iadc_write_reg(iadc, QPNP_HW_SETTLE_DELAY,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700661 iadc->adc->amux_prop->hw_settle_time);
662 if (rc < 0) {
663 pr_err("qpnp adc configure error for hw settling time setup\n");
664 return rc;
665 }
666
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700667 rc = qpnp_iadc_write_reg(iadc, QPNP_FAST_AVG_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700668 iadc->adc->amux_prop->fast_avg_setup);
669 if (rc < 0) {
670 pr_err("qpnp adc fast averaging configure error\n");
671 return rc;
672 }
673
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700674 if (!iadc->iadc_poll_eoc)
675 INIT_COMPLETION(iadc->adc->adc_rslt_completion);
Siddartha Mohanadoss3f219c42013-04-02 11:01:28 -0700676
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700677 rc = qpnp_iadc_enable(iadc, true);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700678 if (rc)
679 return rc;
680
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700681 rc = qpnp_iadc_write_reg(iadc, QPNP_CONV_REQ, qpnp_iadc_conv_req);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700682 if (rc) {
683 pr_err("qpnp adc read adc failed with %d\n", rc);
684 return rc;
685 }
686
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700687 if (iadc->iadc_poll_eoc) {
688 while (status1 != QPNP_STATUS1_EOC) {
689 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
690 if (rc < 0)
691 return rc;
692 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
693 usleep_range(QPNP_ADC_CONV_TIME_MIN,
694 QPNP_ADC_CONV_TIME_MAX);
695 count++;
696 if (count > QPNP_ADC_ERR_COUNT) {
697 pr_err("retry error exceeded\n");
698 rc = qpnp_iadc_status_debug(iadc);
699 if (rc < 0)
700 pr_err("IADC status debug failed\n");
701 rc = -EINVAL;
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800702 return rc;
703 }
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700704 }
705 } else {
706 rc = wait_for_completion_timeout(
707 &iadc->adc->adc_rslt_completion,
708 QPNP_ADC_COMPLETION_TIMEOUT);
709 if (!rc) {
710 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
711 if (rc < 0)
712 return rc;
713 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
714 if (status1 == QPNP_STATUS1_EOC)
715 pr_debug("End of conversion status set\n");
716 else {
717 rc = qpnp_iadc_status_debug(iadc);
718 if (rc < 0) {
719 pr_err("status debug failed %d\n", rc);
720 return rc;
721 }
722 return -EINVAL;
723 }
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700724 }
725 }
726
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700727 rc = qpnp_iadc_read_conversion_result(iadc, raw_code);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700728 if (rc) {
729 pr_err("qpnp adc read adc failed with %d\n", rc);
730 return rc;
731 }
732
733 return 0;
734}
735
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700736#define IADC_CENTER 0xC000
737#define IADC_READING_RESOLUTION_N 542535
738#define IADC_READING_RESOLUTION_D 100000
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700739static int32_t qpnp_convert_raw_offset_voltage(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700740{
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700741 s64 numerator;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700742
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800743 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
744 pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
745 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
746 return -EINVAL;
747 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700748
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700749 numerator = iadc->adc->calib.offset_raw - IADC_CENTER;
750 numerator *= IADC_READING_RESOLUTION_N;
751 iadc->adc->calib.offset_uv = div_s64(numerator,
752 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700753
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700754 numerator = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
755 numerator *= IADC_READING_RESOLUTION_N;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700756
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700757 iadc->adc->calib.gain_uv = div_s64(numerator,
758 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700759
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700760 pr_debug("gain_uv:%d offset_uv:%d\n",
761 iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700762 return 0;
763}
764
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700765#define IADC_IDEAL_RAW_GAIN 3291
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700766int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
767 bool batfet_closed)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700768{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700769 uint8_t rslt_lsb, rslt_msb;
770 int32_t rc = 0;
771 uint16_t raw_data;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800772 uint32_t mode_sel = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700773
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700774 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700775 return -EPROBE_DEFER;
776
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800777 mutex_lock(&iadc->adc->adc_lock);
778
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700779 if (iadc->iadc_poll_eoc) {
780 pr_debug("acquiring iadc eoc wakelock\n");
781 pm_stay_awake(iadc->dev);
782 }
783
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700784 rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800785 &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700786 if (rc < 0) {
787 pr_err("qpnp adc result read failed with %d\n", rc);
788 goto fail;
789 }
790
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700791 iadc->adc->calib.gain_raw = raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700792
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700793 /*
794 * there is a features in the BMS where if the batfet is opened
795 * the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
796 * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
797 * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
798 * internal rsense.
799 */
800 if (!batfet_closed || iadc->external_rsense) {
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700801 /* external offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700802 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800803 &raw_data, mode_sel);
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700804 if (rc < 0) {
805 pr_err("qpnp adc result read failed with %d\n", rc);
806 goto fail;
807 }
808 } else {
809 /* internal offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700810 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2,
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700811 &raw_data, mode_sel);
812 if (rc < 0) {
813 pr_err("qpnp adc result read failed with %d\n", rc);
814 goto fail;
815 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700816 }
817
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700818 iadc->adc->calib.offset_raw = raw_data;
819 if (rc < 0) {
820 pr_err("qpnp adc offset/gain calculation failed\n");
821 goto fail;
822 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700823
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700824 if (iadc->iadc_comp.revision_dig_major == QPNP_IADC_PM8026_2_REV2
825 && iadc->iadc_comp.revision_ana_minor ==
826 QPNP_IADC_PM8026_2_REV3)
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700827 iadc->adc->calib.gain_raw =
828 iadc->adc->calib.offset_raw + IADC_IDEAL_RAW_GAIN;
829
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700830 pr_debug("raw gain:0x%x, raw offset:0x%x\n",
831 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
832
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700833 rc = qpnp_convert_raw_offset_voltage(iadc);
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800834 if (rc < 0) {
835 pr_err("qpnp raw_voltage conversion failed\n");
836 goto fail;
837 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700838
839 rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
840 QPNP_BIT_SHIFT_8;
841 rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
842
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700843 pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
844
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700845 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700846 QPNP_IADC_SEC_ACCESS_DATA);
847 if (rc < 0) {
848 pr_err("qpnp iadc configure error for sec access\n");
849 goto fail;
850 }
851
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700852 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700853 rslt_msb);
854 if (rc < 0) {
855 pr_err("qpnp iadc configure error for MSB write\n");
856 goto fail;
857 }
858
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700859 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700860 QPNP_IADC_SEC_ACCESS_DATA);
861 if (rc < 0) {
862 pr_err("qpnp iadc configure error for sec access\n");
863 goto fail;
864 }
865
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700866 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700867 rslt_lsb);
868 if (rc < 0) {
869 pr_err("qpnp iadc configure error for LSB write\n");
870 goto fail;
871 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700872fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700873 if (iadc->iadc_poll_eoc) {
874 pr_debug("releasing iadc eoc wakelock\n");
875 pm_relax(iadc->dev);
876 }
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800877 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700878 return rc;
879}
Siddartha Mohanadoss06673922013-03-27 11:14:19 -0700880EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700881
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700882static void qpnp_iadc_work(struct work_struct *work)
883{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700884 struct qpnp_iadc_chip *iadc = container_of(work,
885 struct qpnp_iadc_chip, iadc_work.work);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700886 int rc = 0;
887
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700888 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700889 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700890 if (rc)
891 pr_debug("periodic IADC calibration failed\n");
892 }
893
894 schedule_delayed_work(&iadc->iadc_work,
895 round_jiffies_relative(msecs_to_jiffies
896 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700897 return;
898}
899
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700900static int32_t qpnp_iadc_version_check(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700901{
902 uint8_t revision;
903 int rc;
904
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700905 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &revision);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700906 if (rc < 0) {
907 pr_err("qpnp adc result read failed with %d\n", rc);
908 return rc;
909 }
910
911 if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
912 pr_err("IADC Version not supported\n");
913 return -EINVAL;
914 }
915
916 return 0;
917}
918
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700919struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700920{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700921 struct qpnp_iadc_chip *iadc;
922 struct device_node *node = NULL;
923 char prop_name[QPNP_MAX_PROP_NAME_LEN];
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700924
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700925 snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-iadc", name);
926
927 node = of_parse_phandle(dev->of_node, prop_name, 0);
928 if (node == NULL)
929 return ERR_PTR(-ENODEV);
930
931 list_for_each_entry(iadc, &qpnp_iadc_device_list, list)
932 if (iadc->adc->spmi->dev.of_node == node)
933 return iadc;
934 return ERR_PTR(-EPROBE_DEFER);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700935}
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700936EXPORT_SYMBOL(qpnp_get_iadc);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700937
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700938int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700939{
940 uint8_t rslt_rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700941 int32_t rc = 0, sign_bit = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700942
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700943 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800944 return -EPROBE_DEFER;
945
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700946 if (iadc->external_rsense) {
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700947 *rsense = iadc->rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700948 return rc;
949 }
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700950
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700951 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700952 if (rc < 0) {
953 pr_err("qpnp adc rsense read failed with %d\n", rc);
954 return rc;
955 }
956
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700957 pr_debug("rsense:0%x\n", rslt_rsense);
958
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700959 if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
960 sign_bit = 1;
961
962 rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
963
964 if (sign_bit)
965 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
966 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
967 else
968 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
969 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
970
971 return rc;
972}
Xiaozhe Shi767fdb62013-01-10 15:09:08 -0800973EXPORT_SYMBOL(qpnp_iadc_get_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700974
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700975static int32_t qpnp_check_pmic_temp(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700976{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700977 struct qpnp_vadc_result result_pmic_therm;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700978 int64_t die_temp_offset;
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800979 int rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700980
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700981 rc = qpnp_vadc_read(iadc->vadc_dev, DIE_TEMP, &result_pmic_therm);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700982 if (rc < 0)
983 return rc;
984
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700985 die_temp_offset = result_pmic_therm.physical -
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700986 iadc->die_temp;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700987 if (die_temp_offset < 0)
988 die_temp_offset = -die_temp_offset;
989
990 if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700991 iadc->die_temp = result_pmic_therm.physical;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700992 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700993 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700994 if (rc)
995 pr_err("IADC calibration failed rc = %d\n", rc);
996 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700997 }
998
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800999 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001000}
1001
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001002int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
1003 enum qpnp_iadc_channels channel,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001004 struct qpnp_iadc_result *result)
1005{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001006 int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001007 int32_t rsense_u_ohms = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001008 int64_t result_current;
1009 uint16_t raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001010
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001011 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001012 return -EPROBE_DEFER;
1013
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001014 rc = qpnp_check_pmic_temp(iadc);
1015 if (rc) {
1016 pr_err("Error checking pmic therm temp\n");
1017 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001018 }
1019
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001020 mutex_lock(&iadc->adc->adc_lock);
1021
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001022 if (iadc->iadc_poll_eoc) {
1023 pr_debug("acquiring iadc eoc wakelock\n");
1024 pm_stay_awake(iadc->dev);
1025 }
1026
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001027 rc = qpnp_iadc_configure(iadc, channel, &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001028 if (rc < 0) {
1029 pr_err("qpnp adc result read failed with %d\n", rc);
1030 goto fail;
1031 }
1032
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001033 rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001034 pr_debug("current raw:0%x and rsense:%d\n",
1035 raw_data, rsense_n_ohms);
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001036 rsense_u_ohms = rsense_n_ohms/1000;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001037 num = raw_data - iadc->adc->calib.offset_raw;
1038 if (num < 0) {
1039 sign = 1;
1040 num = -num;
1041 }
1042
1043 result->result_uv = (num * QPNP_ADC_GAIN_NV)/
1044 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
1045 result_current = result->result_uv;
1046 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001047 /* Intentional fall through. Process the result w/o comp */
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001048 do_div(result_current, rsense_u_ohms);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001049
1050 if (sign) {
1051 result->result_uv = -result->result_uv;
1052 result_current = -result_current;
1053 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001054 rc = qpnp_iadc_comp_result(iadc, &result_current);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001055 if (rc < 0)
1056 pr_err("Error during compensating the IADC\n");
1057 rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001058
1059 result->result_ua = (int32_t) result_current;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001060fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001061 if (iadc->iadc_poll_eoc) {
1062 pr_debug("releasing iadc eoc wakelock\n");
1063 pm_relax(iadc->dev);
1064 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001065 mutex_unlock(&iadc->adc->adc_lock);
1066
1067 return rc;
1068}
1069EXPORT_SYMBOL(qpnp_iadc_read);
1070
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001071int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
1072 struct qpnp_iadc_calib *result)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001073{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001074 int rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001075
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001076 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001077 return -EPROBE_DEFER;
1078
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001079 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001080 if (rc) {
1081 pr_err("Error checking pmic therm temp\n");
1082 return rc;
1083 }
1084
1085 mutex_lock(&iadc->adc->adc_lock);
1086 result->gain_raw = iadc->adc->calib.gain_raw;
1087 result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
1088 result->gain_uv = iadc->adc->calib.gain_uv;
1089 result->offset_raw = iadc->adc->calib.offset_raw;
1090 result->ideal_offset_uv =
1091 QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
1092 result->offset_uv = iadc->adc->calib.offset_uv;
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001093 pr_debug("raw gain:0%x, raw offset:0%x\n",
1094 result->gain_raw, result->offset_raw);
1095 pr_debug("gain_uv:%d offset_uv:%d\n",
1096 result->gain_uv, result->offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001097 mutex_unlock(&iadc->adc->adc_lock);
1098
1099 return 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001100}
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001101EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001102
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001103int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001104{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001105 iadc->skip_auto_calibrations = true;
1106 return 0;
1107}
1108EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
1109
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001110int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001111{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001112 iadc->skip_auto_calibrations = false;
1113 return 0;
1114}
1115EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
1116
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001117int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001118 enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
1119 enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
1120{
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001121 int rc = 0, mode_sel = 0, num = 0, rsense_n_ohms = 0, sign = 0;
1122 uint16_t raw_data;
1123 int32_t rsense_u_ohms = 0;
1124 int64_t result_current;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001125
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001126 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001127 return -EPROBE_DEFER;
1128
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001129 mutex_lock(&iadc->adc->adc_lock);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001130
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001131 if (iadc->iadc_poll_eoc) {
1132 pr_debug("acquiring iadc eoc wakelock\n");
1133 pm_stay_awake(iadc->dev);
1134 }
1135
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001136 iadc->iadc_mode_sel = true;
1137
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001138 rc = qpnp_vadc_iadc_sync_request(iadc->vadc_dev, v_channel);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001139 if (rc) {
1140 pr_err("Configuring VADC failed\n");
1141 goto fail;
1142 }
1143
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001144 rc = qpnp_iadc_configure(iadc, i_channel, &raw_data, mode_sel);
1145 if (rc < 0) {
1146 pr_err("qpnp adc result read failed with %d\n", rc);
1147 goto fail_release_vadc;
1148 }
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001149
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001150 rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
1151 pr_debug("current raw:0%x and rsense:%d\n",
1152 raw_data, rsense_n_ohms);
1153 rsense_u_ohms = rsense_n_ohms/1000;
1154 num = raw_data - iadc->adc->calib.offset_raw;
1155 if (num < 0) {
1156 sign = 1;
1157 num = -num;
1158 }
1159
1160 i_result->result_uv = (num * QPNP_ADC_GAIN_NV)/
1161 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
1162 result_current = i_result->result_uv;
1163 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
1164 /* Intentional fall through. Process the result w/o comp */
1165 do_div(result_current, rsense_u_ohms);
1166
1167 if (sign) {
1168 i_result->result_uv = -i_result->result_uv;
1169 result_current = -result_current;
1170 }
1171 result_current *= -1;
1172 rc = qpnp_iadc_comp_result(iadc, &result_current);
1173 if (rc < 0)
1174 pr_err("Error during compensating the IADC\n");
1175 rc = 0;
1176 result_current *= -1;
1177
1178 i_result->result_ua = (int32_t) result_current;
1179
1180fail_release_vadc:
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001181 rc = qpnp_vadc_iadc_sync_complete_request(iadc->vadc_dev, v_channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001182 v_result);
1183 if (rc)
1184 pr_err("Releasing VADC failed\n");
1185fail:
1186 iadc->iadc_mode_sel = false;
1187
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001188 if (iadc->iadc_poll_eoc) {
1189 pr_debug("releasing iadc eoc wakelock\n");
1190 pm_relax(iadc->dev);
1191 }
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001192 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001193
1194 return rc;
1195}
1196EXPORT_SYMBOL(qpnp_iadc_vadc_sync_read);
1197
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001198static ssize_t qpnp_iadc_show(struct device *dev,
1199 struct device_attribute *devattr, char *buf)
1200{
1201 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001202 struct qpnp_iadc_chip *iadc = dev_get_drvdata(dev);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001203 struct qpnp_iadc_result result;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001204 int rc = -1;
1205
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001206 rc = qpnp_iadc_read(iadc, attr->index, &result);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001207
1208 if (rc)
1209 return 0;
1210
1211 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001212 "Result:%d\n", result.result_ua);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001213}
1214
1215static struct sensor_device_attribute qpnp_adc_attr =
1216 SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
1217
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001218static int32_t qpnp_iadc_init_hwmon(struct qpnp_iadc_chip *iadc,
1219 struct spmi_device *spmi)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001220{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001221 struct device_node *child;
1222 struct device_node *node = spmi->dev.of_node;
1223 int rc = 0, i = 0, channel;
1224
1225 for_each_child_of_node(node, child) {
1226 channel = iadc->adc->adc_channels[i].channel_num;
1227 qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
1228 qpnp_adc_attr.dev_attr.attr.name =
1229 iadc->adc->adc_channels[i].name;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001230 memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
1231 sizeof(qpnp_adc_attr));
Stephen Boyd8a5c4e42012-10-30 11:07:22 -07001232 sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001233 rc = device_create_file(&spmi->dev,
1234 &iadc->sens_attr[i].dev_attr);
1235 if (rc) {
1236 dev_err(&spmi->dev,
1237 "device_create_file failed for dev %s\n",
1238 iadc->adc->adc_channels[i].name);
1239 goto hwmon_err_sens;
1240 }
1241 i++;
1242 }
1243
1244 return 0;
1245hwmon_err_sens:
1246 pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
1247 return rc;
1248}
1249
1250static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
1251{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001252 struct qpnp_iadc_chip *iadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001253 struct qpnp_adc_drv *adc_qpnp;
1254 struct device_node *node = spmi->dev.of_node;
1255 struct device_node *child;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001256 int rc, count_adc_channel_list = 0, i = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001257
1258 for_each_child_of_node(node, child)
1259 count_adc_channel_list++;
1260
1261 if (!count_adc_channel_list) {
1262 pr_err("No channel listing\n");
1263 return -EINVAL;
1264 }
1265
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001266 iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_chip) +
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001267 (sizeof(struct sensor_device_attribute) *
1268 count_adc_channel_list), GFP_KERNEL);
1269 if (!iadc) {
1270 dev_err(&spmi->dev, "Unable to allocate memory\n");
1271 return -ENOMEM;
1272 }
1273
1274 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1275 GFP_KERNEL);
1276 if (!adc_qpnp) {
1277 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossc61babb2013-08-02 13:37:12 -07001278 return -ENOMEM;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001279 }
1280
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001281 iadc->dev = &(spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001282 iadc->adc = adc_qpnp;
1283
1284 rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
1285 if (rc) {
1286 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossc61babb2013-08-02 13:37:12 -07001287 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001288 }
1289
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001290 iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
1291 if (IS_ERR(iadc->vadc_dev)) {
1292 rc = PTR_ERR(iadc->vadc_dev);
1293 if (rc != -EPROBE_DEFER)
1294 pr_err("vadc property missing, rc=%d\n", rc);
Siddartha Mohanadossc61babb2013-08-02 13:37:12 -07001295 return rc;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001296 }
1297
Stephen Boydbeab4502013-04-25 10:18:17 -07001298 mutex_init(&iadc->adc->adc_lock);
1299
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001300 rc = of_property_read_u32(node, "qcom,rsense",
1301 &iadc->rsense);
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -07001302 if (rc)
1303 pr_debug("Defaulting to internal rsense\n");
1304 else {
1305 pr_debug("Use external rsense\n");
1306 iadc->external_rsense = true;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001307 }
1308
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001309 iadc->iadc_poll_eoc = of_property_read_bool(node,
1310 "qcom,iadc-poll-eoc");
1311 if (!iadc->iadc_poll_eoc) {
1312 rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
1313 qpnp_iadc_isr, IRQF_TRIGGER_RISING,
1314 "qpnp_iadc_interrupt", iadc);
1315 if (rc) {
1316 dev_err(&spmi->dev, "failed to request adc irq\n");
1317 return rc;
1318 } else
1319 enable_irq_wake(iadc->adc->adc_irq_eoc);
1320 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001321
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001322 rc = qpnp_iadc_init_hwmon(iadc, spmi);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001323 if (rc) {
1324 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001325 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001326 }
1327 iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
1328
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001329 rc = qpnp_iadc_version_check(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001330 if (rc) {
1331 dev_err(&spmi->dev, "IADC version not supported\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001332 goto fail;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001333 }
1334
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001335 INIT_WORK(&iadc->trigger_completion_work, qpnp_iadc_trigger_completion);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001336 INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001337 rc = qpnp_iadc_comp_info(iadc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001338 if (rc) {
1339 dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
1340 goto fail;
1341 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001342
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001343 dev_set_drvdata(&spmi->dev, iadc);
1344 list_add(&iadc->list, &qpnp_iadc_device_list);
1345 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001346 if (rc)
1347 dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001348
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001349 if (iadc->iadc_poll_eoc)
1350 device_init_wakeup(iadc->dev, 1);
1351
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001352 schedule_delayed_work(&iadc->iadc_work,
1353 round_jiffies_relative(msecs_to_jiffies
1354 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001355 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001356fail:
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001357 for_each_child_of_node(node, child) {
1358 device_remove_file(&spmi->dev,
1359 &iadc->sens_attr[i].dev_attr);
1360 i++;
1361 }
1362 hwmon_device_unregister(iadc->iadc_hwmon);
1363
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001364 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001365}
1366
1367static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
1368{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001369 struct qpnp_iadc_chip *iadc = dev_get_drvdata(&spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001370 struct device_node *node = spmi->dev.of_node;
1371 struct device_node *child;
1372 int i = 0;
1373
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001374 cancel_delayed_work(&iadc->iadc_work);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001375 for_each_child_of_node(node, child) {
1376 device_remove_file(&spmi->dev,
1377 &iadc->sens_attr[i].dev_attr);
1378 i++;
1379 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001380 hwmon_device_unregister(iadc->iadc_hwmon);
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001381 if (iadc->iadc_poll_eoc)
1382 pm_relax(iadc->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001383 dev_set_drvdata(&spmi->dev, NULL);
1384
1385 return 0;
1386}
1387
1388static const struct of_device_id qpnp_iadc_match_table[] = {
1389 { .compatible = "qcom,qpnp-iadc",
1390 },
1391 {}
1392};
1393
1394static struct spmi_driver qpnp_iadc_driver = {
1395 .driver = {
1396 .name = "qcom,qpnp-iadc",
1397 .of_match_table = qpnp_iadc_match_table,
1398 },
1399 .probe = qpnp_iadc_probe,
1400 .remove = qpnp_iadc_remove,
1401};
1402
1403static int __init qpnp_iadc_init(void)
1404{
1405 return spmi_driver_register(&qpnp_iadc_driver);
1406}
1407module_init(qpnp_iadc_init);
1408
1409static void __exit qpnp_iadc_exit(void)
1410{
1411 spmi_driver_unregister(&qpnp_iadc_driver);
1412}
1413module_exit(qpnp_iadc_exit);
1414
1415MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
1416MODULE_LICENSE("GPL v2");