blob: b89568de46c4135136e4fed045b38326431cf8ee [file] [log] [blame]
Xiaozhe Shi767fdb62013-01-10 15:09:08 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/kernel.h>
16#include <linux/of.h>
17#include <linux/err.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/delay.h>
21#include <linux/mutex.h>
22#include <linux/types.h>
23#include <linux/hwmon.h>
24#include <linux/module.h>
25#include <linux/debugfs.h>
26#include <linux/spmi.h>
27#include <linux/of_irq.h>
28#include <linux/wakelock.h>
29#include <linux/interrupt.h>
30#include <linux/completion.h>
31#include <linux/hwmon-sysfs.h>
32#include <linux/qpnp/qpnp-adc.h>
33#include <linux/platform_device.h>
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -070034#include <linux/wakelock.h>
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070035
36/* QPNP IADC register definition */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070037#define QPNP_IADC_REVISION1 0x0
38#define QPNP_IADC_REVISION2 0x1
39#define QPNP_IADC_REVISION3 0x2
40#define QPNP_IADC_REVISION4 0x3
41#define QPNP_IADC_PERPH_TYPE 0x4
42#define QPNP_IADC_PERH_SUBTYPE 0x5
43
44#define QPNP_IADC_SUPPORTED_REVISION2 1
45
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070046#define QPNP_STATUS1 0x8
47#define QPNP_STATUS1_OP_MODE 4
48#define QPNP_STATUS1_MULTI_MEAS_EN BIT(3)
49#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
50#define QPNP_STATUS1_REQ_STS BIT(1)
51#define QPNP_STATUS1_EOC BIT(0)
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -070052#define QPNP_STATUS1_REQ_STS_EOC_MASK 0x3
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070053#define QPNP_STATUS2 0x9
54#define QPNP_STATUS2_CONV_SEQ_STATE_SHIFT 4
55#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
56#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
57#define QPNP_CONV_TIMEOUT_ERR 2
58
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070059#define QPNP_IADC_MODE_CTL 0x40
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070060#define QPNP_OP_MODE_SHIFT 4
61#define QPNP_USE_BMS_DATA BIT(4)
62#define QPNP_VADC_SYNCH_EN BIT(2)
63#define QPNP_OFFSET_RMV_EN BIT(1)
64#define QPNP_ADC_TRIM_EN BIT(0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070065#define QPNP_IADC_EN_CTL1 0x46
66#define QPNP_IADC_ADC_EN BIT(7)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070067#define QPNP_ADC_CH_SEL_CTL 0x48
68#define QPNP_ADC_DIG_PARAM 0x50
69#define QPNP_ADC_CLK_SEL_MASK 0x3
70#define QPNP_ADC_DEC_RATIO_SEL_MASK 0xc
71#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 2
72
73#define QPNP_HW_SETTLE_DELAY 0x51
74#define QPNP_CONV_REQ 0x52
75#define QPNP_CONV_REQ_SET BIT(7)
76#define QPNP_CONV_SEQ_CTL 0x54
77#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
78#define QPNP_CONV_SEQ_TRIG_CTL 0x55
79#define QPNP_FAST_AVG_CTL 0x5a
80
81#define QPNP_M0_LOW_THR_LSB 0x5c
82#define QPNP_M0_LOW_THR_MSB 0x5d
83#define QPNP_M0_HIGH_THR_LSB 0x5e
84#define QPNP_M0_HIGH_THR_MSB 0x5f
85#define QPNP_M1_LOW_THR_LSB 0x69
86#define QPNP_M1_LOW_THR_MSB 0x6a
87#define QPNP_M1_HIGH_THR_LSB 0x6b
88#define QPNP_M1_HIGH_THR_MSB 0x6c
89
90#define QPNP_DATA0 0x60
91#define QPNP_DATA1 0x61
92#define QPNP_CONV_TIMEOUT_ERR 2
93
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -070094#define QPNP_IADC_SEC_ACCESS 0xD0
95#define QPNP_IADC_SEC_ACCESS_DATA 0xA5
96#define QPNP_IADC_MSB_OFFSET 0xF2
97#define QPNP_IADC_LSB_OFFSET 0xF3
98#define QPNP_IADC_NOMINAL_RSENSE 0xF4
99#define QPNP_IADC_ATE_GAIN_CALIB_OFFSET 0xF5
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700100#define QPNP_INT_TEST_VAL 0xE1
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700101
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700102#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
103#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
104
105#define QPNP_IADC_ADC_DIG_PARAM 0x50
106#define QPNP_IADC_CLK_SEL_SHIFT 1
107#define QPNP_IADC_DEC_RATIO_SEL 3
108
109#define QPNP_IADC_CONV_REQUEST 0x52
110#define QPNP_IADC_CONV_REQ BIT(7)
111
112#define QPNP_IADC_DATA0 0x60
113#define QPNP_IADC_DATA1 0x61
114
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700115#define QPNP_ADC_CONV_TIME_MIN 2000
116#define QPNP_ADC_CONV_TIME_MAX 2100
117#define QPNP_ADC_ERR_COUNT 20
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700118
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700119#define QPNP_ADC_GAIN_NV 17857
120#define QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL 0
121#define QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR 10000000
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -0700122#define QPNP_IADC_NANO_VOLTS_FACTOR 1000000
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700123#define QPNP_IADC_CALIB_SECONDS 300000
124#define QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT 15625
125#define QPNP_IADC_DIE_TEMP_CALIB_OFFSET 5000
126
127#define QPNP_RAW_CODE_16_BIT_MSB_MASK 0xff00
128#define QPNP_RAW_CODE_16_BIT_LSB_MASK 0xff
129#define QPNP_BIT_SHIFT_8 8
130#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700131#define QPNP_ADC_COMPLETION_TIMEOUT HZ
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700132
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700133struct qpnp_iadc_comp {
134 bool ext_rsense;
135 u8 id;
136 u8 sys_gain;
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700137 u8 revision_dig_major;
138 u8 revision_ana_minor;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700139};
140
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700141struct qpnp_iadc_chip {
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700142 struct device *dev;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700143 struct qpnp_adc_drv *adc;
144 int32_t rsense;
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700145 bool external_rsense;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700146 struct device *iadc_hwmon;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700147 struct list_head list;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700148 int64_t die_temp;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700149 struct delayed_work iadc_work;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800150 struct mutex iadc_vadc_lock;
151 bool iadc_mode_sel;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700152 struct qpnp_iadc_comp iadc_comp;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700153 struct qpnp_vadc_chip *vadc_dev;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700154 struct work_struct trigger_completion_work;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700155 bool skip_auto_calibrations;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700156 bool iadc_poll_eoc;
157 struct sensor_device_attribute sens_attr[0];
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700158};
159
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700160LIST_HEAD(qpnp_iadc_device_list);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700161
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700162static int32_t qpnp_iadc_read_reg(struct qpnp_iadc_chip *iadc,
163 uint32_t reg, u8 *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700164{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700165 int rc;
166
167 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700168 (iadc->adc->offset + reg), data, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700169 if (rc < 0) {
170 pr_err("qpnp iadc read reg %d failed with %d\n", reg, rc);
171 return rc;
172 }
173
174 return 0;
175}
176
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700177static int32_t qpnp_iadc_write_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 u8 *buf;
182
183 buf = &data;
184 rc = spmi_ext_register_writel(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700185 (iadc->adc->offset + reg), buf, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700186 if (rc < 0) {
187 pr_err("qpnp iadc write 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 int qpnp_iadc_is_valid(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800195{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700196 struct qpnp_iadc_chip *iadc_chip = NULL;
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800197
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700198 list_for_each_entry(iadc_chip, &qpnp_iadc_device_list, list)
199 if (iadc == iadc_chip)
200 return 0;
201
202 return -EINVAL;
203}
204
205static void qpnp_iadc_trigger_completion(struct work_struct *work)
206{
207 struct qpnp_iadc_chip *iadc = container_of(work,
208 struct qpnp_iadc_chip, trigger_completion_work);
209
210 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800211 return;
212
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800213 complete(&iadc->adc->adc_rslt_completion);
214
215 return;
216}
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800217
218static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
219{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700220 struct qpnp_iadc_chip *iadc = dev_id;
221
222 schedule_work(&iadc->trigger_completion_work);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800223
224 return IRQ_HANDLED;
225}
226
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700227static int32_t qpnp_iadc_enable(struct qpnp_iadc_chip *dev, bool state)
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800228{
229 int rc = 0;
230 u8 data = 0;
231
232 data = QPNP_IADC_ADC_EN;
233 if (state) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700234 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800235 data);
236 if (rc < 0) {
237 pr_err("IADC enable failed\n");
238 return rc;
239 }
240 } else {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700241 rc = qpnp_iadc_write_reg(dev, QPNP_IADC_EN_CTL1,
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800242 (~data & QPNP_IADC_ADC_EN));
243 if (rc < 0) {
244 pr_err("IADC disable failed\n");
245 return rc;
246 }
247 }
248
249 return 0;
250}
251
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700252static int32_t qpnp_iadc_status_debug(struct qpnp_iadc_chip *dev)
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800253{
254 int rc = 0;
255 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0;
256
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700257 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_MODE_CTL, &mode);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800258 if (rc < 0) {
259 pr_err("mode ctl register read failed with %d\n", rc);
260 return rc;
261 }
262
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700263 rc = qpnp_iadc_read_reg(dev, QPNP_ADC_DIG_PARAM, &dig);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800264 if (rc < 0) {
265 pr_err("digital param read failed with %d\n", rc);
266 return rc;
267 }
268
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700269 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_ADC_CH_SEL_CTL, &chan);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800270 if (rc < 0) {
271 pr_err("channel read failed with %d\n", rc);
272 return rc;
273 }
274
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700275 rc = qpnp_iadc_read_reg(dev, QPNP_STATUS1, &status1);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800276 if (rc < 0) {
277 pr_err("status1 read failed with %d\n", rc);
278 return rc;
279 }
280
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700281 rc = qpnp_iadc_read_reg(dev, QPNP_IADC_EN_CTL1, &en);
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800282 if (rc < 0) {
283 pr_err("en read failed with %d\n", rc);
284 return rc;
285 }
286
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700287 pr_debug("EOC not set with status:%x, dig:%x, ch:%x, mode:%x, en:%x\n",
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800288 status1, dig, chan, mode, en);
289
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700290 rc = qpnp_iadc_enable(dev, false);
Siddartha Mohanadosse2363592012-12-14 18:59:01 -0800291 if (rc < 0) {
292 pr_err("IADC disable failed with %d\n", rc);
293 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700294 }
295
296 return 0;
297}
298
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700299static int32_t qpnp_iadc_read_conversion_result(struct qpnp_iadc_chip *iadc,
300 int16_t *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700301{
302 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700303 uint16_t rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700304 int32_t rc;
305
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700306 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA0, &rslt_lsb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700307 if (rc < 0) {
308 pr_err("qpnp adc result read failed with %d\n", rc);
309 return rc;
310 }
311
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700312 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_DATA1, &rslt_msb);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700313 if (rc < 0) {
314 pr_err("qpnp adc result read failed with %d\n", rc);
315 return rc;
316 }
317
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700318 rslt = (rslt_msb << 8) | rslt_lsb;
319 *data = rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700320
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700321 rc = qpnp_iadc_enable(iadc, false);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700322 if (rc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700323 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700324
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700325 return 0;
326}
327
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700328#define QPNP_IADC_PM8941_3_1_REV2 3
329#define QPNP_IADC_PM8941_3_1_REV3 2
330#define QPNP_IADC_PM8026_1_REV2 1
331#define QPNP_IADC_PM8026_1_REV3 2
332#define QPNP_IADC_PM8026_2_REV2 4
333#define QPNP_IADC_PM8026_2_REV3 2
334#define QPNP_IADC_PM8110_1_REV2 2
335#define QPNP_IADC_PM8110_1_REV3 2
336
337#define QPNP_IADC_REV_ID_8941_3_1 1
338#define QPNP_IADC_REV_ID_8026_1_0 2
339#define QPNP_IADC_REV_ID_8026_2_0 3
340#define QPNP_IADC_REV_ID_8110_1_0 4
341
342static void qpnp_temp_comp_version_check(struct qpnp_iadc_chip *iadc,
343 int32_t *version)
344{
345 if ((iadc->iadc_comp.revision_dig_major ==
346 QPNP_IADC_PM8941_3_1_REV2) &&
347 (iadc->iadc_comp.revision_ana_minor ==
348 QPNP_IADC_PM8941_3_1_REV3))
349 *version = QPNP_IADC_REV_ID_8941_3_1;
350 else if ((iadc->iadc_comp.revision_dig_major ==
351 QPNP_IADC_PM8026_1_REV2) &&
352 (iadc->iadc_comp.revision_ana_minor ==
353 QPNP_IADC_PM8026_1_REV3))
354 *version = QPNP_IADC_REV_ID_8026_1_0;
355 else if ((iadc->iadc_comp.revision_dig_major ==
356 QPNP_IADC_PM8026_2_REV2) &&
357 (iadc->iadc_comp.revision_ana_minor ==
358 QPNP_IADC_PM8026_2_REV3))
359 *version = QPNP_IADC_REV_ID_8026_2_0;
360 else if ((iadc->iadc_comp.revision_dig_major ==
361 QPNP_IADC_PM8110_1_REV2) &&
362 (iadc->iadc_comp.revision_ana_minor ==
363 QPNP_IADC_PM8110_1_REV3))
364 *version = QPNP_IADC_REV_ID_8110_1_0;
365 else
366 *version = -EINVAL;
367
368 return;
369}
370
371#define QPNP_COEFF_1 969000
372#define QPNP_COEFF_2 32
373#define QPNP_COEFF_3_TYPEA 1700000
374#define QPNP_COEFF_3_TYPEB 1000000
375#define QPNP_COEFF_4 100
376#define QPNP_COEFF_5 15000
377#define QPNP_COEFF_6 100000
378#define QPNP_COEFF_7 21700
379#define QPNP_COEFF_8 100000000
380#define QPNP_COEFF_9 38
381#define QPNP_COEFF_10 40
382#define QPNP_COEFF_11 7
383#define QPNP_COEFF_12 11
384#define QPNP_COEFF_13 37
385#define QPNP_COEFF_14 39
386#define QPNP_COEFF_15 9
387#define QPNP_COEFF_16 11
388#define QPNP_COEFF_17 851200
389#define QPNP_COEFF_18 296500
390#define QPNP_COEFF_19 222400
391#define QPNP_COEFF_20 813800
392#define QPNP_COEFF_21 1059100
393#define QPNP_COEFF_22 5000000
394#define QPNP_COEFF_23 3722500
395#define QPNP_COEFF_24 84
396
397static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_chip *iadc,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700398 int64_t die_temp)
399{
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700400 int64_t temp_var = 0, sys_gain_coeff = 0, old;
401 int32_t coeff_a = 0, coeff_b = 0;
402 int32_t version;
403
404 qpnp_temp_comp_version_check(iadc, &version);
405 if (version == -EINVAL)
406 return 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700407
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700408 old = *result;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700409 *result = *result * 1000000;
410
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700411 if (iadc->iadc_comp.sys_gain > 127)
412 sys_gain_coeff = -QPNP_COEFF_6 *
413 (iadc->iadc_comp.sys_gain - 128);
414 else
415 sys_gain_coeff = QPNP_COEFF_6 *
416 iadc->iadc_comp.sys_gain;
417
418 switch (version) {
419 case QPNP_IADC_REV_ID_8941_3_1:
420 switch (iadc->iadc_comp.id) {
421 case COMP_ID_GF:
422 if (!iadc->iadc_comp.ext_rsense) {
423 /* internal rsense */
424 coeff_a = QPNP_COEFF_2;
425 coeff_b = -QPNP_COEFF_3_TYPEA;
426 } else {
427 if (*result < 0) {
428 /* charge */
429 coeff_a = QPNP_COEFF_5;
430 coeff_b = QPNP_COEFF_6;
431 } else {
432 /* discharge */
433 coeff_a = -QPNP_COEFF_7;
434 coeff_b = QPNP_COEFF_6;
435 }
436 }
437 break;
438 case COMP_ID_TSMC:
439 default:
440 if (!iadc->iadc_comp.ext_rsense) {
441 /* internal rsense */
442 coeff_a = QPNP_COEFF_2;
443 coeff_b = -QPNP_COEFF_3_TYPEB;
444 } else {
445 if (*result < 0) {
446 /* charge */
447 coeff_a = QPNP_COEFF_5;
448 coeff_b = QPNP_COEFF_6;
449 } else {
450 /* discharge */
451 coeff_a = -QPNP_COEFF_7;
452 coeff_b = QPNP_COEFF_6;
453 }
454 }
455 break;
456 }
457 break;
458 case QPNP_IADC_REV_ID_8026_1_0:
459 /* pm8026 rev 1.0 */
460 switch (iadc->iadc_comp.id) {
461 case COMP_ID_GF:
462 if (!iadc->iadc_comp.ext_rsense) {
463 /* internal rsense */
464 if (*result < 0) {
465 /* charge */
466 coeff_a = QPNP_COEFF_9;
467 coeff_b = -QPNP_COEFF_17;
468 } else {
469 coeff_a = QPNP_COEFF_10;
470 coeff_b = QPNP_COEFF_18;
471 }
472 } else {
473 if (*result < 0) {
474 /* charge */
475 coeff_a = -QPNP_COEFF_11;
476 coeff_b = 0;
477 } else {
478 /* discharge */
479 coeff_a = -QPNP_COEFF_17;
480 coeff_b = -QPNP_COEFF_19;
481 }
482 }
483 break;
484 case COMP_ID_TSMC:
485 default:
486 if (!iadc->iadc_comp.ext_rsense) {
487 /* internal rsense */
488 if (*result < 0) {
489 /* charge */
490 coeff_a = QPNP_COEFF_13;
491 coeff_b = -QPNP_COEFF_20;
492 } else {
493 coeff_a = QPNP_COEFF_14;
494 coeff_b = QPNP_COEFF_21;
495 }
496 } else {
497 if (*result < 0) {
498 /* charge */
499 coeff_a = -QPNP_COEFF_15;
500 coeff_b = 0;
501 } else {
502 /* discharge */
503 coeff_a = -QPNP_COEFF_12;
504 coeff_b = -QPNP_COEFF_19;
505 }
506 }
507 break;
508 }
509 break;
510 case QPNP_IADC_REV_ID_8110_1_0:
511 /* pm8110 rev 1.0 */
512 switch (iadc->iadc_comp.id) {
513 case COMP_ID_GF:
514 if (!iadc->iadc_comp.ext_rsense) {
515 /* internal rsense */
516 if (*result < 0) {
517 /* charge */
518 coeff_a = QPNP_COEFF_24;
519 coeff_b = -QPNP_COEFF_22;
520 } else {
521 coeff_a = QPNP_COEFF_24;
522 coeff_b = -QPNP_COEFF_23;
523 }
524 }
525 break;
526 case COMP_ID_SMIC:
527 default:
528 if (!iadc->iadc_comp.ext_rsense) {
529 /* internal rsense */
530 if (*result < 0) {
531 /* charge */
532 coeff_a = QPNP_COEFF_24;
533 coeff_b = -QPNP_COEFF_22;
534 } else {
535 coeff_a = QPNP_COEFF_24;
536 coeff_b = -QPNP_COEFF_23;
537 }
538 }
539 break;
540 }
541 break;
542 default:
543 case QPNP_IADC_REV_ID_8026_2_0:
544 /* pm8026 rev 1.0 */
545 coeff_a = 0;
546 coeff_b = 0;
547 break;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700548 }
549
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700550 temp_var = (coeff_a * die_temp) + coeff_b;
551 temp_var = div64_s64(temp_var, QPNP_COEFF_4);
552 temp_var = 1000000 * (1000000 - temp_var);
553
554 if (!iadc->iadc_comp.ext_rsense) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700555 /* internal rsense */
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700556 *result = div64_s64(*result * 1000000, temp_var);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700557 }
558
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700559 if (iadc->iadc_comp.ext_rsense) {
560 /* external rsense */
561 sys_gain_coeff = (1000000 +
562 div64_s64(sys_gain_coeff, QPNP_COEFF_4));
563 temp_var = div64_s64(temp_var * sys_gain_coeff,
564 1000000000);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700565 *result = div64_s64(*result, temp_var);
566 }
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700567 pr_debug("%lld compensated into %lld\n", old, *result);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700568
569 return 0;
570}
571
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700572int32_t qpnp_iadc_comp_result(struct qpnp_iadc_chip *iadc, int64_t *result)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700573{
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700574 return qpnp_iadc_comp(result, iadc, iadc->die_temp);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700575}
576EXPORT_SYMBOL(qpnp_iadc_comp_result);
577
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700578static int32_t qpnp_iadc_comp_info(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700579{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700580 int rc = 0;
581
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700582 rc = qpnp_iadc_read_reg(iadc, QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700583 if (rc < 0) {
584 pr_err("qpnp adc comp id failed with %d\n", rc);
585 return rc;
586 }
587
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700588 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2,
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700589 &iadc->iadc_comp.revision_dig_major);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700590 if (rc < 0) {
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700591 pr_err("qpnp adc revision2 read failed with %d\n", rc);
592 return rc;
593 }
594
595 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION3,
596 &iadc->iadc_comp.revision_ana_minor);
597 if (rc < 0) {
598 pr_err("qpnp adc revision3 read failed with %d\n", rc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700599 return rc;
600 }
601
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700602 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700603 &iadc->iadc_comp.sys_gain);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700604 if (rc < 0) {
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700605 pr_err("full scale read failed with %d\n", rc);
Siddartha Mohanadoss7bea8442013-06-17 17:50:22 -0700606 return rc;
607 }
608
609 if (iadc->external_rsense)
610 iadc->iadc_comp.ext_rsense = true;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700611
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700612 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 -0700613 iadc->iadc_comp.id,
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700614 iadc->iadc_comp.revision_dig_major,
615 iadc->iadc_comp.revision_ana_minor,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700616 iadc->iadc_comp.sys_gain,
617 iadc->iadc_comp.ext_rsense);
618 return rc;
619}
620
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700621static int32_t qpnp_iadc_configure(struct qpnp_iadc_chip *iadc,
622 enum qpnp_iadc_channels channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800623 uint16_t *raw_code, uint32_t mode_sel)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700624{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700625 u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
626 u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700627 u8 status1 = 0;
628 uint32_t count = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700629 int32_t rc = 0;
630
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700631 qpnp_iadc_ch_sel_reg = channel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700632
633 qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
634 QPNP_IADC_DEC_RATIO_SEL;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800635 if (iadc->iadc_mode_sel)
636 qpnp_iadc_mode_reg |= (QPNP_ADC_TRIM_EN | QPNP_VADC_SYNCH_EN);
637 else
638 qpnp_iadc_mode_reg |= QPNP_ADC_TRIM_EN;
639
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700640 qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
641
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700642 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700643 if (rc) {
644 pr_err("qpnp adc read adc failed with %d\n", rc);
645 return rc;
646 }
647
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700648 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_ADC_CH_SEL_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700649 qpnp_iadc_ch_sel_reg);
650 if (rc) {
651 pr_err("qpnp adc read adc failed with %d\n", rc);
652 return rc;
653 }
654
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700655 rc = qpnp_iadc_write_reg(iadc, QPNP_ADC_DIG_PARAM,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700656 qpnp_iadc_dig_param_reg);
657 if (rc) {
658 pr_err("qpnp adc read adc failed with %d\n", rc);
659 return rc;
660 }
661
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700662 rc = qpnp_iadc_write_reg(iadc, QPNP_HW_SETTLE_DELAY,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700663 iadc->adc->amux_prop->hw_settle_time);
664 if (rc < 0) {
665 pr_err("qpnp adc configure error for hw settling time setup\n");
666 return rc;
667 }
668
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700669 rc = qpnp_iadc_write_reg(iadc, QPNP_FAST_AVG_CTL,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700670 iadc->adc->amux_prop->fast_avg_setup);
671 if (rc < 0) {
672 pr_err("qpnp adc fast averaging configure error\n");
673 return rc;
674 }
675
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700676 if (!iadc->iadc_poll_eoc)
677 INIT_COMPLETION(iadc->adc->adc_rslt_completion);
Siddartha Mohanadoss3f219c42013-04-02 11:01:28 -0700678
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700679 rc = qpnp_iadc_enable(iadc, true);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700680 if (rc)
681 return rc;
682
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700683 rc = qpnp_iadc_write_reg(iadc, QPNP_CONV_REQ, qpnp_iadc_conv_req);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700684 if (rc) {
685 pr_err("qpnp adc read adc failed with %d\n", rc);
686 return rc;
687 }
688
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700689 if (iadc->iadc_poll_eoc) {
690 while (status1 != QPNP_STATUS1_EOC) {
691 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
692 if (rc < 0)
693 return rc;
694 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
695 usleep_range(QPNP_ADC_CONV_TIME_MIN,
696 QPNP_ADC_CONV_TIME_MAX);
697 count++;
698 if (count > QPNP_ADC_ERR_COUNT) {
699 pr_err("retry error exceeded\n");
700 rc = qpnp_iadc_status_debug(iadc);
701 if (rc < 0)
702 pr_err("IADC status debug failed\n");
703 rc = -EINVAL;
Siddartha Mohanadossd3a3c952012-12-10 16:55:19 -0800704 return rc;
705 }
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700706 }
707 } else {
708 rc = wait_for_completion_timeout(
709 &iadc->adc->adc_rslt_completion,
710 QPNP_ADC_COMPLETION_TIMEOUT);
711 if (!rc) {
712 rc = qpnp_iadc_read_reg(iadc, QPNP_STATUS1, &status1);
713 if (rc < 0)
714 return rc;
715 status1 &= QPNP_STATUS1_REQ_STS_EOC_MASK;
716 if (status1 == QPNP_STATUS1_EOC)
717 pr_debug("End of conversion status set\n");
718 else {
719 rc = qpnp_iadc_status_debug(iadc);
720 if (rc < 0) {
721 pr_err("status debug failed %d\n", rc);
722 return rc;
723 }
724 return -EINVAL;
725 }
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700726 }
727 }
728
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700729 rc = qpnp_iadc_read_conversion_result(iadc, raw_code);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700730 if (rc) {
731 pr_err("qpnp adc read adc failed with %d\n", rc);
732 return rc;
733 }
734
735 return 0;
736}
737
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700738#define IADC_CENTER 0xC000
739#define IADC_READING_RESOLUTION_N 542535
740#define IADC_READING_RESOLUTION_D 100000
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700741static int32_t qpnp_convert_raw_offset_voltage(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700742{
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700743 s64 numerator;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700744
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800745 if ((iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw) == 0) {
746 pr_err("raw offset errors! raw_gain:0x%x and raw_offset:0x%x\n",
747 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
748 return -EINVAL;
749 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700750
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700751 numerator = iadc->adc->calib.offset_raw - IADC_CENTER;
752 numerator *= IADC_READING_RESOLUTION_N;
753 iadc->adc->calib.offset_uv = div_s64(numerator,
754 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700755
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700756 numerator = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
757 numerator *= IADC_READING_RESOLUTION_N;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700758
Abhijeet Dharmapurikar29005fa2013-07-15 17:57:27 -0700759 iadc->adc->calib.gain_uv = div_s64(numerator,
760 IADC_READING_RESOLUTION_D);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700761
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700762 pr_debug("gain_uv:%d offset_uv:%d\n",
763 iadc->adc->calib.gain_uv, iadc->adc->calib.offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700764 return 0;
765}
766
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700767#define IADC_IDEAL_RAW_GAIN 3291
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700768int32_t qpnp_iadc_calibrate_for_trim(struct qpnp_iadc_chip *iadc,
769 bool batfet_closed)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700770{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700771 uint8_t rslt_lsb, rslt_msb;
772 int32_t rc = 0;
773 uint16_t raw_data;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800774 uint32_t mode_sel = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700775
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700776 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700777 return -EPROBE_DEFER;
778
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800779 mutex_lock(&iadc->adc->adc_lock);
780
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700781 if (iadc->iadc_poll_eoc) {
782 pr_debug("acquiring iadc eoc wakelock\n");
783 pm_stay_awake(iadc->dev);
784 }
785
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700786 rc = qpnp_iadc_configure(iadc, GAIN_CALIBRATION_17P857MV,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800787 &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700788 if (rc < 0) {
789 pr_err("qpnp adc result read failed with %d\n", rc);
790 goto fail;
791 }
792
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700793 iadc->adc->calib.gain_raw = raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700794
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700795 /*
796 * there is a features in the BMS where if the batfet is opened
797 * the BMS reads from INTERNAL_RSENSE (channel 0) actually go to
798 * OFFSET_CALIBRATION_CSP_CSN (channel 5). Hence if batfet is opened
799 * we have to calibrate based on OFFSET_CALIBRATION_CSP_CSN even for
800 * internal rsense.
801 */
802 if (!batfet_closed || iadc->external_rsense) {
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700803 /* external offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700804 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP_CSN,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800805 &raw_data, mode_sel);
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700806 if (rc < 0) {
807 pr_err("qpnp adc result read failed with %d\n", rc);
808 goto fail;
809 }
810 } else {
811 /* internal offset calculation */
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700812 rc = qpnp_iadc_configure(iadc, OFFSET_CALIBRATION_CSP2_CSN2,
Siddartha Mohanadossce7694c2013-07-08 16:47:28 -0700813 &raw_data, mode_sel);
814 if (rc < 0) {
815 pr_err("qpnp adc result read failed with %d\n", rc);
816 goto fail;
817 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700818 }
819
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700820 iadc->adc->calib.offset_raw = raw_data;
821 if (rc < 0) {
822 pr_err("qpnp adc offset/gain calculation failed\n");
823 goto fail;
824 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700825
Siddartha Mohanadossc6921682013-08-07 08:45:41 -0700826 if (iadc->iadc_comp.revision_dig_major == QPNP_IADC_PM8026_2_REV2
827 && iadc->iadc_comp.revision_ana_minor ==
828 QPNP_IADC_PM8026_2_REV3)
Xiaozhe Shif84c8bb2013-07-30 12:22:03 -0700829 iadc->adc->calib.gain_raw =
830 iadc->adc->calib.offset_raw + IADC_IDEAL_RAW_GAIN;
831
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700832 pr_debug("raw gain:0x%x, raw offset:0x%x\n",
833 iadc->adc->calib.gain_raw, iadc->adc->calib.offset_raw);
834
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700835 rc = qpnp_convert_raw_offset_voltage(iadc);
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800836 if (rc < 0) {
837 pr_err("qpnp raw_voltage conversion failed\n");
838 goto fail;
839 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700840
841 rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
842 QPNP_BIT_SHIFT_8;
843 rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
844
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700845 pr_debug("trim values:lsb:0x%x and msb:0x%x\n", rslt_lsb, rslt_msb);
846
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700847 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700848 QPNP_IADC_SEC_ACCESS_DATA);
849 if (rc < 0) {
850 pr_err("qpnp iadc configure error for sec access\n");
851 goto fail;
852 }
853
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700854 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_MSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700855 rslt_msb);
856 if (rc < 0) {
857 pr_err("qpnp iadc configure error for MSB write\n");
858 goto fail;
859 }
860
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700861 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_SEC_ACCESS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700862 QPNP_IADC_SEC_ACCESS_DATA);
863 if (rc < 0) {
864 pr_err("qpnp iadc configure error for sec access\n");
865 goto fail;
866 }
867
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700868 rc = qpnp_iadc_write_reg(iadc, QPNP_IADC_LSB_OFFSET,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700869 rslt_lsb);
870 if (rc < 0) {
871 pr_err("qpnp iadc configure error for LSB write\n");
872 goto fail;
873 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700874fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -0700875 if (iadc->iadc_poll_eoc) {
876 pr_debug("releasing iadc eoc wakelock\n");
877 pm_relax(iadc->dev);
878 }
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800879 mutex_unlock(&iadc->adc->adc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700880 return rc;
881}
Siddartha Mohanadoss06673922013-03-27 11:14:19 -0700882EXPORT_SYMBOL(qpnp_iadc_calibrate_for_trim);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700883
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700884static void qpnp_iadc_work(struct work_struct *work)
885{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700886 struct qpnp_iadc_chip *iadc = container_of(work,
887 struct qpnp_iadc_chip, iadc_work.work);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700888 int rc = 0;
889
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700890 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700891 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700892 if (rc)
893 pr_debug("periodic IADC calibration failed\n");
894 }
895
896 schedule_delayed_work(&iadc->iadc_work,
897 round_jiffies_relative(msecs_to_jiffies
898 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700899 return;
900}
901
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700902static int32_t qpnp_iadc_version_check(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700903{
904 uint8_t revision;
905 int rc;
906
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700907 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_REVISION2, &revision);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700908 if (rc < 0) {
909 pr_err("qpnp adc result read failed with %d\n", rc);
910 return rc;
911 }
912
913 if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
914 pr_err("IADC Version not supported\n");
915 return -EINVAL;
916 }
917
918 return 0;
919}
920
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700921struct qpnp_iadc_chip *qpnp_get_iadc(struct device *dev, const char *name)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700922{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700923 struct qpnp_iadc_chip *iadc;
924 struct device_node *node = NULL;
925 char prop_name[QPNP_MAX_PROP_NAME_LEN];
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700926
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700927 snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-iadc", name);
928
929 node = of_parse_phandle(dev->of_node, prop_name, 0);
930 if (node == NULL)
931 return ERR_PTR(-ENODEV);
932
933 list_for_each_entry(iadc, &qpnp_iadc_device_list, list)
934 if (iadc->adc->spmi->dev.of_node == node)
935 return iadc;
936 return ERR_PTR(-EPROBE_DEFER);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700937}
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700938EXPORT_SYMBOL(qpnp_get_iadc);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700939
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700940int32_t qpnp_iadc_get_rsense(struct qpnp_iadc_chip *iadc, int32_t *rsense)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700941{
942 uint8_t rslt_rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700943 int32_t rc = 0, sign_bit = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700944
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700945 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -0800946 return -EPROBE_DEFER;
947
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700948 if (iadc->external_rsense) {
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700949 *rsense = iadc->rsense;
Siddartha Mohanadoss58279542013-05-28 16:20:46 -0700950 return rc;
951 }
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -0700952
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700953 rc = qpnp_iadc_read_reg(iadc, QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700954 if (rc < 0) {
955 pr_err("qpnp adc rsense read failed with %d\n", rc);
956 return rc;
957 }
958
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700959 pr_debug("rsense:0%x\n", rslt_rsense);
960
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700961 if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
962 sign_bit = 1;
963
964 rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
965
966 if (sign_bit)
967 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
968 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
969 else
970 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
971 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
972
973 return rc;
974}
Xiaozhe Shi767fdb62013-01-10 15:09:08 -0800975EXPORT_SYMBOL(qpnp_iadc_get_rsense);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700976
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700977static int32_t qpnp_check_pmic_temp(struct qpnp_iadc_chip *iadc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700978{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700979 struct qpnp_vadc_result result_pmic_therm;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700980 int64_t die_temp_offset;
Siddartha Mohanadossd752e472013-02-26 18:30:14 -0800981 int rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700982
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700983 rc = qpnp_vadc_read(iadc->vadc_dev, DIE_TEMP, &result_pmic_therm);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700984 if (rc < 0)
985 return rc;
986
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700987 die_temp_offset = result_pmic_therm.physical -
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700988 iadc->die_temp;
Siddartha Mohanadossd4e9edc2013-04-17 14:42:16 -0700989 if (die_temp_offset < 0)
990 die_temp_offset = -die_temp_offset;
991
992 if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
Abhijeet Dharmapurikar0ef9b5c2013-07-15 18:24:38 -0700993 iadc->die_temp = result_pmic_therm.physical;
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700994 if (!iadc->skip_auto_calibrations) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -0700995 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -0700996 if (rc)
997 pr_err("IADC calibration failed rc = %d\n", rc);
998 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700999 }
1000
Siddartha Mohanadossd752e472013-02-26 18:30:14 -08001001 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001002}
1003
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001004int32_t qpnp_iadc_read(struct qpnp_iadc_chip *iadc,
1005 enum qpnp_iadc_channels channel,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001006 struct qpnp_iadc_result *result)
1007{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001008 int32_t rc, rsense_n_ohms, sign = 0, num, mode_sel = 0;
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001009 int32_t rsense_u_ohms = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001010 int64_t result_current;
1011 uint16_t raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001012
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001013 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001014 return -EPROBE_DEFER;
1015
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001016 if (!iadc->iadc_mode_sel) {
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001017 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001018 if (rc) {
1019 pr_err("Error checking pmic therm temp\n");
1020 return rc;
1021 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001022 }
1023
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001024 mutex_lock(&iadc->adc->adc_lock);
1025
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001026 if (iadc->iadc_poll_eoc) {
1027 pr_debug("acquiring iadc eoc wakelock\n");
1028 pm_stay_awake(iadc->dev);
1029 }
1030
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001031 rc = qpnp_iadc_configure(iadc, channel, &raw_data, mode_sel);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001032 if (rc < 0) {
1033 pr_err("qpnp adc result read failed with %d\n", rc);
1034 goto fail;
1035 }
1036
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001037 rc = qpnp_iadc_get_rsense(iadc, &rsense_n_ohms);
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001038 pr_debug("current raw:0%x and rsense:%d\n",
1039 raw_data, rsense_n_ohms);
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001040 rsense_u_ohms = rsense_n_ohms/1000;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001041 num = raw_data - iadc->adc->calib.offset_raw;
1042 if (num < 0) {
1043 sign = 1;
1044 num = -num;
1045 }
1046
1047 result->result_uv = (num * QPNP_ADC_GAIN_NV)/
1048 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
1049 result_current = result->result_uv;
1050 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001051 /* Intentional fall through. Process the result w/o comp */
Siddartha Mohanadoss22618be2013-04-02 15:02:19 -07001052 do_div(result_current, rsense_u_ohms);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001053
1054 if (sign) {
1055 result->result_uv = -result->result_uv;
1056 result_current = -result_current;
1057 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001058 rc = qpnp_iadc_comp_result(iadc, &result_current);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001059 if (rc < 0)
1060 pr_err("Error during compensating the IADC\n");
1061 rc = 0;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001062
1063 result->result_ua = (int32_t) result_current;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001064fail:
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001065 if (iadc->iadc_poll_eoc) {
1066 pr_debug("releasing iadc eoc wakelock\n");
1067 pm_relax(iadc->dev);
1068 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001069 mutex_unlock(&iadc->adc->adc_lock);
1070
1071 return rc;
1072}
1073EXPORT_SYMBOL(qpnp_iadc_read);
1074
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001075int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_chip *iadc,
1076 struct qpnp_iadc_calib *result)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001077{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001078 int rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001079
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001080 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001081 return -EPROBE_DEFER;
1082
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001083 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001084 if (rc) {
1085 pr_err("Error checking pmic therm temp\n");
1086 return rc;
1087 }
1088
1089 mutex_lock(&iadc->adc->adc_lock);
1090 result->gain_raw = iadc->adc->calib.gain_raw;
1091 result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
1092 result->gain_uv = iadc->adc->calib.gain_uv;
1093 result->offset_raw = iadc->adc->calib.offset_raw;
1094 result->ideal_offset_uv =
1095 QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
1096 result->offset_uv = iadc->adc->calib.offset_uv;
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -07001097 pr_debug("raw gain:0%x, raw offset:0%x\n",
1098 result->gain_raw, result->offset_raw);
1099 pr_debug("gain_uv:%d offset_uv:%d\n",
1100 result->gain_uv, result->offset_uv);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001101 mutex_unlock(&iadc->adc->adc_lock);
1102
1103 return 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001104}
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001105EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001106
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001107int qpnp_iadc_skip_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001108{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001109 iadc->skip_auto_calibrations = true;
1110 return 0;
1111}
1112EXPORT_SYMBOL(qpnp_iadc_skip_calibration);
1113
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001114int qpnp_iadc_resume_calibration(struct qpnp_iadc_chip *iadc)
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001115{
Abhijeet Dharmapurikar84b13dd2013-07-08 18:43:56 -07001116 iadc->skip_auto_calibrations = false;
1117 return 0;
1118}
1119EXPORT_SYMBOL(qpnp_iadc_resume_calibration);
1120
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001121int32_t qpnp_iadc_vadc_sync_read(struct qpnp_iadc_chip *iadc,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001122 enum qpnp_iadc_channels i_channel, struct qpnp_iadc_result *i_result,
1123 enum qpnp_vadc_channels v_channel, struct qpnp_vadc_result *v_result)
1124{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001125 int rc = 0;
1126
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001127 if (qpnp_iadc_is_valid(iadc) < 0)
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001128 return -EPROBE_DEFER;
1129
1130 mutex_lock(&iadc->iadc_vadc_lock);
1131
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001132 if (iadc->iadc_poll_eoc) {
1133 pr_debug("acquiring iadc eoc wakelock\n");
1134 pm_stay_awake(iadc->dev);
1135 }
1136
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001137 rc = qpnp_check_pmic_temp(iadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001138 if (rc) {
1139 pr_err("PMIC die temp check failed\n");
1140 goto fail;
1141 }
1142
1143 iadc->iadc_mode_sel = true;
1144
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001145 rc = qpnp_vadc_iadc_sync_request(iadc->vadc_dev, v_channel);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001146 if (rc) {
1147 pr_err("Configuring VADC failed\n");
1148 goto fail;
1149 }
1150
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001151 rc = qpnp_iadc_read(iadc, i_channel, i_result);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001152 if (rc)
1153 pr_err("Configuring IADC failed\n");
1154 /* Intentional fall through to release VADC */
1155
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001156 rc = qpnp_vadc_iadc_sync_complete_request(iadc->vadc_dev, v_channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001157 v_result);
1158 if (rc)
1159 pr_err("Releasing VADC failed\n");
1160fail:
1161 iadc->iadc_mode_sel = false;
1162
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001163 if (iadc->iadc_poll_eoc) {
1164 pr_debug("releasing iadc eoc wakelock\n");
1165 pm_relax(iadc->dev);
1166 }
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001167 mutex_unlock(&iadc->iadc_vadc_lock);
1168
1169 return rc;
1170}
1171EXPORT_SYMBOL(qpnp_iadc_vadc_sync_read);
1172
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001173static ssize_t qpnp_iadc_show(struct device *dev,
1174 struct device_attribute *devattr, char *buf)
1175{
1176 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001177 struct qpnp_iadc_chip *iadc = dev_get_drvdata(dev);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001178 struct qpnp_iadc_result result;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001179 int rc = -1;
1180
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001181 rc = qpnp_iadc_read(iadc, attr->index, &result);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001182
1183 if (rc)
1184 return 0;
1185
1186 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001187 "Result:%d\n", result.result_ua);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001188}
1189
1190static struct sensor_device_attribute qpnp_adc_attr =
1191 SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
1192
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001193static int32_t qpnp_iadc_init_hwmon(struct qpnp_iadc_chip *iadc,
1194 struct spmi_device *spmi)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001195{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001196 struct device_node *child;
1197 struct device_node *node = spmi->dev.of_node;
1198 int rc = 0, i = 0, channel;
1199
1200 for_each_child_of_node(node, child) {
1201 channel = iadc->adc->adc_channels[i].channel_num;
1202 qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
1203 qpnp_adc_attr.dev_attr.attr.name =
1204 iadc->adc->adc_channels[i].name;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001205 memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
1206 sizeof(qpnp_adc_attr));
Stephen Boyd8a5c4e42012-10-30 11:07:22 -07001207 sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001208 rc = device_create_file(&spmi->dev,
1209 &iadc->sens_attr[i].dev_attr);
1210 if (rc) {
1211 dev_err(&spmi->dev,
1212 "device_create_file failed for dev %s\n",
1213 iadc->adc->adc_channels[i].name);
1214 goto hwmon_err_sens;
1215 }
1216 i++;
1217 }
1218
1219 return 0;
1220hwmon_err_sens:
1221 pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
1222 return rc;
1223}
1224
1225static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
1226{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001227 struct qpnp_iadc_chip *iadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001228 struct qpnp_adc_drv *adc_qpnp;
1229 struct device_node *node = spmi->dev.of_node;
1230 struct device_node *child;
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001231 int rc, count_adc_channel_list = 0, i = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001232
1233 for_each_child_of_node(node, child)
1234 count_adc_channel_list++;
1235
1236 if (!count_adc_channel_list) {
1237 pr_err("No channel listing\n");
1238 return -EINVAL;
1239 }
1240
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001241 iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_chip) +
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001242 (sizeof(struct sensor_device_attribute) *
1243 count_adc_channel_list), GFP_KERNEL);
1244 if (!iadc) {
1245 dev_err(&spmi->dev, "Unable to allocate memory\n");
1246 return -ENOMEM;
1247 }
1248
1249 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1250 GFP_KERNEL);
1251 if (!adc_qpnp) {
1252 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001253 rc = -ENOMEM;
1254 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001255 }
1256
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001257 iadc->dev = &(spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001258 iadc->adc = adc_qpnp;
1259
1260 rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
1261 if (rc) {
1262 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001263 goto fail;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001264 }
1265
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001266 iadc->vadc_dev = qpnp_get_vadc(&spmi->dev, "iadc");
1267 if (IS_ERR(iadc->vadc_dev)) {
1268 rc = PTR_ERR(iadc->vadc_dev);
1269 if (rc != -EPROBE_DEFER)
1270 pr_err("vadc property missing, rc=%d\n", rc);
1271 goto fail;
1272 }
1273
Stephen Boydbeab4502013-04-25 10:18:17 -07001274 mutex_init(&iadc->adc->adc_lock);
1275
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001276 rc = of_property_read_u32(node, "qcom,rsense",
1277 &iadc->rsense);
Siddartha Mohanadosse70010b2013-04-04 14:51:41 -07001278 if (rc)
1279 pr_debug("Defaulting to internal rsense\n");
1280 else {
1281 pr_debug("Use external rsense\n");
1282 iadc->external_rsense = true;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001283 }
1284
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001285 iadc->iadc_poll_eoc = of_property_read_bool(node,
1286 "qcom,iadc-poll-eoc");
1287 if (!iadc->iadc_poll_eoc) {
1288 rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
1289 qpnp_iadc_isr, IRQF_TRIGGER_RISING,
1290 "qpnp_iadc_interrupt", iadc);
1291 if (rc) {
1292 dev_err(&spmi->dev, "failed to request adc irq\n");
1293 return rc;
1294 } else
1295 enable_irq_wake(iadc->adc->adc_irq_eoc);
1296 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001297
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001298 rc = qpnp_iadc_init_hwmon(iadc, spmi);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001299 if (rc) {
1300 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001301 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001302 }
1303 iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
1304
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001305 rc = qpnp_iadc_version_check(iadc);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001306 if (rc) {
1307 dev_err(&spmi->dev, "IADC version not supported\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001308 goto fail;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001309 }
1310
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001311 mutex_init(&iadc->iadc_vadc_lock);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001312 INIT_WORK(&iadc->trigger_completion_work, qpnp_iadc_trigger_completion);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001313 INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001314 rc = qpnp_iadc_comp_info(iadc);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001315 if (rc) {
1316 dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
1317 goto fail;
1318 }
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -07001319
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001320 dev_set_drvdata(&spmi->dev, iadc);
1321 list_add(&iadc->list, &qpnp_iadc_device_list);
1322 rc = qpnp_iadc_calibrate_for_trim(iadc, true);
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001323 if (rc)
1324 dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001325
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001326 if (iadc->iadc_poll_eoc)
1327 device_init_wakeup(iadc->dev, 1);
1328
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001329 schedule_delayed_work(&iadc->iadc_work,
1330 round_jiffies_relative(msecs_to_jiffies
1331 (QPNP_IADC_CALIB_SECONDS)));
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001332 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001333fail:
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001334 for_each_child_of_node(node, child) {
1335 device_remove_file(&spmi->dev,
1336 &iadc->sens_attr[i].dev_attr);
1337 i++;
1338 }
1339 hwmon_device_unregister(iadc->iadc_hwmon);
1340
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001341 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001342}
1343
1344static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
1345{
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001346 struct qpnp_iadc_chip *iadc = dev_get_drvdata(&spmi->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001347 struct device_node *node = spmi->dev.of_node;
1348 struct device_node *child;
1349 int i = 0;
1350
Siddartha Mohanadossa9b91672013-02-22 18:32:27 -08001351 cancel_delayed_work(&iadc->iadc_work);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001352 mutex_destroy(&iadc->iadc_vadc_lock);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001353 for_each_child_of_node(node, child) {
1354 device_remove_file(&spmi->dev,
1355 &iadc->sens_attr[i].dev_attr);
1356 i++;
1357 }
Siddartha Mohanadoss55d0bca2013-06-24 08:29:34 -07001358 hwmon_device_unregister(iadc->iadc_hwmon);
Siddartha Mohanadossf82a6f22013-07-27 20:47:34 -07001359 if (iadc->iadc_poll_eoc)
1360 pm_relax(iadc->dev);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -07001361 dev_set_drvdata(&spmi->dev, NULL);
1362
1363 return 0;
1364}
1365
1366static const struct of_device_id qpnp_iadc_match_table[] = {
1367 { .compatible = "qcom,qpnp-iadc",
1368 },
1369 {}
1370};
1371
1372static struct spmi_driver qpnp_iadc_driver = {
1373 .driver = {
1374 .name = "qcom,qpnp-iadc",
1375 .of_match_table = qpnp_iadc_match_table,
1376 },
1377 .probe = qpnp_iadc_probe,
1378 .remove = qpnp_iadc_remove,
1379};
1380
1381static int __init qpnp_iadc_init(void)
1382{
1383 return spmi_driver_register(&qpnp_iadc_driver);
1384}
1385module_init(qpnp_iadc_init);
1386
1387static void __exit qpnp_iadc_exit(void)
1388{
1389 spmi_driver_unregister(&qpnp_iadc_driver);
1390}
1391module_exit(qpnp_iadc_exit);
1392
1393MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
1394MODULE_LICENSE("GPL v2");