blob: ec6d8ecf498f2677946dfbe8f32fbb0aae4d35fa [file] [log] [blame]
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001/* Copyright (c) 2012-2014, 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 Mohanadoss18c4b9f2014-01-23 16:13:31 -0800132#define SMBB_BAT_IF_TRIM_CNST_RDS_MASK 0x7
133#define SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST 2
134#define QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST 127
135#define QPNP_IADC_RSENSE_DEFAULT_VALUE 7800000
136#define QPNP_IADC_RSENSE_DEFAULT_TYPEB_GF 9000000
137#define QPNP_IADC_RSENSE_DEFAULT_TYPEB_SMIC 9700000
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700138
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700139struct qpnp_iadc_comp {
140 bool ext_rsense;
141 u8 id;
142 u8 sys_gain;
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700143 u8 revision_dig_major;
144 u8 revision_ana_minor;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700145};
146
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700147struct qpnp_iadc_chip {
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700148 struct device *dev;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700149 struct qpnp_adc_drv *adc;
150 int32_t rsense;
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700151 bool external_rsense;
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800152 bool default_internal_rsense;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700153 struct device *iadc_hwmon;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700154 struct list_head list;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700155 int64_t die_temp;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700156 struct delayed_work iadc_work;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800157 bool iadc_mode_sel;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700158 struct qpnp_iadc_comp iadc_comp;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700159 struct qpnp_vadc_chip *vadc_dev;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700160 struct work_struct trigger_completion_work;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700161 bool skip_auto_calibrations;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700162 bool iadc_poll_eoc;
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800163 u16 batt_id_trim_cnst_rds;
164 int rds_trim_default_type;
165 bool rds_trim_default_check;
166 int32_t rsense_workaround_value;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700167 struct sensor_device_attribute sens_attr[0];
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700168};
169
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700170LIST_HEAD(qpnp_iadc_device_list);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700171
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800172enum qpnp_iadc_rsense_rds_workaround {
173 QPNP_IADC_RDS_DEFAULT_TYPEA,
174 QPNP_IADC_RDS_DEFAULT_TYPEB,
175};
176
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700177static int32_t qpnp_iadc_read_reg(struct qpnp_iadc_chip *iadc,
178 uint32_t reg, u8 *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700179{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700180 int rc;
181
182 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700183 (iadc->adc->offset + reg), data, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700184 if (rc < 0) {
185 pr_err("qpnp iadc read reg %d failed with %d\n", reg, rc);
186 return rc;
187 }
188
189 return 0;
190}
191
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700192static int32_t qpnp_iadc_write_reg(struct qpnp_iadc_chip *iadc,
193 uint32_t reg, u8 data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700194{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700195 int rc;
196 u8 *buf;
197
198 buf = &data;
199 rc = spmi_ext_register_writel(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700200 (iadc->adc->offset + reg), buf, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700201 if (rc < 0) {
202 pr_err("qpnp iadc write reg %d failed with %d\n", reg, rc);
203 return rc;
204 }
205
206 return 0;
207}
208
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700209static int qpnp_iadc_is_valid(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800210{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700211 struct qpnp_iadc_chip *iadc_chip = NULL;
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800212
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700213 list_for_each_entry(iadc_chip, &qpnp_iadc_device_list, list)
214 if (iadc == iadc_chip)
215 return 0;
216
217 return -EINVAL;
218}
219
220static void qpnp_iadc_trigger_completion(struct work_struct *work)
221{
222 struct qpnp_iadc_chip *iadc = container_of(work,
223 struct qpnp_iadc_chip, trigger_completion_work);
224
225 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800226 return;
227
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800228 complete(&iadc->adc->adc_rslt_completion);
229
230 return;
231}
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800232
233static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
234{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700235 struct qpnp_iadc_chip *iadc = dev_id;
236
237 schedule_work(&iadc->trigger_completion_work);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800238
239 return IRQ_HANDLED;
240}
241
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700242static int32_t qpnp_iadc_enable(struct qpnp_iadc_chip *dev, bool state)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800243{
244 int rc = 0;
245 u8 data = 0;
246
247 data = QPNP_IADC_ADC_EN;
248 if (state) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700249 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800250 data);
251 if (rc < 0) {
252 pr_err("IADC enable failed\n");
253 return rc;
254 }
255 } else {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700256 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800257 (~data & QPNP_IADC_ADC_EN));
258 if (rc < 0) {
259 pr_err("IADC disable failed\n");
260 return rc;
261 }
262 }
263
264 return 0;
265}
266
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700267static int32_t qpnp_iadc_status_debug(struct qpnp_iadc_chip *dev)
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800268{
269 int rc = 0;
270 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
271
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700272 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_MODE_CTL, &mode);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800273 if (rc < 0) {
274 pr_err("mode ctl register read failed with %d\n", rc);
275 return rc;
276 }
277
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700278 rc = qpnp_iadc_read_reg(dev, QPNP_ADC_DIG_PARAM, &dig);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800279 if (rc < 0) {
280 pr_err("digital param read failed with %d\n", rc);
281 return rc;
282 }
283
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700284 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_ADC_CH_SEL_CTL, &chan);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800285 if (rc < 0) {
286 pr_err("channel read failed with %d\n", rc);
287 return rc;
288 }
289
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700290 rc = qpnp_iadc_read_reg(dev, QPNP_STATUS1, &status1);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800291 if (rc < 0) {
292 pr_err("status1 read failed with %d\n", rc);
293 return rc;
294 }
295
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700296 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_EN_CTL1, &en);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800297 if (rc < 0) {
298 pr_err("en read failed with %d\n", rc);
299 return rc;
300 }
301
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700302 pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800303 status1, dig, chan, mode, en);
304
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700305 rc = qpnp_iadc_enable(dev, false);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800306 if (rc < 0) {
307 pr_err("IADC disable failed with %d\n", rc);
308 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700309 }
310
311 return 0;
312}
313
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700314static int32_t qpnp_iadc_read_conversion_result(struct qpnp_iadc_chip *iadc,
315 int16_t *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700316{
317 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700318 uint16_t rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700319 int32_t rc;
320
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700321 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA0, &rslt_lsb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700322 if (rc < 0) {
323 pr_err("qpnp adc result read failed with %d\n", rc);
324 return rc;
325 }
326
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700327 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA1, &rslt_msb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700328 if (rc < 0) {
329 pr_err("qpnp adc result read failed with %d\n", rc);
330 return rc;
331 }
332
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700333 rslt = (rslt_msb << 8) | rslt_lsb;
334 *data = rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700335
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700336 rc = qpnp_iadc_enable(iadc, false);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700337 if (rc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700338 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700339
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700340 return 0;
341}
342
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700343#define QPNP_IADC_PM8026_2_REV2 4
344#define QPNP_IADC_PM8026_2_REV3 2
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700345
346#define QPNP_COEFF_1 969000
347#define QPNP_COEFF_2 32
348#define QPNP_COEFF_3_TYPEA 1700000
349#define QPNP_COEFF_3_TYPEB 1000000
350#define QPNP_COEFF_4 100
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700351#define QPNP_COEFF_5 15
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700352#define QPNP_COEFF_6 100000
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700353#define QPNP_COEFF_7 21
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700354#define QPNP_COEFF_8 100000000
355#define QPNP_COEFF_9 38
356#define QPNP_COEFF_10 40
357#define QPNP_COEFF_11 7
358#define QPNP_COEFF_12 11
359#define QPNP_COEFF_13 37
360#define QPNP_COEFF_14 39
361#define QPNP_COEFF_15 9
362#define QPNP_COEFF_16 11
363#define QPNP_COEFF_17 851200
364#define QPNP_COEFF_18 296500
365#define QPNP_COEFF_19 222400
366#define QPNP_COEFF_20 813800
367#define QPNP_COEFF_21 1059100
368#define QPNP_COEFF_22 5000000
369#define QPNP_COEFF_23 3722500
370#define QPNP_COEFF_24 84
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700371#define QPNP_COEFF_25 33
372#define QPNP_COEFF_26 22
Xiaozhe Shi80754222013-10-30 14:11:41 -0700373#define QPNP_COEFF_27 53
374#define QPNP_COEFF_28 48
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700375
376static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700377 int64_t die_temp)
378{
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700379 int64_t temp_var = 0, sys_gain_coeff = 0, old;
380 int32_t coeff_a = 0, coeff_b = 0;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700381 int version = 0;
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700382
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700383 version = qpnp_adc_get_revid_version(iadc->dev);
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700384 if (version == -EINVAL)
385 return 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700386
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700387 old = *result;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700388 *result = *result * 1000000;
389
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700390 if (iadc->iadc_comp.sys_gain > 127)
391 sys_gain_coeff = -QPNP_COEFF_6 *
392 (iadc->iadc_comp.sys_gain - 128);
393 else
394 sys_gain_coeff = QPNP_COEFF_6 *
395 iadc->iadc_comp.sys_gain;
396
397 switch (version) {
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700398 case QPNP_REV_ID_8941_3_1:
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700399 switch (iadc->iadc_comp.id) {
400 case COMP_ID_GF:
401 if (!iadc->iadc_comp.ext_rsense) {
402 /* internal rsense */
403 coeff_a = QPNP_COEFF_2;
404 coeff_b = -QPNP_COEFF_3_TYPEA;
405 } else {
406 if (*result < 0) {
407 /* charge */
408 coeff_a = QPNP_COEFF_5;
409 coeff_b = QPNP_COEFF_6;
410 } else {
411 /* discharge */
412 coeff_a = -QPNP_COEFF_7;
413 coeff_b = QPNP_COEFF_6;
414 }
415 }
416 break;
417 case COMP_ID_TSMC:
418 default:
419 if (!iadc->iadc_comp.ext_rsense) {
420 /* internal rsense */
421 coeff_a = QPNP_COEFF_2;
422 coeff_b = -QPNP_COEFF_3_TYPEB;
423 } else {
424 if (*result < 0) {
425 /* charge */
426 coeff_a = QPNP_COEFF_5;
427 coeff_b = QPNP_COEFF_6;
428 } else {
429 /* discharge */
430 coeff_a = -QPNP_COEFF_7;
431 coeff_b = QPNP_COEFF_6;
432 }
433 }
434 break;
435 }
436 break;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700437 case QPNP_REV_ID_8026_2_1:
Siddartha Mohanadoss68b4e082014-01-28 10:53:13 -0800438 case QPNP_REV_ID_8026_2_2:
439 /* pm8026 rev 2.1 and 2.2 */
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700440 switch (iadc->iadc_comp.id) {
441 case COMP_ID_GF:
442 if (!iadc->iadc_comp.ext_rsense) {
443 /* internal rsense */
444 if (*result < 0) {
445 /* charge */
446 coeff_a = 0;
447 coeff_b = 0;
448 } else {
449 coeff_a = QPNP_COEFF_25;
450 coeff_b = 0;
451 }
452 } else {
453 if (*result < 0) {
454 /* charge */
455 coeff_a = 0;
456 coeff_b = 0;
457 } else {
458 /* discharge */
459 coeff_a = 0;
460 coeff_b = 0;
461 }
462 }
463 break;
464 case COMP_ID_TSMC:
465 default:
466 if (!iadc->iadc_comp.ext_rsense) {
467 /* internal rsense */
468 if (*result < 0) {
469 /* charge */
470 coeff_a = 0;
471 coeff_b = 0;
472 } else {
473 coeff_a = QPNP_COEFF_26;
474 coeff_b = 0;
475 }
476 } else {
477 if (*result < 0) {
478 /* charge */
479 coeff_a = 0;
480 coeff_b = 0;
481 } else {
482 /* discharge */
483 coeff_a = 0;
484 coeff_b = 0;
485 }
486 }
487 break;
488 }
489 break;
490 case QPNP_REV_ID_8026_1_0:
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700491 /* pm8026 rev 1.0 */
492 switch (iadc->iadc_comp.id) {
493 case COMP_ID_GF:
494 if (!iadc->iadc_comp.ext_rsense) {
495 /* internal rsense */
496 if (*result < 0) {
497 /* charge */
498 coeff_a = QPNP_COEFF_9;
499 coeff_b = -QPNP_COEFF_17;
500 } else {
501 coeff_a = QPNP_COEFF_10;
502 coeff_b = QPNP_COEFF_18;
503 }
504 } else {
505 if (*result < 0) {
506 /* charge */
507 coeff_a = -QPNP_COEFF_11;
508 coeff_b = 0;
509 } else {
510 /* discharge */
511 coeff_a = -QPNP_COEFF_17;
512 coeff_b = -QPNP_COEFF_19;
513 }
514 }
515 break;
516 case COMP_ID_TSMC:
517 default:
518 if (!iadc->iadc_comp.ext_rsense) {
519 /* internal rsense */
520 if (*result < 0) {
521 /* charge */
522 coeff_a = QPNP_COEFF_13;
523 coeff_b = -QPNP_COEFF_20;
524 } else {
525 coeff_a = QPNP_COEFF_14;
526 coeff_b = QPNP_COEFF_21;
527 }
528 } else {
529 if (*result < 0) {
530 /* charge */
531 coeff_a = -QPNP_COEFF_15;
532 coeff_b = 0;
533 } else {
534 /* discharge */
535 coeff_a = -QPNP_COEFF_12;
536 coeff_b = -QPNP_COEFF_19;
537 }
538 }
539 break;
540 }
541 break;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700542 case QPNP_REV_ID_8110_1_0:
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700543 /* pm8110 rev 1.0 */
544 switch (iadc->iadc_comp.id) {
545 case COMP_ID_GF:
546 if (!iadc->iadc_comp.ext_rsense) {
547 /* internal rsense */
548 if (*result < 0) {
549 /* charge */
550 coeff_a = QPNP_COEFF_24;
551 coeff_b = -QPNP_COEFF_22;
552 } else {
553 coeff_a = QPNP_COEFF_24;
554 coeff_b = -QPNP_COEFF_23;
555 }
556 }
557 break;
558 case COMP_ID_SMIC:
559 default:
560 if (!iadc->iadc_comp.ext_rsense) {
561 /* internal rsense */
562 if (*result < 0) {
563 /* charge */
564 coeff_a = QPNP_COEFF_24;
565 coeff_b = -QPNP_COEFF_22;
566 } else {
567 coeff_a = QPNP_COEFF_24;
568 coeff_b = -QPNP_COEFF_23;
569 }
570 }
571 break;
572 }
573 break;
Xiaozhe Shi80754222013-10-30 14:11:41 -0700574 case QPNP_REV_ID_8110_2_0:
575 die_temp -= 25000;
576 /* pm8110 rev 2.0 */
577 switch (iadc->iadc_comp.id) {
578 case COMP_ID_GF:
579 if (!iadc->iadc_comp.ext_rsense) {
580 /* internal rsense */
581 if (*result < 0) {
582 /* charge */
583 coeff_a = 0;
584 coeff_b = 0;
585 } else {
586 coeff_a = QPNP_COEFF_27;
587 coeff_b = 0;
588 }
589 }
590 break;
591 case COMP_ID_SMIC:
592 default:
593 if (!iadc->iadc_comp.ext_rsense) {
594 /* internal rsense */
595 if (*result < 0) {
596 /* charge */
597 coeff_a = 0;
598 coeff_b = 0;
599 } else {
600 coeff_a = QPNP_COEFF_28;
601 coeff_b = 0;
602 }
603 }
604 break;
605 }
606 break;
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700607 default:
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700608 case QPNP_REV_ID_8026_2_0:
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700609 /* pm8026 rev 1.0 */
610 coeff_a = 0;
611 coeff_b = 0;
612 break;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700613 }
614
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700615 temp_var = (coeff_a * die_temp) + coeff_b;
616 temp_var = div64_s64(temp_var, QPNP_COEFF_4);
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700617 temp_var = 1000 * (1000000 - temp_var);
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700618
619 if (!iadc->iadc_comp.ext_rsense) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700620 /* internal rsense */
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700621 *result = div64_s64(*result * 1000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700622 }
623
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700624 if (iadc->iadc_comp.ext_rsense) {
625 /* external rsense */
626 sys_gain_coeff = (1000000 +
627 div64_s64(sys_gain_coeff, QPNP_COEFF_4));
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700628 temp_var = div64_s64(temp_var * sys_gain_coeff, 1000000);
Siddartha Mohanadoss54bbfce2013-08-21 22:02:51 -0700629 *result = div64_s64(*result * 1000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700630 }
Xiaozhe Shi4e3a83c2013-12-02 15:30:56 -0800631 pr_debug("%lld compensated into %lld, a: %d, b: %d, sys_gain: %lld\n",
632 old, *result, coeff_a, coeff_b, sys_gain_coeff);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700633
634 return 0;
635}
636
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700637int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc, int64_t *result)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700638{
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700639 return qpnp_iadc_comp(result, iadc, iadc->die_temp);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700640}
641EXPORT_SYMBOL(qpnp_iadc_comp_result);
642
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800643static int qpnp_iadc_rds_trim_update_check(struct qpnp_iadc_chip *iadc)
644{
645 int rc = 0;
646 u8 trim2_val = 0, smbb_batt_trm_data = 0;
647
648 if (!iadc->rds_trim_default_check) {
649 pr_debug("No internal rds trim check needed\n");
650 return 0;
651 }
652
653 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &trim2_val);
654 if (rc < 0) {
655 pr_err("qpnp adc trim2_fullscale1 reg read failed %d\n", rc);
656 return rc;
657 }
658
659 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
660 iadc->batt_id_trim_cnst_rds, &smbb_batt_trm_data, 1);
661 if (rc < 0) {
662 pr_err("batt_id trim_cnst rds reg read failed %d\n", rc);
663 return rc;
664 }
665
666 pr_debug("n_trim:0x%x smb_trm:0x%x\n", trim2_val, smbb_batt_trm_data);
667
668 if (iadc->rds_trim_default_type == QPNP_IADC_RDS_DEFAULT_TYPEA) {
669 if (((smbb_batt_trm_data & SMBB_BAT_IF_TRIM_CNST_RDS_MASK) ==
670 SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST) &&
671 (trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
672 iadc->rsense_workaround_value =
673 QPNP_IADC_RSENSE_DEFAULT_VALUE;
674 iadc->default_internal_rsense = true;
675 }
676 } else if (iadc->rds_trim_default_type ==
677 QPNP_IADC_RDS_DEFAULT_TYPEB) {
678 if (((smbb_batt_trm_data & SMBB_BAT_IF_TRIM_CNST_RDS_MASK) >=
679 SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST) &&
680 (trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
681 iadc->rsense_workaround_value =
682 QPNP_IADC_RSENSE_DEFAULT_VALUE;
683 iadc->default_internal_rsense = true;
684 } else if (((smbb_batt_trm_data &
685 SMBB_BAT_IF_TRIM_CNST_RDS_MASK)
686 < SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST) &&
687 (trim2_val ==
688 QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
689 if (iadc->iadc_comp.id == COMP_ID_GF) {
690 iadc->rsense_workaround_value =
691 QPNP_IADC_RSENSE_DEFAULT_TYPEB_GF;
692 iadc->default_internal_rsense = true;
693 } else if (iadc->iadc_comp.id == COMP_ID_SMIC) {
694 iadc->rsense_workaround_value =
695 QPNP_IADC_RSENSE_DEFAULT_TYPEB_SMIC;
696 iadc->default_internal_rsense = true;
697 }
698 }
699 }
700
701 return 0;
702}
703
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700704static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700705{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700706 int rc = 0;
707
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700708 rc = qpnp_iadc_read_reg(iadc, QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700709 if (rc < 0) {
710 pr_err("qpnp adc comp id failed with %d\n", rc);
711 return rc;
712 }
713
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700714 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2,
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700715 &iadc->iadc_comp.revision_dig_major);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700716 if (rc < 0) {
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700717 pr_err("qpnp adc revision2 read failed with %d\n", rc);
718 return rc;
719 }
720
721 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION3,
722 &iadc->iadc_comp.revision_ana_minor);
723 if (rc < 0) {
724 pr_err("qpnp adc revision3 read failed with %d\n", rc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700725 return rc;
726 }
727
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700728 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700729 &iadc->iadc_comp.sys_gain);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700730 if (rc < 0) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700731 pr_err("full scale read failed with %d\n", rc);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700732 return rc;
733 }
734
735 if (iadc->external_rsense)
736 iadc->iadc_comp.ext_rsense = true;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700737
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700738 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 -0700739 iadc->iadc_comp.id,
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700740 iadc->iadc_comp.revision_dig_major,
741 iadc->iadc_comp.revision_ana_minor,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700742 iadc->iadc_comp.sys_gain,
743 iadc->iadc_comp.ext_rsense);
744 return rc;
745}
746
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700747static int32_t qpnp_iadc_configure(struct qpnp_iadc_chip *iadc,
748 enum qpnp_iadc_channels channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800749 uint16_t *raw_code, uint32_t mode_sel)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700750{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700751 u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
752 u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700753 u8 status1 = 0;
754 uint32_t count = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700755 int32_t rc = 0;
756
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700757 qpnp_iadc_ch_sel_reg = channel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700758
759 qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
760 QPNP_IADC_DEC_RATIO_SEL;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800761 if (iadc->iadc_mode_sel)
762 qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN);
763 else
764 qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
765
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700766 qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
767
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700768 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700769 if (rc) {
770 pr_err("qpnp adc read adc failed with %d\n", rc);
771 return rc;
772 }
773
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700774 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_ADC_CH_SEL_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700775 qpnp_iadc_ch_sel_reg);
776 if (rc) {
777 pr_err("qpnp adc read adc failed with %d\n", rc);
778 return rc;
779 }
780
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700781 rc = qpnp_iadc_write_reg(iadc, QPNP_ADC_DIG_PARAM,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700782 qpnp_iadc_dig_param_reg);
783 if (rc) {
784 pr_err("qpnp adc read adc failed with %d\n", rc);
785 return rc;
786 }
787
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700788 rc = qpnp_iadc_write_reg(iadc, QPNP_HW_SETTLE_DELAY,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700789 iadc->adc->amux_prop->hw_settle_time);
790 if (rc < 0) {
791 pr_err("qpnp adc configure error for hw settling time setup\n");
792 return rc;
793 }
794
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700795 rc = qpnp_iadc_write_reg(iadc, QPNP_FAST_AVG_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700796 iadc->adc->amux_prop->fast_avg_setup);
797 if (rc < 0) {
798 pr_err("qpnp adc fast averaging configure error\n");
799 return rc;
800 }
801
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700802 if (!iadc->iadc_poll_eoc)
803 INIT_COMPLETION(iadc->adc->adc_rslt_completion);
Siddartha Mohanadoss3f219c42013-04-02 11:01:28 -0700804
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700805 rc = qpnp_iadc_enable(iadc, true);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700806 if (rc)
807 return rc;
808
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700809 rc = qpnp_iadc_write_reg(iadc, QPNP_CONV_REQ, qpnp_iadc_conv_req);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700810 if (rc) {
811 pr_err("qpnp adc read adc failed with %d\n", rc);
812 return rc;
813 }
814
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700815 if (iadc->iadc_poll_eoc) {
816 while (status1 != QPNP_STATUS1_EOC) {
817 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
818 if (rc < 0)
819 return rc;
820 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
821 usleep_range(QPNP_ADC_CONV_TIME_MIN,
822 QPNP_ADC_CONV_TIME_MAX);
823 count++;
824 if (count > QPNP_ADC_ERR_COUNT) {
825 pr_err("retry error exceeded\n");
826 rc = qpnp_iadc_status_debug(iadc);
827 if (rc < 0)
828 pr_err("IADC status debug failed\n");
829 rc = -EINVAL;
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800830 return rc;
831 }
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700832 }
833 } else {
834 rc = wait_for_completion_timeout(
835 &iadc->adc->adc_rslt_completion,
836 QPNP_ADC_COMPLETION_TIMEOUT);
837 if (!rc) {
838 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
839 if (rc < 0)
840 return rc;
841 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
842 if (status1 == QPNP_STATUS1_EOC)
843 pr_debug("End of conversion status set\n");
844 else {
845 rc = qpnp_iadc_status_debug(iadc);
846 if (rc < 0) {
847 pr_err("status debug failed %d\n", rc);
848 return rc;
849 }
850 return -EINVAL;
851 }
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700852 }
853 }
854
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700855 rc = qpnp_iadc_read_conversion_result(iadc, raw_code);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700856 if (rc) {
857 pr_err("qpnp adc read adc failed with %d\n", rc);
858 return rc;
859 }
860
861 return 0;
862}
863
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700864#define IADC_CENTER 0xC000
865#define IADC_READING_RESOLUTION_N 542535
866#define IADC_READING_RESOLUTION_D 100000
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700867static int32_t qpnp_convert_raw_offset_voltage(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700868{
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700869 s64 numerator;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700870
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800871 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
872 pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
873 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
874 return -EINVAL;
875 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700876
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700877 numerator = iadc->adc->calib.offset_raw - IADC_CENTER;
878 numerator *= IADC_READING_RESOLUTION_N;
879 iadc->adc->calib.offset_uv = div_s64(numerator,
880 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700881
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700882 numerator = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
883 numerator *= IADC_READING_RESOLUTION_N;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700884
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700885 iadc->adc->calib.gain_uv = div_s64(numerator,
886 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700887
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700888 pr_debug("gain_uv:%d offset_uv:%d\n",
889 iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700890 return 0;
891}
892
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700893#define IADC_IDEAL_RAW_GAIN 3291
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700894int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
895 bool batfet_closed)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700896{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700897 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss8b076be2014-03-11 19:03:03 -0700898 int32_t rc = 0, version = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700899 uint16_t raw_data;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800900 uint32_t mode_sel = 0;
Siddartha Mohanadoss8b076be2014-03-11 19:03:03 -0700901 bool iadc_offset_ch_batfet_check;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700902
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700903 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700904 return -EPROBE_DEFER;
905
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800906 mutex_lock(&iadc->adc->adc_lock);
907
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700908 if (iadc->iadc_poll_eoc) {
909 pr_debug("acquiring iadc eoc wakelock\n");
910 pm_stay_awake(iadc->dev);
911 }
912
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700913 rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800914 &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700915 if (rc < 0) {
916 pr_err("qpnp adc result read failed with %d\n", rc);
917 goto fail;
918 }
919
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700920 iadc->adc->calib.gain_raw = raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700921
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700922 /*
Siddartha Mohanadoss8b076be2014-03-11 19:03:03 -0700923 * there is a features on PM8941 in the BMS where if the batfet is
924 * opened the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700925 * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
926 * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
927 * internal rsense.
928 */
Siddartha Mohanadoss8b076be2014-03-11 19:03:03 -0700929 version = qpnp_adc_get_revid_version(iadc->dev);
930 if ((version == QPNP_REV_ID_8941_3_1) ||
931 (version == QPNP_REV_ID_8941_3_0) ||
932 (version == QPNP_REV_ID_8941_2_0))
933 iadc_offset_ch_batfet_check = true;
934 else
935 iadc_offset_ch_batfet_check = false;
936
Siddartha Mohanadoss5e1e6ed2014-03-17 22:38:29 -0700937 if ((iadc_offset_ch_batfet_check && !batfet_closed) ||
938 (iadc->external_rsense)) {
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700939 /* external offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700940 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800941 &raw_data, mode_sel);
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700942 if (rc < 0) {
943 pr_err("qpnp adc result read failed with %d\n", rc);
944 goto fail;
945 }
946 } else {
947 /* internal offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700948 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2,
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700949 &raw_data, mode_sel);
950 if (rc < 0) {
951 pr_err("qpnp adc result read failed with %d\n", rc);
952 goto fail;
953 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700954 }
955
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700956 iadc->adc->calib.offset_raw = raw_data;
957 if (rc < 0) {
958 pr_err("qpnp adc offset/gain calculation failed\n");
959 goto fail;
960 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700961
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700962 if (iadc->iadc_comp.revision_dig_major == QPNP_IADC_PM8026_2_REV2
963 && iadc->iadc_comp.revision_ana_minor ==
964 QPNP_IADC_PM8026_2_REV3)
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700965 iadc->adc->calib.gain_raw =
966 iadc->adc->calib.offset_raw + IADC_IDEAL_RAW_GAIN;
967
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700968 pr_debug("raw gain:0x%x, raw offset:0x%x\n",
969 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
970
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700971 rc = qpnp_convert_raw_offset_voltage(iadc);
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800972 if (rc < 0) {
973 pr_err("qpnp raw_voltage conversion failed\n");
974 goto fail;
975 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700976
977 rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
978 QPNP_BIT_SHIFT_8;
979 rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
980
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700981 pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
982
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700983 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700984 QPNP_IADC_SEC_ACCESS_DATA);
985 if (rc < 0) {
986 pr_err("qpnp iadc configure error for sec access\n");
987 goto fail;
988 }
989
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700990 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700991 rslt_msb);
992 if (rc < 0) {
993 pr_err("qpnp iadc configure error for MSB write\n");
994 goto fail;
995 }
996
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700997 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700998 QPNP_IADC_SEC_ACCESS_DATA);
999 if (rc < 0) {
1000 pr_err("qpnp iadc configure error for sec access\n");
1001 goto fail;
1002 }
1003
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001004 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001005 rslt_lsb);
1006 if (rc < 0) {
1007 pr_err("qpnp iadc configure error for LSB write\n");
1008 goto fail;
1009 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001010fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001011 if (iadc->iadc_poll_eoc) {
1012 pr_debug("releasing iadc eoc wakelock\n");
1013 pm_relax(iadc->dev);
1014 }
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001015 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001016 return rc;
1017}
Siddartha Mohanadoss06673922013-03-27 11:14:19 -07001018EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001019
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001020static void qpnp_iadc_work(struct work_struct *work)
1021{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001022 struct qpnp_iadc_chip *iadc = container_of(work,
1023 struct qpnp_iadc_chip, iadc_work.work);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001024 int rc = 0;
1025
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001026 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001027 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001028 if (rc)
1029 pr_debug("periodic IADC calibration failed\n");
1030 }
1031
1032 schedule_delayed_work(&iadc->iadc_work,
1033 round_jiffies_relative(msecs_to_jiffies
1034 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001035 return;
1036}
1037
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001038static int32_t qpnp_iadc_version_check(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001039{
1040 uint8_t revision;
1041 int rc;
1042
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001043 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &revision);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001044 if (rc < 0) {
1045 pr_err("qpnp adc result read failed with %d\n", rc);
1046 return rc;
1047 }
1048
1049 if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
1050 pr_err("IADC Version not supported\n");
1051 return -EINVAL;
1052 }
1053
1054 return 0;
1055}
1056
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001057struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001058{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001059 struct qpnp_iadc_chip *iadc;
1060 struct device_node *node = NULL;
1061 char prop_name[QPNP_MAX_PROP_NAME_LEN];
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001062
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001063 snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-iadc", name);
1064
1065 node = of_parse_phandle(dev->of_node, prop_name, 0);
1066 if (node == NULL)
1067 return ERR_PTR(-ENODEV);
1068
1069 list_for_each_entry(iadc, &qpnp_iadc_device_list, list)
1070 if (iadc->adc->spmi->dev.of_node == node)
1071 return iadc;
1072 return ERR_PTR(-EPROBE_DEFER);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001073}
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001074EXPORT_SYMBOL(qpnp_get_iadc);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001075
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001076int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001077{
Dipen Parmaraac5a342014-02-20 17:58:48 +05301078 uint8_t rslt_rsense = 0;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -07001079 int32_t rc = 0, sign_bit = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001080
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001081 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001082 return -EPROBE_DEFER;
1083
Siddartha Mohanadoss58279542013-05-28 16:20:46 -07001084 if (iadc->external_rsense) {
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -07001085 *rsense = iadc->rsense;
Dipen Parmaraac5a342014-02-20 17:58:48 +05301086 } else if (iadc->default_internal_rsense) {
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001087 *rsense = iadc->rsense_workaround_value;
Dipen Parmaraac5a342014-02-20 17:58:48 +05301088 } else {
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001089
Dipen Parmaraac5a342014-02-20 17:58:48 +05301090 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE,
1091 &rslt_rsense);
1092 if (rc < 0) {
1093 pr_err("qpnp adc rsense read failed with %d\n", rc);
1094 return rc;
1095 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001096
Dipen Parmaraac5a342014-02-20 17:58:48 +05301097 pr_debug("rsense:0%x\n", rslt_rsense);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001098
Dipen Parmaraac5a342014-02-20 17:58:48 +05301099 if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
1100 sign_bit = 1;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001101
Dipen Parmaraac5a342014-02-20 17:58:48 +05301102 rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001103
Dipen Parmaraac5a342014-02-20 17:58:48 +05301104 if (sign_bit)
1105 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001106 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
Dipen Parmaraac5a342014-02-20 17:58:48 +05301107 else
1108 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001109 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
Dipen Parmaraac5a342014-02-20 17:58:48 +05301110 }
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001111 pr_debug("rsense value is %d\n", *rsense);
1112
Dipen Parmaraac5a342014-02-20 17:58:48 +05301113 if (*rsense == 0)
1114 pr_err("incorrect rsens value:%d rslt_rsense:%d\n",
1115 *rsense, rslt_rsense);
1116
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001117 return rc;
1118}
Xiaozhe Shi767fdb62013-01-10 15:09:08 -08001119EXPORT_SYMBOL(qpnp_iadc_get_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001120
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001121static int32_t qpnp_check_pmic_temp(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001122{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001123 struct qpnp_vadc_result result_pmic_therm;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -07001124 int64_t die_temp_offset;
Siddartha Mohanadossd752e472013-02-26 18:30:14 -08001125 int rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001126
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001127 rc = qpnp_vadc_read(iadc->vadc_dev, DIE_TEMP, &result_pmic_therm);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001128 if (rc < 0)
1129 return rc;
1130
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -07001131 die_temp_offset = result_pmic_therm.physical -
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001132 iadc->die_temp;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -07001133 if (die_temp_offset < 0)
1134 die_temp_offset = -die_temp_offset;
1135
1136 if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -07001137 iadc->die_temp = result_pmic_therm.physical;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001138 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001139 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001140 if (rc)
1141 pr_err("IADC calibration failed rc = %d\n", rc);
1142 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001143 }
1144
Siddartha Mohanadossd752e472013-02-26 18:30:14 -08001145 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001146}
1147
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001148int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
1149 enum qpnp_iadc_channels channel,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001150 struct qpnp_iadc_result *result)
1151{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001152 int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001153 int32_t rsense_u_ohms = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001154 int64_t result_current;
1155 uint16_t raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001156
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001157 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001158 return -EPROBE_DEFER;
1159
Dipen Parmar454c4b12013-11-25 14:40:47 +05301160 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
1161 pr_err("raw offset errors! run iadc calibration again\n");
1162 return -EINVAL;
1163 }
1164
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001165 rc = qpnp_check_pmic_temp(iadc);
1166 if (rc) {
1167 pr_err("Error checking pmic therm temp\n");
1168 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001169 }
1170
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001171 mutex_lock(&iadc->adc->adc_lock);
1172
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001173 if (iadc->iadc_poll_eoc) {
1174 pr_debug("acquiring iadc eoc wakelock\n");
1175 pm_stay_awake(iadc->dev);
1176 }
1177
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001178 rc = qpnp_iadc_configure(iadc, channel, &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001179 if (rc < 0) {
1180 pr_err("qpnp adc result read failed with %d\n", rc);
1181 goto fail;
1182 }
1183
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001184 rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001185 pr_debug("current raw:0%x and rsense:%d\n",
1186 raw_data, rsense_n_ohms);
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001187 rsense_u_ohms = rsense_n_ohms/1000;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001188 num = raw_data - iadc->adc->calib.offset_raw;
1189 if (num < 0) {
1190 sign = 1;
1191 num = -num;
1192 }
1193
1194 result->result_uv = (num * QPNP_ADC_GAIN_NV)/
1195 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
1196 result_current = result->result_uv;
1197 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001198 /* Intentional fall through. Process the result w/o comp */
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001199 do_div(result_current, rsense_u_ohms);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001200
1201 if (sign) {
1202 result->result_uv = -result->result_uv;
1203 result_current = -result_current;
1204 }
Xiaozhe Shie51d5542013-11-01 13:06:14 -07001205 result_current *= -1;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001206 rc = qpnp_iadc_comp_result(iadc, &result_current);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001207 if (rc < 0)
1208 pr_err("Error during compensating the IADC\n");
1209 rc = 0;
Xiaozhe Shie51d5542013-11-01 13:06:14 -07001210 result_current *= -1;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001211
1212 result->result_ua = (int32_t) result_current;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001213fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001214 if (iadc->iadc_poll_eoc) {
1215 pr_debug("releasing iadc eoc wakelock\n");
1216 pm_relax(iadc->dev);
1217 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001218 mutex_unlock(&iadc->adc->adc_lock);
1219
1220 return rc;
1221}
1222EXPORT_SYMBOL(qpnp_iadc_read);
1223
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001224int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
1225 struct qpnp_iadc_calib *result)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001226{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001227 int rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001228
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001229 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001230 return -EPROBE_DEFER;
1231
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001232 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001233 if (rc) {
1234 pr_err("Error checking pmic therm temp\n");
1235 return rc;
1236 }
1237
1238 mutex_lock(&iadc->adc->adc_lock);
1239 result->gain_raw = iadc->adc->calib.gain_raw;
1240 result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
1241 result->gain_uv = iadc->adc->calib.gain_uv;
1242 result->offset_raw = iadc->adc->calib.offset_raw;
1243 result->ideal_offset_uv =
1244 QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
1245 result->offset_uv = iadc->adc->calib.offset_uv;
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001246 pr_debug("raw gain:0%x, raw offset:0%x\n",
1247 result->gain_raw, result->offset_raw);
1248 pr_debug("gain_uv:%d offset_uv:%d\n",
1249 result->gain_uv, result->offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001250 mutex_unlock(&iadc->adc->adc_lock);
1251
1252 return 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001253}
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001254EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001255
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001256int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001257{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001258 iadc->skip_auto_calibrations = true;
1259 return 0;
1260}
1261EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
1262
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001263int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001264{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001265 iadc->skip_auto_calibrations = false;
1266 return 0;
1267}
1268EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
1269
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001270int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001271 enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
1272 enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
1273{
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001274 int rc = 0, mode_sel = 0, num = 0, rsense_n_ohms = 0, sign = 0;
1275 uint16_t raw_data;
1276 int32_t rsense_u_ohms = 0;
1277 int64_t result_current;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001278
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001279 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001280 return -EPROBE_DEFER;
1281
Dipen Parmaraac5a342014-02-20 17:58:48 +05301282 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
1283 pr_err("raw offset errors! run iadc calibration again\n");
1284 return -EINVAL;
1285 }
1286
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001287 mutex_lock(&iadc->adc->adc_lock);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001288
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001289 if (iadc->iadc_poll_eoc) {
1290 pr_debug("acquiring iadc eoc wakelock\n");
1291 pm_stay_awake(iadc->dev);
1292 }
1293
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001294 iadc->iadc_mode_sel = true;
1295
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001296 rc = qpnp_vadc_iadc_sync_request(iadc->vadc_dev, v_channel);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001297 if (rc) {
1298 pr_err("Configuring VADC failed\n");
1299 goto fail;
1300 }
1301
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001302 rc = qpnp_iadc_configure(iadc, i_channel, &raw_data, mode_sel);
1303 if (rc < 0) {
1304 pr_err("qpnp adc result read failed with %d\n", rc);
1305 goto fail_release_vadc;
1306 }
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001307
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001308 rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
1309 pr_debug("current raw:0%x and rsense:%d\n",
1310 raw_data, rsense_n_ohms);
1311 rsense_u_ohms = rsense_n_ohms/1000;
1312 num = raw_data - iadc->adc->calib.offset_raw;
1313 if (num < 0) {
1314 sign = 1;
1315 num = -num;
1316 }
1317
1318 i_result->result_uv = (num * QPNP_ADC_GAIN_NV)/
1319 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
1320 result_current = i_result->result_uv;
1321 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
1322 /* Intentional fall through. Process the result w/o comp */
Dipen Parmaraac5a342014-02-20 17:58:48 +05301323 if (!rsense_u_ohms) {
1324 pr_err("rsense error=%d\n", rsense_u_ohms);
1325 goto fail_release_vadc;
1326 }
1327
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001328 do_div(result_current, rsense_u_ohms);
1329
1330 if (sign) {
1331 i_result->result_uv = -i_result->result_uv;
1332 result_current = -result_current;
1333 }
1334 result_current *= -1;
1335 rc = qpnp_iadc_comp_result(iadc, &result_current);
1336 if (rc < 0)
1337 pr_err("Error during compensating the IADC\n");
1338 rc = 0;
1339 result_current *= -1;
1340
1341 i_result->result_ua = (int32_t) result_current;
1342
1343fail_release_vadc:
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001344 rc = qpnp_vadc_iadc_sync_complete_request(iadc->vadc_dev, v_channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001345 v_result);
1346 if (rc)
1347 pr_err("Releasing VADC failed\n");
1348fail:
1349 iadc->iadc_mode_sel = false;
1350
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001351 if (iadc->iadc_poll_eoc) {
1352 pr_debug("releasing iadc eoc wakelock\n");
1353 pm_relax(iadc->dev);
1354 }
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001355 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001356
1357 return rc;
1358}
1359EXPORT_SYMBOL(qpnp_iadc_vadc_sync_read);
1360
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001361static ssize_t qpnp_iadc_show(struct device *dev,
1362 struct device_attribute *devattr, char *buf)
1363{
1364 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001365 struct qpnp_iadc_chip *iadc = dev_get_drvdata(dev);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001366 struct qpnp_iadc_result result;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001367 int rc = -1;
1368
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001369 rc = qpnp_iadc_read(iadc, attr->index, &result);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001370
1371 if (rc)
1372 return 0;
1373
1374 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001375 "Result:%d\n", result.result_ua);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001376}
1377
1378static struct sensor_device_attribute qpnp_adc_attr =
1379 SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
1380
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001381static int32_t qpnp_iadc_init_hwmon(struct qpnp_iadc_chip *iadc,
1382 struct spmi_device *spmi)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001383{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001384 struct device_node *child;
1385 struct device_node *node = spmi->dev.of_node;
1386 int rc = 0, i = 0, channel;
1387
1388 for_each_child_of_node(node, child) {
1389 channel = iadc->adc->adc_channels[i].channel_num;
1390 qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
1391 qpnp_adc_attr.dev_attr.attr.name =
1392 iadc->adc->adc_channels[i].name;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001393 memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
1394 sizeof(qpnp_adc_attr));
Stephen Boyd8a5c4e42012-10-30 11:07:22 -07001395 sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001396 rc = device_create_file(&spmi->dev,
1397 &iadc->sens_attr[i].dev_attr);
1398 if (rc) {
1399 dev_err(&spmi->dev,
1400 "device_create_file failed for dev %s\n",
1401 iadc->adc->adc_channels[i].name);
1402 goto hwmon_err_sens;
1403 }
1404 i++;
1405 }
1406
1407 return 0;
1408hwmon_err_sens:
1409 pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
1410 return rc;
1411}
1412
1413static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
1414{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001415 struct qpnp_iadc_chip *iadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001416 struct qpnp_adc_drv *adc_qpnp;
1417 struct device_node *node = spmi->dev.of_node;
1418 struct device_node *child;
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001419 struct resource *res;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001420 int rc, count_adc_channel_list = 0, i = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001421
1422 for_each_child_of_node(node, child)
1423 count_adc_channel_list++;
1424
1425 if (!count_adc_channel_list) {
1426 pr_err("No channel listing\n");
1427 return -EINVAL;
1428 }
1429
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001430 iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_chip) +
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001431 (sizeof(struct sensor_device_attribute) *
1432 count_adc_channel_list), GFP_KERNEL);
1433 if (!iadc) {
1434 dev_err(&spmi->dev, "Unable to allocate memory\n");
1435 return -ENOMEM;
1436 }
1437
1438 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1439 GFP_KERNEL);
1440 if (!adc_qpnp) {
1441 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossc61babb2013-08-02 13:37:12 -07001442 return -ENOMEM;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001443 }
1444
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001445 iadc->dev = &(spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001446 iadc->adc = adc_qpnp;
1447
1448 rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
1449 if (rc) {
1450 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossc61babb2013-08-02 13:37:12 -07001451 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001452 }
1453
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001454 res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
1455 "batt-id-trim-cnst-rds");
1456 if (!res) {
1457 dev_err(&spmi->dev, "failed to read batt_id trim register\n");
1458 return -EINVAL;
1459 }
1460 iadc->batt_id_trim_cnst_rds = res->start;
1461 rc = of_property_read_u32(node, "qcom,use-default-rds-trim",
1462 &iadc->rds_trim_default_type);
1463 if (rc)
1464 pr_debug("No trim workaround needed\n");
1465 else {
1466 pr_debug("Use internal RDS trim workaround\n");
1467 iadc->rds_trim_default_check = true;
1468 }
1469
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001470 iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
1471 if (IS_ERR(iadc->vadc_dev)) {
1472 rc = PTR_ERR(iadc->vadc_dev);
1473 if (rc != -EPROBE_DEFER)
1474 pr_err("vadc property missing, rc=%d\n", rc);
Siddartha Mohanadossc61babb2013-08-02 13:37:12 -07001475 return rc;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001476 }
1477
Stephen Boydbeab4502013-04-25 10:18:17 -07001478 mutex_init(&iadc->adc->adc_lock);
1479
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001480 rc = of_property_read_u32(node, "qcom,rsense",
1481 &iadc->rsense);
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -07001482 if (rc)
1483 pr_debug("Defaulting to internal rsense\n");
1484 else {
1485 pr_debug("Use external rsense\n");
1486 iadc->external_rsense = true;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001487 }
1488
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001489 iadc->iadc_poll_eoc = of_property_read_bool(node,
1490 "qcom,iadc-poll-eoc");
1491 if (!iadc->iadc_poll_eoc) {
1492 rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
1493 qpnp_iadc_isr, IRQF_TRIGGER_RISING,
1494 "qpnp_iadc_interrupt", iadc);
1495 if (rc) {
1496 dev_err(&spmi->dev, "failed to request adc irq\n");
1497 return rc;
1498 } else
1499 enable_irq_wake(iadc->adc->adc_irq_eoc);
1500 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001501
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001502 rc = qpnp_iadc_init_hwmon(iadc, spmi);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001503 if (rc) {
1504 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001505 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001506 }
1507 iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
1508
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001509 rc = qpnp_iadc_version_check(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001510 if (rc) {
1511 dev_err(&spmi->dev, "IADC version not supported\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001512 goto fail;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001513 }
1514
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001515 INIT_WORK(&iadc->trigger_completion_work, qpnp_iadc_trigger_completion);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001516 INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001517 rc = qpnp_iadc_comp_info(iadc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001518 if (rc) {
1519 dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
1520 goto fail;
1521 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001522
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001523 rc = qpnp_iadc_rds_trim_update_check(iadc);
1524 if (rc) {
1525 dev_err(&spmi->dev, "Rds trim update failed!\n");
1526 goto fail;
1527 }
1528
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001529 dev_set_drvdata(&spmi->dev, iadc);
1530 list_add(&iadc->list, &qpnp_iadc_device_list);
1531 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001532 if (rc)
1533 dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001534
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001535 if (iadc->iadc_poll_eoc)
1536 device_init_wakeup(iadc->dev, 1);
1537
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001538 schedule_delayed_work(&iadc->iadc_work,
1539 round_jiffies_relative(msecs_to_jiffies
1540 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001541 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001542fail:
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001543 for_each_child_of_node(node, child) {
1544 device_remove_file(&spmi->dev,
1545 &iadc->sens_attr[i].dev_attr);
1546 i++;
1547 }
1548 hwmon_device_unregister(iadc->iadc_hwmon);
1549
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001550 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001551}
1552
1553static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
1554{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001555 struct qpnp_iadc_chip *iadc = dev_get_drvdata(&spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001556 struct device_node *node = spmi->dev.of_node;
1557 struct device_node *child;
1558 int i = 0;
1559
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001560 cancel_delayed_work(&iadc->iadc_work);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001561 for_each_child_of_node(node, child) {
1562 device_remove_file(&spmi->dev,
1563 &iadc->sens_attr[i].dev_attr);
1564 i++;
1565 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001566 hwmon_device_unregister(iadc->iadc_hwmon);
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001567 if (iadc->iadc_poll_eoc)
1568 pm_relax(iadc->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001569 dev_set_drvdata(&spmi->dev, NULL);
1570
1571 return 0;
1572}
1573
1574static const struct of_device_id qpnp_iadc_match_table[] = {
1575 { .compatible = "qcom,qpnp-iadc",
1576 },
1577 {}
1578};
1579
1580static struct spmi_driver qpnp_iadc_driver = {
1581 .driver = {
1582 .name = "qcom,qpnp-iadc",
1583 .of_match_table = qpnp_iadc_match_table,
1584 },
1585 .probe = qpnp_iadc_probe,
1586 .remove = qpnp_iadc_remove,
1587};
1588
1589static int __init qpnp_iadc_init(void)
1590{
1591 return spmi_driver_register(&qpnp_iadc_driver);
1592}
1593module_init(qpnp_iadc_init);
1594
1595static void __exit qpnp_iadc_exit(void)
1596{
1597 spmi_driver_unregister(&qpnp_iadc_driver);
1598}
1599module_exit(qpnp_iadc_exit);
1600
1601MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
1602MODULE_LICENSE("GPL v2");