blob: 135490750ee663855fa48993076c904700896952 [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
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070073#define QPNP_CONV_REQ 0x52
74#define QPNP_CONV_REQ_SET BIT(7)
75#define QPNP_CONV_SEQ_CTL 0x54
76#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
77#define QPNP_CONV_SEQ_TRIG_CTL 0x55
78#define QPNP_FAST_AVG_CTL 0x5a
79
80#define QPNP_M0_LOW_THR_LSB 0x5c
81#define QPNP_M0_LOW_THR_MSB 0x5d
82#define QPNP_M0_HIGH_THR_LSB 0x5e
83#define QPNP_M0_HIGH_THR_MSB 0x5f
84#define QPNP_M1_LOW_THR_LSB 0x69
85#define QPNP_M1_LOW_THR_MSB 0x6a
86#define QPNP_M1_HIGH_THR_LSB 0x6b
87#define QPNP_M1_HIGH_THR_MSB 0x6c
88
89#define QPNP_DATA0 0x60
90#define QPNP_DATA1 0x61
91#define QPNP_CONV_TIMEOUT_ERR 2
92
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -070093#define QPNP_IADC_SEC_ACCESS 0xD0
94#define QPNP_IADC_SEC_ACCESS_DATA 0xA5
95#define QPNP_IADC_MSB_OFFSET 0xF2
96#define QPNP_IADC_LSB_OFFSET 0xF3
97#define QPNP_IADC_NOMINAL_RSENSE 0xF4
98#define QPNP_IADC_ATE_GAIN_CALIB_OFFSET 0xF5
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -070099#define QPNP_INT_TEST_VAL 0xE1
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700100
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700101#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
102#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
103
104#define QPNP_IADC_ADC_DIG_PARAM 0x50
105#define QPNP_IADC_CLK_SEL_SHIFT 1
106#define QPNP_IADC_DEC_RATIO_SEL 3
107
108#define QPNP_IADC_CONV_REQUEST 0x52
109#define QPNP_IADC_CONV_REQ BIT(7)
110
111#define QPNP_IADC_DATA0 0x60
112#define QPNP_IADC_DATA1 0x61
113
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700114#define QPNP_ADC_CONV_TIME_MIN 2000
115#define QPNP_ADC_CONV_TIME_MAX 2100
116#define QPNP_ADC_ERR_COUNT 20
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700117
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700118#define QPNP_ADC_GAIN_NV 17857
119#define QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL 0
120#define QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR 10000000
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700121#define QPNP_IADC_NANO_VOLTS_FACTOR 1000000
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700122#define QPNP_IADC_CALIB_SECONDS 300000
123#define QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT 15625
124#define QPNP_IADC_DIE_TEMP_CALIB_OFFSET 5000
125
126#define QPNP_RAW_CODE_16_BIT_MSB_MASK 0xff00
127#define QPNP_RAW_CODE_16_BIT_LSB_MASK 0xff
128#define QPNP_BIT_SHIFT_8 8
129#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700130#define QPNP_ADC_COMPLETION_TIMEOUT HZ
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800131#define SMBB_BAT_IF_TRIM_CNST_RDS_MASK 0x7
Dipen Parmarc908fd12014-03-25 17:50:58 +0530132#define SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_0 0
133#define SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2 2
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800134#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;
Dipen Parmarba874582014-07-23 19:00:48 +0530165 int max_channels_available;
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800166 bool rds_trim_default_check;
167 int32_t rsense_workaround_value;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700168 struct sensor_device_attribute sens_attr[0];
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700169};
170
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700171LIST_HEAD(qpnp_iadc_device_list);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700172
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800173enum qpnp_iadc_rsense_rds_workaround {
174 QPNP_IADC_RDS_DEFAULT_TYPEA,
175 QPNP_IADC_RDS_DEFAULT_TYPEB,
Dipen Parmarc908fd12014-03-25 17:50:58 +0530176 QPNP_IADC_RDS_DEFAULT_TYPEC,
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800177};
178
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700179static int32_t qpnp_iadc_read_reg(struct qpnp_iadc_chip *iadc,
180 uint32_t reg, u8 *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700181{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700182 int rc;
183
184 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700185 (iadc->adc->offset + reg), data, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700186 if (rc < 0) {
187 pr_err("qpnp iadc read reg %d failed with %d\n", reg, rc);
188 return rc;
189 }
190
191 return 0;
192}
193
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700194static int32_t qpnp_iadc_write_reg(struct qpnp_iadc_chip *iadc,
195 uint32_t reg, u8 data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700196{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700197 int rc;
198 u8 *buf;
199
200 buf = &data;
201 rc = spmi_ext_register_writel(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700202 (iadc->adc->offset + reg), buf, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700203 if (rc < 0) {
204 pr_err("qpnp iadc write reg %d failed with %d\n", reg, rc);
205 return rc;
206 }
207
208 return 0;
209}
210
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700211static int qpnp_iadc_is_valid(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800212{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700213 struct qpnp_iadc_chip *iadc_chip = NULL;
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800214
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700215 list_for_each_entry(iadc_chip, &qpnp_iadc_device_list, list)
216 if (iadc == iadc_chip)
217 return 0;
218
219 return -EINVAL;
220}
221
222static void qpnp_iadc_trigger_completion(struct work_struct *work)
223{
224 struct qpnp_iadc_chip *iadc = container_of(work,
225 struct qpnp_iadc_chip, trigger_completion_work);
226
227 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800228 return;
229
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800230 complete(&iadc->adc->adc_rslt_completion);
231
232 return;
233}
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800234
235static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
236{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700237 struct qpnp_iadc_chip *iadc = dev_id;
238
239 schedule_work(&iadc->trigger_completion_work);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800240
241 return IRQ_HANDLED;
242}
243
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700244static int32_t qpnp_iadc_enable(struct qpnp_iadc_chip *dev, bool state)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800245{
246 int rc = 0;
247 u8 data = 0;
248
249 data = QPNP_IADC_ADC_EN;
250 if (state) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700251 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800252 data);
253 if (rc < 0) {
254 pr_err("IADC enable failed\n");
255 return rc;
256 }
257 } else {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700258 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800259 (~data & QPNP_IADC_ADC_EN));
260 if (rc < 0) {
261 pr_err("IADC disable failed\n");
262 return rc;
263 }
264 }
265
266 return 0;
267}
268
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700269static int32_t qpnp_iadc_status_debug(struct qpnp_iadc_chip *dev)
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800270{
271 int rc = 0;
272 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
273
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700274 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_MODE_CTL, &mode);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800275 if (rc < 0) {
276 pr_err("mode ctl register 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_ADC_DIG_PARAM, &dig);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800281 if (rc < 0) {
282 pr_err("digital param read failed with %d\n", rc);
283 return rc;
284 }
285
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700286 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_ADC_CH_SEL_CTL, &chan);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800287 if (rc < 0) {
288 pr_err("channel read failed with %d\n", rc);
289 return rc;
290 }
291
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700292 rc = qpnp_iadc_read_reg(dev, QPNP_STATUS1, &status1);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800293 if (rc < 0) {
294 pr_err("status1 read failed with %d\n", rc);
295 return rc;
296 }
297
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700298 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_EN_CTL1, &en);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800299 if (rc < 0) {
300 pr_err("en read failed with %d\n", rc);
301 return rc;
302 }
303
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700304 pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800305 status1, dig, chan, mode, en);
306
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700307 rc = qpnp_iadc_enable(dev, false);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800308 if (rc < 0) {
309 pr_err("IADC disable failed with %d\n", rc);
310 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700311 }
312
313 return 0;
314}
315
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700316static int32_t qpnp_iadc_read_conversion_result(struct qpnp_iadc_chip *iadc,
317 int16_t *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700318{
319 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700320 uint16_t rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700321 int32_t rc;
322
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700323 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA0, &rslt_lsb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700324 if (rc < 0) {
325 pr_err("qpnp adc result read failed with %d\n", rc);
326 return rc;
327 }
328
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700329 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA1, &rslt_msb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700330 if (rc < 0) {
331 pr_err("qpnp adc result read failed with %d\n", rc);
332 return rc;
333 }
334
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700335 rslt = (rslt_msb << 8) | rslt_lsb;
336 *data = rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700337
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700338 rc = qpnp_iadc_enable(iadc, false);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700339 if (rc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700340 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700341
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700342 return 0;
343}
344
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700345#define QPNP_IADC_PM8026_2_REV2 4
346#define QPNP_IADC_PM8026_2_REV3 2
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700347
348#define QPNP_COEFF_1 969000
349#define QPNP_COEFF_2 32
350#define QPNP_COEFF_3_TYPEA 1700000
351#define QPNP_COEFF_3_TYPEB 1000000
352#define QPNP_COEFF_4 100
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700353#define QPNP_COEFF_5 15
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700354#define QPNP_COEFF_6 100000
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700355#define QPNP_COEFF_7 21
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700356#define QPNP_COEFF_8 100000000
357#define QPNP_COEFF_9 38
358#define QPNP_COEFF_10 40
359#define QPNP_COEFF_11 7
360#define QPNP_COEFF_12 11
361#define QPNP_COEFF_13 37
362#define QPNP_COEFF_14 39
363#define QPNP_COEFF_15 9
364#define QPNP_COEFF_16 11
365#define QPNP_COEFF_17 851200
366#define QPNP_COEFF_18 296500
367#define QPNP_COEFF_19 222400
368#define QPNP_COEFF_20 813800
369#define QPNP_COEFF_21 1059100
370#define QPNP_COEFF_22 5000000
371#define QPNP_COEFF_23 3722500
372#define QPNP_COEFF_24 84
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700373#define QPNP_COEFF_25 33
374#define QPNP_COEFF_26 22
Xiaozhe Shi80754222013-10-30 14:11:41 -0700375#define QPNP_COEFF_27 53
376#define QPNP_COEFF_28 48
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700377
378static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700379 int64_t die_temp)
380{
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700381 int64_t temp_var = 0, sys_gain_coeff = 0, old;
382 int32_t coeff_a = 0, coeff_b = 0;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700383 int version = 0;
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700384
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700385 version = qpnp_adc_get_revid_version(iadc->dev);
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700386 if (version == -EINVAL)
387 return 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700388
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700389 old = *result;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700390 *result = *result * 1000000;
391
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700392 if (iadc->iadc_comp.sys_gain > 127)
393 sys_gain_coeff = -QPNP_COEFF_6 *
394 (iadc->iadc_comp.sys_gain - 128);
395 else
396 sys_gain_coeff = QPNP_COEFF_6 *
397 iadc->iadc_comp.sys_gain;
398
399 switch (version) {
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700400 case QPNP_REV_ID_8941_3_1:
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700401 switch (iadc->iadc_comp.id) {
402 case COMP_ID_GF:
403 if (!iadc->iadc_comp.ext_rsense) {
404 /* internal rsense */
405 coeff_a = QPNP_COEFF_2;
406 coeff_b = -QPNP_COEFF_3_TYPEA;
407 } else {
408 if (*result < 0) {
409 /* charge */
410 coeff_a = QPNP_COEFF_5;
411 coeff_b = QPNP_COEFF_6;
412 } else {
413 /* discharge */
414 coeff_a = -QPNP_COEFF_7;
415 coeff_b = QPNP_COEFF_6;
416 }
417 }
418 break;
419 case COMP_ID_TSMC:
420 default:
421 if (!iadc->iadc_comp.ext_rsense) {
422 /* internal rsense */
423 coeff_a = QPNP_COEFF_2;
424 coeff_b = -QPNP_COEFF_3_TYPEB;
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 }
438 break;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700439 case QPNP_REV_ID_8026_2_1:
Siddartha Mohanadoss68b4e082014-01-28 10:53:13 -0800440 case QPNP_REV_ID_8026_2_2:
441 /* pm8026 rev 2.1 and 2.2 */
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700442 switch (iadc->iadc_comp.id) {
443 case COMP_ID_GF:
444 if (!iadc->iadc_comp.ext_rsense) {
445 /* internal rsense */
446 if (*result < 0) {
447 /* charge */
448 coeff_a = 0;
449 coeff_b = 0;
450 } else {
451 coeff_a = QPNP_COEFF_25;
452 coeff_b = 0;
453 }
454 } else {
455 if (*result < 0) {
456 /* charge */
457 coeff_a = 0;
458 coeff_b = 0;
459 } else {
460 /* discharge */
461 coeff_a = 0;
462 coeff_b = 0;
463 }
464 }
465 break;
466 case COMP_ID_TSMC:
467 default:
468 if (!iadc->iadc_comp.ext_rsense) {
469 /* internal rsense */
470 if (*result < 0) {
471 /* charge */
472 coeff_a = 0;
473 coeff_b = 0;
474 } else {
475 coeff_a = QPNP_COEFF_26;
476 coeff_b = 0;
477 }
478 } else {
479 if (*result < 0) {
480 /* charge */
481 coeff_a = 0;
482 coeff_b = 0;
483 } else {
484 /* discharge */
485 coeff_a = 0;
486 coeff_b = 0;
487 }
488 }
489 break;
490 }
491 break;
492 case QPNP_REV_ID_8026_1_0:
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700493 /* pm8026 rev 1.0 */
494 switch (iadc->iadc_comp.id) {
495 case COMP_ID_GF:
496 if (!iadc->iadc_comp.ext_rsense) {
497 /* internal rsense */
498 if (*result < 0) {
499 /* charge */
500 coeff_a = QPNP_COEFF_9;
501 coeff_b = -QPNP_COEFF_17;
502 } else {
503 coeff_a = QPNP_COEFF_10;
504 coeff_b = QPNP_COEFF_18;
505 }
506 } else {
507 if (*result < 0) {
508 /* charge */
509 coeff_a = -QPNP_COEFF_11;
510 coeff_b = 0;
511 } else {
512 /* discharge */
513 coeff_a = -QPNP_COEFF_17;
514 coeff_b = -QPNP_COEFF_19;
515 }
516 }
517 break;
518 case COMP_ID_TSMC:
519 default:
520 if (!iadc->iadc_comp.ext_rsense) {
521 /* internal rsense */
522 if (*result < 0) {
523 /* charge */
524 coeff_a = QPNP_COEFF_13;
525 coeff_b = -QPNP_COEFF_20;
526 } else {
527 coeff_a = QPNP_COEFF_14;
528 coeff_b = QPNP_COEFF_21;
529 }
530 } else {
531 if (*result < 0) {
532 /* charge */
533 coeff_a = -QPNP_COEFF_15;
534 coeff_b = 0;
535 } else {
536 /* discharge */
537 coeff_a = -QPNP_COEFF_12;
538 coeff_b = -QPNP_COEFF_19;
539 }
540 }
541 break;
542 }
543 break;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700544 case QPNP_REV_ID_8110_1_0:
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700545 /* pm8110 rev 1.0 */
546 switch (iadc->iadc_comp.id) {
547 case COMP_ID_GF:
548 if (!iadc->iadc_comp.ext_rsense) {
549 /* internal rsense */
550 if (*result < 0) {
551 /* charge */
552 coeff_a = QPNP_COEFF_24;
553 coeff_b = -QPNP_COEFF_22;
554 } else {
555 coeff_a = QPNP_COEFF_24;
556 coeff_b = -QPNP_COEFF_23;
557 }
558 }
559 break;
560 case COMP_ID_SMIC:
561 default:
562 if (!iadc->iadc_comp.ext_rsense) {
563 /* internal rsense */
564 if (*result < 0) {
565 /* charge */
566 coeff_a = QPNP_COEFF_24;
567 coeff_b = -QPNP_COEFF_22;
568 } else {
569 coeff_a = QPNP_COEFF_24;
570 coeff_b = -QPNP_COEFF_23;
571 }
572 }
573 break;
574 }
575 break;
Xiaozhe Shi80754222013-10-30 14:11:41 -0700576 case QPNP_REV_ID_8110_2_0:
577 die_temp -= 25000;
578 /* pm8110 rev 2.0 */
579 switch (iadc->iadc_comp.id) {
580 case COMP_ID_GF:
581 if (!iadc->iadc_comp.ext_rsense) {
582 /* internal rsense */
583 if (*result < 0) {
584 /* charge */
585 coeff_a = 0;
586 coeff_b = 0;
587 } else {
588 coeff_a = QPNP_COEFF_27;
589 coeff_b = 0;
590 }
591 }
592 break;
593 case COMP_ID_SMIC:
594 default:
595 if (!iadc->iadc_comp.ext_rsense) {
596 /* internal rsense */
597 if (*result < 0) {
598 /* charge */
599 coeff_a = 0;
600 coeff_b = 0;
601 } else {
602 coeff_a = QPNP_COEFF_28;
603 coeff_b = 0;
604 }
605 }
606 break;
607 }
608 break;
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700609 default:
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700610 case QPNP_REV_ID_8026_2_0:
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700611 /* pm8026 rev 1.0 */
612 coeff_a = 0;
613 coeff_b = 0;
614 break;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700615 }
616
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700617 temp_var = (coeff_a * die_temp) + coeff_b;
618 temp_var = div64_s64(temp_var, QPNP_COEFF_4);
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700619 temp_var = 1000 * (1000000 - temp_var);
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700620
621 if (!iadc->iadc_comp.ext_rsense) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700622 /* internal rsense */
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700623 *result = div64_s64(*result * 1000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700624 }
625
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700626 if (iadc->iadc_comp.ext_rsense) {
627 /* external rsense */
628 sys_gain_coeff = (1000000 +
629 div64_s64(sys_gain_coeff, QPNP_COEFF_4));
Siddartha Mohanadoss28473be2013-09-03 15:46:26 -0700630 temp_var = div64_s64(temp_var * sys_gain_coeff, 1000000);
Siddartha Mohanadoss54bbfce2013-08-21 22:02:51 -0700631 *result = div64_s64(*result * 1000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700632 }
Xiaozhe Shi4e3a83c2013-12-02 15:30:56 -0800633 pr_debug("%lld compensated into %lld, a: %d, b: %d, sys_gain: %lld\n",
634 old, *result, coeff_a, coeff_b, sys_gain_coeff);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700635
636 return 0;
637}
638
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700639int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc, int64_t *result)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700640{
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700641 return qpnp_iadc_comp(result, iadc, iadc->die_temp);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700642}
643EXPORT_SYMBOL(qpnp_iadc_comp_result);
644
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800645static int qpnp_iadc_rds_trim_update_check(struct qpnp_iadc_chip *iadc)
646{
647 int rc = 0;
648 u8 trim2_val = 0, smbb_batt_trm_data = 0;
Dipen Parmarc908fd12014-03-25 17:50:58 +0530649 u8 smbb_batt_trm_cnst_rds = 0;
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800650
651 if (!iadc->rds_trim_default_check) {
652 pr_debug("No internal rds trim check needed\n");
653 return 0;
654 }
655
656 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &trim2_val);
657 if (rc < 0) {
658 pr_err("qpnp adc trim2_fullscale1 reg read failed %d\n", rc);
659 return rc;
660 }
661
662 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
663 iadc->batt_id_trim_cnst_rds, &smbb_batt_trm_data, 1);
664 if (rc < 0) {
665 pr_err("batt_id trim_cnst rds reg read failed %d\n", rc);
666 return rc;
667 }
668
Dipen Parmarc908fd12014-03-25 17:50:58 +0530669 smbb_batt_trm_cnst_rds = smbb_batt_trm_data &
670 SMBB_BAT_IF_TRIM_CNST_RDS_MASK;
671
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800672 pr_debug("n_trim:0x%x smb_trm:0x%x\n", trim2_val, smbb_batt_trm_data);
673
674 if (iadc->rds_trim_default_type == QPNP_IADC_RDS_DEFAULT_TYPEA) {
Dipen Parmarc908fd12014-03-25 17:50:58 +0530675
676 if ((smbb_batt_trm_cnst_rds ==
677 SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2) &&
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800678 (trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
679 iadc->rsense_workaround_value =
680 QPNP_IADC_RSENSE_DEFAULT_VALUE;
681 iadc->default_internal_rsense = true;
682 }
683 } else if (iadc->rds_trim_default_type ==
684 QPNP_IADC_RDS_DEFAULT_TYPEB) {
Dipen Parmarc908fd12014-03-25 17:50:58 +0530685 if ((smbb_batt_trm_cnst_rds >=
686 SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2) &&
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800687 (trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
688 iadc->rsense_workaround_value =
689 QPNP_IADC_RSENSE_DEFAULT_VALUE;
690 iadc->default_internal_rsense = true;
Dipen Parmarc908fd12014-03-25 17:50:58 +0530691 } else if ((smbb_batt_trm_cnst_rds <
692 SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2) &&
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800693 (trim2_val ==
694 QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
695 if (iadc->iadc_comp.id == COMP_ID_GF) {
696 iadc->rsense_workaround_value =
697 QPNP_IADC_RSENSE_DEFAULT_TYPEB_GF;
698 iadc->default_internal_rsense = true;
699 } else if (iadc->iadc_comp.id == COMP_ID_SMIC) {
700 iadc->rsense_workaround_value =
701 QPNP_IADC_RSENSE_DEFAULT_TYPEB_SMIC;
702 iadc->default_internal_rsense = true;
703 }
704 }
Dipen Parmarc908fd12014-03-25 17:50:58 +0530705 } else if (iadc->rds_trim_default_type == QPNP_IADC_RDS_DEFAULT_TYPEC) {
706
707 if ((smbb_batt_trm_cnst_rds >
708 SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_0) &&
709 (smbb_batt_trm_cnst_rds <=
710 SMBB_BAT_IF_TRIM_CNST_RDS_MASK_CONST_2) &&
711 (trim2_val == QPNP_IADC1_USR_TRIM2_ADC_FULLSCALE1_CONST)) {
712 iadc->rsense_workaround_value =
713 QPNP_IADC_RSENSE_DEFAULT_VALUE;
714 iadc->default_internal_rsense = true;
715 }
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -0800716 }
717
718 return 0;
719}
720
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700721static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700722{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700723 int rc = 0;
724
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700725 rc = qpnp_iadc_read_reg(iadc, QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700726 if (rc < 0) {
727 pr_err("qpnp adc comp id failed with %d\n", rc);
728 return rc;
729 }
730
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700731 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2,
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700732 &iadc->iadc_comp.revision_dig_major);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700733 if (rc < 0) {
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700734 pr_err("qpnp adc revision2 read failed with %d\n", rc);
735 return rc;
736 }
737
738 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION3,
739 &iadc->iadc_comp.revision_ana_minor);
740 if (rc < 0) {
741 pr_err("qpnp adc revision3 read failed with %d\n", rc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700742 return rc;
743 }
744
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700745 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700746 &iadc->iadc_comp.sys_gain);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700747 if (rc < 0) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700748 pr_err("full scale read failed with %d\n", rc);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700749 return rc;
750 }
751
752 if (iadc->external_rsense)
753 iadc->iadc_comp.ext_rsense = true;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700754
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700755 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 -0700756 iadc->iadc_comp.id,
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700757 iadc->iadc_comp.revision_dig_major,
758 iadc->iadc_comp.revision_ana_minor,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700759 iadc->iadc_comp.sys_gain,
760 iadc->iadc_comp.ext_rsense);
761 return rc;
762}
763
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700764static int32_t qpnp_iadc_configure(struct qpnp_iadc_chip *iadc,
765 enum qpnp_iadc_channels channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800766 uint16_t *raw_code, uint32_t mode_sel)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700767{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700768 u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
769 u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700770 u8 status1 = 0;
771 uint32_t count = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700772 int32_t rc = 0;
773
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700774 qpnp_iadc_ch_sel_reg = channel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700775
776 qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
777 QPNP_IADC_DEC_RATIO_SEL;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800778 if (iadc->iadc_mode_sel)
779 qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN);
780 else
781 qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
782
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700783 qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
784
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700785 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700786 if (rc) {
787 pr_err("qpnp adc read adc failed with %d\n", rc);
788 return rc;
789 }
790
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700791 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_ADC_CH_SEL_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700792 qpnp_iadc_ch_sel_reg);
793 if (rc) {
794 pr_err("qpnp adc read adc failed with %d\n", rc);
795 return rc;
796 }
797
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700798 rc = qpnp_iadc_write_reg(iadc, QPNP_ADC_DIG_PARAM,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700799 qpnp_iadc_dig_param_reg);
800 if (rc) {
801 pr_err("qpnp adc read adc failed with %d\n", rc);
802 return rc;
803 }
804
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700805 rc = qpnp_iadc_write_reg(iadc, QPNP_FAST_AVG_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700806 iadc->adc->amux_prop->fast_avg_setup);
807 if (rc < 0) {
808 pr_err("qpnp adc fast averaging configure error\n");
809 return rc;
810 }
811
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700812 if (!iadc->iadc_poll_eoc)
813 INIT_COMPLETION(iadc->adc->adc_rslt_completion);
Siddartha Mohanadoss3f219c42013-04-02 11:01:28 -0700814
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700815 rc = qpnp_iadc_enable(iadc, true);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700816 if (rc)
817 return rc;
818
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700819 rc = qpnp_iadc_write_reg(iadc, QPNP_CONV_REQ, qpnp_iadc_conv_req);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700820 if (rc) {
821 pr_err("qpnp adc read adc failed with %d\n", rc);
822 return rc;
823 }
824
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700825 if (iadc->iadc_poll_eoc) {
826 while (status1 != QPNP_STATUS1_EOC) {
827 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
828 if (rc < 0)
829 return rc;
830 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
831 usleep_range(QPNP_ADC_CONV_TIME_MIN,
832 QPNP_ADC_CONV_TIME_MAX);
833 count++;
834 if (count > QPNP_ADC_ERR_COUNT) {
835 pr_err("retry error exceeded\n");
836 rc = qpnp_iadc_status_debug(iadc);
837 if (rc < 0)
838 pr_err("IADC status debug failed\n");
839 rc = -EINVAL;
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800840 return rc;
841 }
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700842 }
843 } else {
844 rc = wait_for_completion_timeout(
845 &iadc->adc->adc_rslt_completion,
846 QPNP_ADC_COMPLETION_TIMEOUT);
847 if (!rc) {
848 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
849 if (rc < 0)
850 return rc;
851 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
852 if (status1 == QPNP_STATUS1_EOC)
853 pr_debug("End of conversion status set\n");
854 else {
855 rc = qpnp_iadc_status_debug(iadc);
856 if (rc < 0) {
857 pr_err("status debug failed %d\n", rc);
858 return rc;
859 }
860 return -EINVAL;
861 }
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700862 }
863 }
864
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700865 rc = qpnp_iadc_read_conversion_result(iadc, raw_code);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700866 if (rc) {
867 pr_err("qpnp adc read adc failed with %d\n", rc);
868 return rc;
869 }
870
871 return 0;
872}
873
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700874#define IADC_CENTER 0xC000
875#define IADC_READING_RESOLUTION_N 542535
876#define IADC_READING_RESOLUTION_D 100000
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700877static int32_t qpnp_convert_raw_offset_voltage(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700878{
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700879 s64 numerator;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700880
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800881 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
882 pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
883 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
884 return -EINVAL;
885 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700886
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700887 numerator = iadc->adc->calib.offset_raw - IADC_CENTER;
888 numerator *= IADC_READING_RESOLUTION_N;
889 iadc->adc->calib.offset_uv = div_s64(numerator,
890 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700891
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700892 numerator = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
893 numerator *= IADC_READING_RESOLUTION_N;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700894
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700895 iadc->adc->calib.gain_uv = div_s64(numerator,
896 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700897
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700898 pr_debug("gain_uv:%d offset_uv:%d\n",
899 iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700900 return 0;
901}
902
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700903#define IADC_IDEAL_RAW_GAIN 3291
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700904int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
905 bool batfet_closed)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700906{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700907 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss8b076be2014-03-11 19:03:03 -0700908 int32_t rc = 0, version = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700909 uint16_t raw_data;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800910 uint32_t mode_sel = 0;
Siddartha Mohanadoss8b076be2014-03-11 19:03:03 -0700911 bool iadc_offset_ch_batfet_check;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700912
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700913 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700914 return -EPROBE_DEFER;
915
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800916 mutex_lock(&iadc->adc->adc_lock);
917
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700918 if (iadc->iadc_poll_eoc) {
919 pr_debug("acquiring iadc eoc wakelock\n");
920 pm_stay_awake(iadc->dev);
921 }
922
Dipen Parmarba874582014-07-23 19:00:48 +0530923 iadc->adc->amux_prop->decimation = DECIMATION_TYPE1;
924 iadc->adc->amux_prop->fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
925
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700926 rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800927 &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700928 if (rc < 0) {
929 pr_err("qpnp adc result read failed with %d\n", rc);
930 goto fail;
931 }
932
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700933 iadc->adc->calib.gain_raw = raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700934
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700935 /*
Siddartha Mohanadoss8b076be2014-03-11 19:03:03 -0700936 * there is a features on PM8941 in the BMS where if the batfet is
937 * opened the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700938 * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
939 * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
940 * internal rsense.
941 */
Siddartha Mohanadoss8b076be2014-03-11 19:03:03 -0700942 version = qpnp_adc_get_revid_version(iadc->dev);
943 if ((version == QPNP_REV_ID_8941_3_1) ||
944 (version == QPNP_REV_ID_8941_3_0) ||
945 (version == QPNP_REV_ID_8941_2_0))
946 iadc_offset_ch_batfet_check = true;
947 else
948 iadc_offset_ch_batfet_check = false;
949
Siddartha Mohanadoss5e1e6ed2014-03-17 22:38:29 -0700950 if ((iadc_offset_ch_batfet_check && !batfet_closed) ||
951 (iadc->external_rsense)) {
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700952 /* external offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700953 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800954 &raw_data, mode_sel);
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700955 if (rc < 0) {
956 pr_err("qpnp adc result read failed with %d\n", rc);
957 goto fail;
958 }
959 } else {
960 /* internal offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700961 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2,
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700962 &raw_data, mode_sel);
963 if (rc < 0) {
964 pr_err("qpnp adc result read failed with %d\n", rc);
965 goto fail;
966 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700967 }
968
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700969 iadc->adc->calib.offset_raw = raw_data;
970 if (rc < 0) {
971 pr_err("qpnp adc offset/gain calculation failed\n");
972 goto fail;
973 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700974
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700975 if (iadc->iadc_comp.revision_dig_major == QPNP_IADC_PM8026_2_REV2
976 && iadc->iadc_comp.revision_ana_minor ==
977 QPNP_IADC_PM8026_2_REV3)
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700978 iadc->adc->calib.gain_raw =
979 iadc->adc->calib.offset_raw + IADC_IDEAL_RAW_GAIN;
980
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700981 pr_debug("raw gain:0x%x, raw offset:0x%x\n",
982 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
983
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700984 rc = qpnp_convert_raw_offset_voltage(iadc);
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800985 if (rc < 0) {
986 pr_err("qpnp raw_voltage conversion failed\n");
987 goto fail;
988 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700989
990 rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
991 QPNP_BIT_SHIFT_8;
992 rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
993
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700994 pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
995
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700996 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700997 QPNP_IADC_SEC_ACCESS_DATA);
998 if (rc < 0) {
999 pr_err("qpnp iadc configure error for sec access\n");
1000 goto fail;
1001 }
1002
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001003 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001004 rslt_msb);
1005 if (rc < 0) {
1006 pr_err("qpnp iadc configure error for MSB write\n");
1007 goto fail;
1008 }
1009
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001010 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001011 QPNP_IADC_SEC_ACCESS_DATA);
1012 if (rc < 0) {
1013 pr_err("qpnp iadc configure error for sec access\n");
1014 goto fail;
1015 }
1016
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001017 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001018 rslt_lsb);
1019 if (rc < 0) {
1020 pr_err("qpnp iadc configure error for LSB write\n");
1021 goto fail;
1022 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001023fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001024 if (iadc->iadc_poll_eoc) {
1025 pr_debug("releasing iadc eoc wakelock\n");
1026 pm_relax(iadc->dev);
1027 }
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001028 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001029 return rc;
1030}
Siddartha Mohanadoss06673922013-03-27 11:14:19 -07001031EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001032
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001033static void qpnp_iadc_work(struct work_struct *work)
1034{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001035 struct qpnp_iadc_chip *iadc = container_of(work,
1036 struct qpnp_iadc_chip, iadc_work.work);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001037 int rc = 0;
1038
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001039 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001040 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001041 if (rc)
1042 pr_debug("periodic IADC calibration failed\n");
1043 }
1044
1045 schedule_delayed_work(&iadc->iadc_work,
1046 round_jiffies_relative(msecs_to_jiffies
1047 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001048 return;
1049}
1050
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001051static int32_t qpnp_iadc_version_check(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001052{
1053 uint8_t revision;
1054 int rc;
1055
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001056 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &revision);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001057 if (rc < 0) {
1058 pr_err("qpnp adc result read failed with %d\n", rc);
1059 return rc;
1060 }
1061
1062 if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
1063 pr_err("IADC Version not supported\n");
1064 return -EINVAL;
1065 }
1066
1067 return 0;
1068}
1069
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001070struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001071{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001072 struct qpnp_iadc_chip *iadc;
1073 struct device_node *node = NULL;
1074 char prop_name[QPNP_MAX_PROP_NAME_LEN];
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001075
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001076 snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-iadc", name);
1077
1078 node = of_parse_phandle(dev->of_node, prop_name, 0);
1079 if (node == NULL)
1080 return ERR_PTR(-ENODEV);
1081
1082 list_for_each_entry(iadc, &qpnp_iadc_device_list, list)
1083 if (iadc->adc->spmi->dev.of_node == node)
1084 return iadc;
1085 return ERR_PTR(-EPROBE_DEFER);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001086}
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001087EXPORT_SYMBOL(qpnp_get_iadc);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001088
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001089int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001090{
Dipen Parmaraac5a342014-02-20 17:58:48 +05301091 uint8_t rslt_rsense = 0;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -07001092 int32_t rc = 0, sign_bit = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001093
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001094 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001095 return -EPROBE_DEFER;
1096
Siddartha Mohanadoss58279542013-05-28 16:20:46 -07001097 if (iadc->external_rsense) {
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -07001098 *rsense = iadc->rsense;
Dipen Parmaraac5a342014-02-20 17:58:48 +05301099 } else if (iadc->default_internal_rsense) {
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001100 *rsense = iadc->rsense_workaround_value;
Dipen Parmaraac5a342014-02-20 17:58:48 +05301101 } else {
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001102
Dipen Parmaraac5a342014-02-20 17:58:48 +05301103 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE,
1104 &rslt_rsense);
1105 if (rc < 0) {
1106 pr_err("qpnp adc rsense read failed with %d\n", rc);
1107 return rc;
1108 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001109
Dipen Parmaraac5a342014-02-20 17:58:48 +05301110 pr_debug("rsense:0%x\n", rslt_rsense);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001111
Dipen Parmaraac5a342014-02-20 17:58:48 +05301112 if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
1113 sign_bit = 1;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001114
Dipen Parmaraac5a342014-02-20 17:58:48 +05301115 rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001116
Dipen Parmaraac5a342014-02-20 17:58:48 +05301117 if (sign_bit)
1118 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001119 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
Dipen Parmaraac5a342014-02-20 17:58:48 +05301120 else
1121 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001122 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
Dipen Parmaraac5a342014-02-20 17:58:48 +05301123 }
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001124 pr_debug("rsense value is %d\n", *rsense);
1125
Dipen Parmaraac5a342014-02-20 17:58:48 +05301126 if (*rsense == 0)
1127 pr_err("incorrect rsens value:%d rslt_rsense:%d\n",
1128 *rsense, rslt_rsense);
1129
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001130 return rc;
1131}
Xiaozhe Shi767fdb62013-01-10 15:09:08 -08001132EXPORT_SYMBOL(qpnp_iadc_get_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001133
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001134static int32_t qpnp_check_pmic_temp(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001135{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001136 struct qpnp_vadc_result result_pmic_therm;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -07001137 int64_t die_temp_offset;
Siddartha Mohanadossd752e472013-02-26 18:30:14 -08001138 int rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001139
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001140 rc = qpnp_vadc_read(iadc->vadc_dev, DIE_TEMP, &result_pmic_therm);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001141 if (rc < 0)
1142 return rc;
1143
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -07001144 die_temp_offset = result_pmic_therm.physical -
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001145 iadc->die_temp;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -07001146 if (die_temp_offset < 0)
1147 die_temp_offset = -die_temp_offset;
1148
1149 if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -07001150 iadc->die_temp = result_pmic_therm.physical;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001151 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001152 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001153 if (rc)
1154 pr_err("IADC calibration failed rc = %d\n", rc);
1155 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001156 }
1157
Siddartha Mohanadossd752e472013-02-26 18:30:14 -08001158 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001159}
1160
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001161int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
1162 enum qpnp_iadc_channels channel,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001163 struct qpnp_iadc_result *result)
1164{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001165 int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001166 int32_t rsense_u_ohms = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001167 int64_t result_current;
1168 uint16_t raw_data;
Dipen Parmarba874582014-07-23 19:00:48 +05301169 int dt_index = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001170
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001171 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001172 return -EPROBE_DEFER;
1173
Dipen Parmar454c4b12013-11-25 14:40:47 +05301174 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
1175 pr_err("raw offset errors! run iadc calibration again\n");
1176 return -EINVAL;
1177 }
1178
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001179 rc = qpnp_check_pmic_temp(iadc);
1180 if (rc) {
1181 pr_err("Error checking pmic therm temp\n");
1182 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001183 }
1184
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001185 mutex_lock(&iadc->adc->adc_lock);
1186
Dipen Parmarba874582014-07-23 19:00:48 +05301187 while (((enum qpnp_iadc_channels)
1188 iadc->adc->adc_channels[dt_index].channel_num
1189 != channel) && (dt_index < iadc->max_channels_available))
1190 dt_index++;
1191
1192 if (dt_index >= iadc->max_channels_available) {
1193 pr_err("not a valid IADC channel\n");
1194 rc = -EINVAL;
1195 goto fail;
1196 }
1197
1198 iadc->adc->amux_prop->decimation =
1199 iadc->adc->adc_channels[dt_index].adc_decimation;
1200 iadc->adc->amux_prop->fast_avg_setup =
1201 iadc->adc->adc_channels[dt_index].fast_avg_setup;
1202
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001203 if (iadc->iadc_poll_eoc) {
1204 pr_debug("acquiring iadc eoc wakelock\n");
1205 pm_stay_awake(iadc->dev);
1206 }
1207
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001208 rc = qpnp_iadc_configure(iadc, channel, &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001209 if (rc < 0) {
1210 pr_err("qpnp adc result read failed with %d\n", rc);
1211 goto fail;
1212 }
1213
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001214 rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001215 pr_debug("current raw:0%x and rsense:%d\n",
1216 raw_data, rsense_n_ohms);
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001217 rsense_u_ohms = rsense_n_ohms/1000;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001218 num = raw_data - iadc->adc->calib.offset_raw;
1219 if (num < 0) {
1220 sign = 1;
1221 num = -num;
1222 }
1223
1224 result->result_uv = (num * QPNP_ADC_GAIN_NV)/
1225 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
1226 result_current = result->result_uv;
1227 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001228 /* Intentional fall through. Process the result w/o comp */
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001229 do_div(result_current, rsense_u_ohms);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001230
1231 if (sign) {
1232 result->result_uv = -result->result_uv;
1233 result_current = -result_current;
1234 }
Xiaozhe Shie51d5542013-11-01 13:06:14 -07001235 result_current *= -1;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001236 rc = qpnp_iadc_comp_result(iadc, &result_current);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001237 if (rc < 0)
1238 pr_err("Error during compensating the IADC\n");
1239 rc = 0;
Xiaozhe Shie51d5542013-11-01 13:06:14 -07001240 result_current *= -1;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001241
1242 result->result_ua = (int32_t) result_current;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001243fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001244 if (iadc->iadc_poll_eoc) {
1245 pr_debug("releasing iadc eoc wakelock\n");
1246 pm_relax(iadc->dev);
1247 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001248 mutex_unlock(&iadc->adc->adc_lock);
1249
1250 return rc;
1251}
1252EXPORT_SYMBOL(qpnp_iadc_read);
1253
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001254int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
1255 struct qpnp_iadc_calib *result)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001256{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001257 int rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001258
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001259 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001260 return -EPROBE_DEFER;
1261
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001262 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001263 if (rc) {
1264 pr_err("Error checking pmic therm temp\n");
1265 return rc;
1266 }
1267
1268 mutex_lock(&iadc->adc->adc_lock);
1269 result->gain_raw = iadc->adc->calib.gain_raw;
1270 result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
1271 result->gain_uv = iadc->adc->calib.gain_uv;
1272 result->offset_raw = iadc->adc->calib.offset_raw;
1273 result->ideal_offset_uv =
1274 QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
1275 result->offset_uv = iadc->adc->calib.offset_uv;
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001276 pr_debug("raw gain:0%x, raw offset:0%x\n",
1277 result->gain_raw, result->offset_raw);
1278 pr_debug("gain_uv:%d offset_uv:%d\n",
1279 result->gain_uv, result->offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001280 mutex_unlock(&iadc->adc->adc_lock);
1281
1282 return 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001283}
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001284EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001285
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001286int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001287{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001288 iadc->skip_auto_calibrations = true;
1289 return 0;
1290}
1291EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
1292
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001293int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001294{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001295 iadc->skip_auto_calibrations = false;
1296 return 0;
1297}
1298EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
1299
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001300int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001301 enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
1302 enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
1303{
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001304 int rc = 0, mode_sel = 0, num = 0, rsense_n_ohms = 0, sign = 0;
Dipen Parmarba874582014-07-23 19:00:48 +05301305 int dt_index = 0;
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001306 uint16_t raw_data;
1307 int32_t rsense_u_ohms = 0;
1308 int64_t result_current;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001309
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001310 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001311 return -EPROBE_DEFER;
1312
Dipen Parmaraac5a342014-02-20 17:58:48 +05301313 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
1314 pr_err("raw offset errors! run iadc calibration again\n");
1315 return -EINVAL;
1316 }
1317
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001318 mutex_lock(&iadc->adc->adc_lock);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001319
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001320 if (iadc->iadc_poll_eoc) {
1321 pr_debug("acquiring iadc eoc wakelock\n");
1322 pm_stay_awake(iadc->dev);
1323 }
1324
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001325 iadc->iadc_mode_sel = true;
1326
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001327 rc = qpnp_vadc_iadc_sync_request(iadc->vadc_dev, v_channel);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001328 if (rc) {
1329 pr_err("Configuring VADC failed\n");
1330 goto fail;
1331 }
1332
Dipen Parmarba874582014-07-23 19:00:48 +05301333 while (((enum qpnp_iadc_channels)
1334 iadc->adc->adc_channels[dt_index].channel_num
1335 != i_channel) && (dt_index < iadc->max_channels_available))
1336 dt_index++;
1337
1338 if (dt_index >= iadc->max_channels_available) {
1339 pr_err("not a valid IADC channel\n");
1340 rc = -EINVAL;
1341 goto fail;
1342 }
1343
1344 iadc->adc->amux_prop->decimation =
1345 iadc->adc->adc_channels[dt_index].adc_decimation;
1346 iadc->adc->amux_prop->fast_avg_setup =
1347 iadc->adc->adc_channels[dt_index].fast_avg_setup;
1348
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001349 rc = qpnp_iadc_configure(iadc, i_channel, &raw_data, mode_sel);
1350 if (rc < 0) {
1351 pr_err("qpnp adc result read failed with %d\n", rc);
1352 goto fail_release_vadc;
1353 }
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001354
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001355 rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
1356 pr_debug("current raw:0%x and rsense:%d\n",
1357 raw_data, rsense_n_ohms);
1358 rsense_u_ohms = rsense_n_ohms/1000;
1359 num = raw_data - iadc->adc->calib.offset_raw;
1360 if (num < 0) {
1361 sign = 1;
1362 num = -num;
1363 }
1364
1365 i_result->result_uv = (num * QPNP_ADC_GAIN_NV)/
1366 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
1367 result_current = i_result->result_uv;
1368 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
1369 /* Intentional fall through. Process the result w/o comp */
Dipen Parmaraac5a342014-02-20 17:58:48 +05301370 if (!rsense_u_ohms) {
1371 pr_err("rsense error=%d\n", rsense_u_ohms);
1372 goto fail_release_vadc;
1373 }
1374
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001375 do_div(result_current, rsense_u_ohms);
1376
1377 if (sign) {
1378 i_result->result_uv = -i_result->result_uv;
1379 result_current = -result_current;
1380 }
1381 result_current *= -1;
1382 rc = qpnp_iadc_comp_result(iadc, &result_current);
1383 if (rc < 0)
1384 pr_err("Error during compensating the IADC\n");
1385 rc = 0;
1386 result_current *= -1;
1387
1388 i_result->result_ua = (int32_t) result_current;
1389
1390fail_release_vadc:
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001391 rc = qpnp_vadc_iadc_sync_complete_request(iadc->vadc_dev, v_channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001392 v_result);
1393 if (rc)
1394 pr_err("Releasing VADC failed\n");
1395fail:
1396 iadc->iadc_mode_sel = false;
1397
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001398 if (iadc->iadc_poll_eoc) {
1399 pr_debug("releasing iadc eoc wakelock\n");
1400 pm_relax(iadc->dev);
1401 }
Siddartha Mohanadoss797508e2013-11-22 16:28:30 -08001402 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001403
1404 return rc;
1405}
1406EXPORT_SYMBOL(qpnp_iadc_vadc_sync_read);
1407
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001408static ssize_t qpnp_iadc_show(struct device *dev,
1409 struct device_attribute *devattr, char *buf)
1410{
1411 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001412 struct qpnp_iadc_chip *iadc = dev_get_drvdata(dev);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001413 struct qpnp_iadc_result result;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001414 int rc = -1;
1415
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001416 rc = qpnp_iadc_read(iadc, attr->index, &result);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001417
1418 if (rc)
1419 return 0;
1420
1421 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001422 "Result:%d\n", result.result_ua);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001423}
1424
1425static struct sensor_device_attribute qpnp_adc_attr =
1426 SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
1427
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001428static int32_t qpnp_iadc_init_hwmon(struct qpnp_iadc_chip *iadc,
1429 struct spmi_device *spmi)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001430{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001431 struct device_node *child;
1432 struct device_node *node = spmi->dev.of_node;
1433 int rc = 0, i = 0, channel;
1434
1435 for_each_child_of_node(node, child) {
1436 channel = iadc->adc->adc_channels[i].channel_num;
1437 qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
1438 qpnp_adc_attr.dev_attr.attr.name =
1439 iadc->adc->adc_channels[i].name;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001440 memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
1441 sizeof(qpnp_adc_attr));
Stephen Boyd8a5c4e42012-10-30 11:07:22 -07001442 sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001443 rc = device_create_file(&spmi->dev,
1444 &iadc->sens_attr[i].dev_attr);
1445 if (rc) {
1446 dev_err(&spmi->dev,
1447 "device_create_file failed for dev %s\n",
1448 iadc->adc->adc_channels[i].name);
1449 goto hwmon_err_sens;
1450 }
1451 i++;
1452 }
1453
1454 return 0;
1455hwmon_err_sens:
1456 pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
1457 return rc;
1458}
1459
1460static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
1461{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001462 struct qpnp_iadc_chip *iadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001463 struct qpnp_adc_drv *adc_qpnp;
1464 struct device_node *node = spmi->dev.of_node;
1465 struct device_node *child;
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001466 struct resource *res;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001467 int rc, count_adc_channel_list = 0, i = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001468
1469 for_each_child_of_node(node, child)
1470 count_adc_channel_list++;
1471
1472 if (!count_adc_channel_list) {
1473 pr_err("No channel listing\n");
1474 return -EINVAL;
1475 }
1476
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001477 iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_chip) +
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001478 (sizeof(struct sensor_device_attribute) *
1479 count_adc_channel_list), GFP_KERNEL);
1480 if (!iadc) {
1481 dev_err(&spmi->dev, "Unable to allocate memory\n");
1482 return -ENOMEM;
1483 }
1484
1485 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1486 GFP_KERNEL);
1487 if (!adc_qpnp) {
1488 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossc61babb2013-08-02 13:37:12 -07001489 return -ENOMEM;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001490 }
1491
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001492 iadc->dev = &(spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001493 iadc->adc = adc_qpnp;
1494
1495 rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
1496 if (rc) {
1497 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossc61babb2013-08-02 13:37:12 -07001498 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001499 }
1500
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001501 res = spmi_get_resource_byname(spmi, NULL, IORESOURCE_MEM,
1502 "batt-id-trim-cnst-rds");
1503 if (!res) {
1504 dev_err(&spmi->dev, "failed to read batt_id trim register\n");
1505 return -EINVAL;
1506 }
1507 iadc->batt_id_trim_cnst_rds = res->start;
1508 rc = of_property_read_u32(node, "qcom,use-default-rds-trim",
1509 &iadc->rds_trim_default_type);
1510 if (rc)
1511 pr_debug("No trim workaround needed\n");
1512 else {
1513 pr_debug("Use internal RDS trim workaround\n");
1514 iadc->rds_trim_default_check = true;
1515 }
1516
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001517 iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
1518 if (IS_ERR(iadc->vadc_dev)) {
1519 rc = PTR_ERR(iadc->vadc_dev);
1520 if (rc != -EPROBE_DEFER)
1521 pr_err("vadc property missing, rc=%d\n", rc);
Siddartha Mohanadossc61babb2013-08-02 13:37:12 -07001522 return rc;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001523 }
1524
Stephen Boydbeab4502013-04-25 10:18:17 -07001525 mutex_init(&iadc->adc->adc_lock);
1526
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001527 rc = of_property_read_u32(node, "qcom,rsense",
1528 &iadc->rsense);
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -07001529 if (rc)
1530 pr_debug("Defaulting to internal rsense\n");
1531 else {
1532 pr_debug("Use external rsense\n");
1533 iadc->external_rsense = true;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001534 }
1535
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001536 iadc->iadc_poll_eoc = of_property_read_bool(node,
1537 "qcom,iadc-poll-eoc");
1538 if (!iadc->iadc_poll_eoc) {
1539 rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
1540 qpnp_iadc_isr, IRQF_TRIGGER_RISING,
1541 "qpnp_iadc_interrupt", iadc);
1542 if (rc) {
1543 dev_err(&spmi->dev, "failed to request adc irq\n");
1544 return rc;
1545 } else
1546 enable_irq_wake(iadc->adc->adc_irq_eoc);
1547 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001548
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001549 rc = qpnp_iadc_init_hwmon(iadc, spmi);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001550 if (rc) {
1551 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001552 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001553 }
1554 iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
1555
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001556 rc = qpnp_iadc_version_check(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001557 if (rc) {
1558 dev_err(&spmi->dev, "IADC version not supported\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001559 goto fail;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001560 }
1561
Dipen Parmarba874582014-07-23 19:00:48 +05301562 iadc->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001563 INIT_WORK(&iadc->trigger_completion_work, qpnp_iadc_trigger_completion);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001564 INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001565 rc = qpnp_iadc_comp_info(iadc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001566 if (rc) {
1567 dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
1568 goto fail;
1569 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001570
Siddartha Mohanadoss18c4b9f2014-01-23 16:13:31 -08001571 rc = qpnp_iadc_rds_trim_update_check(iadc);
1572 if (rc) {
1573 dev_err(&spmi->dev, "Rds trim update failed!\n");
1574 goto fail;
1575 }
1576
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001577 dev_set_drvdata(&spmi->dev, iadc);
1578 list_add(&iadc->list, &qpnp_iadc_device_list);
1579 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001580 if (rc)
1581 dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001582
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001583 if (iadc->iadc_poll_eoc)
1584 device_init_wakeup(iadc->dev, 1);
1585
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001586 schedule_delayed_work(&iadc->iadc_work,
1587 round_jiffies_relative(msecs_to_jiffies
1588 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001589 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001590fail:
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001591 for_each_child_of_node(node, child) {
1592 device_remove_file(&spmi->dev,
1593 &iadc->sens_attr[i].dev_attr);
1594 i++;
1595 }
1596 hwmon_device_unregister(iadc->iadc_hwmon);
1597
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001598 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001599}
1600
1601static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
1602{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001603 struct qpnp_iadc_chip *iadc = dev_get_drvdata(&spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001604 struct device_node *node = spmi->dev.of_node;
1605 struct device_node *child;
1606 int i = 0;
1607
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001608 cancel_delayed_work(&iadc->iadc_work);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001609 for_each_child_of_node(node, child) {
1610 device_remove_file(&spmi->dev,
1611 &iadc->sens_attr[i].dev_attr);
1612 i++;
1613 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001614 hwmon_device_unregister(iadc->iadc_hwmon);
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001615 if (iadc->iadc_poll_eoc)
1616 pm_relax(iadc->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001617 dev_set_drvdata(&spmi->dev, NULL);
1618
1619 return 0;
1620}
1621
1622static const struct of_device_id qpnp_iadc_match_table[] = {
1623 { .compatible = "qcom,qpnp-iadc",
1624 },
1625 {}
1626};
1627
1628static struct spmi_driver qpnp_iadc_driver = {
1629 .driver = {
1630 .name = "qcom,qpnp-iadc",
1631 .of_match_table = qpnp_iadc_match_table,
1632 },
1633 .probe = qpnp_iadc_probe,
1634 .remove = qpnp_iadc_remove,
1635};
1636
1637static int __init qpnp_iadc_init(void)
1638{
1639 return spmi_driver_register(&qpnp_iadc_driver);
1640}
1641module_init(qpnp_iadc_init);
1642
1643static void __exit qpnp_iadc_exit(void)
1644{
1645 spmi_driver_unregister(&qpnp_iadc_driver);
1646}
1647module_exit(qpnp_iadc_exit);
1648
1649MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
1650MODULE_LICENSE("GPL v2");