blob: 79d57317d121b6fd3346b7188a50253267acf24d [file] [log] [blame]
Siddartha Mohanadoss03d8c6c2014-02-03 17:12:19 -08001/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -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/interrupt.h>
29#include <linux/completion.h>
30#include <linux/hwmon-sysfs.h>
31#include <linux/qpnp/qpnp-adc.h>
32#include <linux/platform_device.h>
33
34/* QPNP VADC register definition */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070035#define QPNP_VADC_REVISION1 0x0
36#define QPNP_VADC_REVISION2 0x1
37#define QPNP_VADC_REVISION3 0x2
38#define QPNP_VADC_REVISION4 0x3
39#define QPNP_VADC_PERPH_TYPE 0x4
40#define QPNP_VADC_PERH_SUBTYPE 0x5
41
42#define QPNP_VADC_SUPPORTED_REVISION2 1
43
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070044#define QPNP_VADC_STATUS1 0x8
45#define QPNP_VADC_STATUS1_OP_MODE 4
46#define QPNP_VADC_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
47#define QPNP_VADC_STATUS1_REQ_STS BIT(1)
48#define QPNP_VADC_STATUS1_EOC BIT(0)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -070049#define QPNP_VADC_STATUS1_REQ_STS_EOC_MASK 0x3
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070050#define QPNP_VADC_STATUS2 0x9
51#define QPNP_VADC_STATUS2_CONV_SEQ_STATE 6
52#define QPNP_VADC_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
53#define QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
54#define QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT 4
55#define QPNP_VADC_CONV_TIMEOUT_ERR 2
56
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070057#define QPNP_VADC_MODE_CTL 0x40
58#define QPNP_VADC_OP_MODE_SHIFT 4
59#define QPNP_VADC_VREF_XO_THM_FORCE BIT(2)
60#define QPNP_VADC_AMUX_TRIM_EN BIT(1)
61#define QPNP_VADC_ADC_TRIM_EN BIT(0)
62#define QPNP_VADC_EN_CTL1 0x46
63#define QPNP_VADC_ADC_EN BIT(7)
64#define QPNP_VADC_ADC_CH_SEL_CTL 0x48
65#define QPNP_VADC_ADC_DIG_PARAM 0x50
66#define QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT 3
67#define QPNP_VADC_HW_SETTLE_DELAY 0x51
68#define QPNP_VADC_CONV_REQ 0x52
69#define QPNP_VADC_CONV_REQ_SET BIT(7)
70#define QPNP_VADC_CONV_SEQ_CTL 0x54
71#define QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT 4
72#define QPNP_VADC_CONV_SEQ_TRIG_CTL 0x55
73#define QPNP_VADC_CONV_SEQ_FALLING_EDGE 0x0
74#define QPNP_VADC_CONV_SEQ_RISING_EDGE 0x1
75#define QPNP_VADC_CONV_SEQ_EDGE_SHIFT 7
76#define QPNP_VADC_FAST_AVG_CTL 0x5a
77
78#define QPNP_VADC_M0_LOW_THR_LSB 0x5c
79#define QPNP_VADC_M0_LOW_THR_MSB 0x5d
80#define QPNP_VADC_M0_HIGH_THR_LSB 0x5e
81#define QPNP_VADC_M0_HIGH_THR_MSB 0x5f
82#define QPNP_VADC_M1_LOW_THR_LSB 0x69
83#define QPNP_VADC_M1_LOW_THR_MSB 0x6a
84#define QPNP_VADC_M1_HIGH_THR_LSB 0x6b
85#define QPNP_VADC_M1_HIGH_THR_MSB 0x6c
Siddartha Mohanadoss22559462013-05-15 15:30:28 -070086#define QPNP_VADC_ACCESS 0xd0
87#define QPNP_VADC_ACCESS_DATA 0xa5
88#define QPNP_VADC_PERH_RESET_CTL3 0xda
89#define QPNP_FOLLOW_OTST2_RB BIT(3)
90#define QPNP_FOLLOW_WARM_RB BIT(2)
91#define QPNP_FOLLOW_SHUTDOWN1_RB BIT(1)
92#define QPNP_FOLLOW_SHUTDOWN2_RB BIT(0)
93
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -070094#define QPNP_INT_TEST_VAL 0xE1
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070095
96#define QPNP_VADC_DATA0 0x60
97#define QPNP_VADC_DATA1 0x61
98#define QPNP_VADC_CONV_TIMEOUT_ERR 2
99#define QPNP_VADC_CONV_TIME_MIN 2000
100#define QPNP_VADC_CONV_TIME_MAX 2100
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700101#define QPNP_ADC_COMPLETION_TIMEOUT HZ
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -0700102#define QPNP_VADC_ERR_COUNT 20
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700103
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700104struct qpnp_vadc_chip {
105 struct device *dev;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700106 struct qpnp_adc_drv *adc;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700107 struct list_head list;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700108 struct dentry *dent;
109 struct device *vadc_hwmon;
110 bool vadc_init_calib;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700111 int max_channels_available;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800112 bool vadc_iadc_sync_lock;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700113 u8 id;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700114 struct work_struct trigger_completion_work;
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -0700115 bool vadc_poll_eoc;
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700116 u8 revision_ana_minor;
117 u8 revision_dig_major;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700118 struct sensor_device_attribute sens_attr[0];
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700119};
120
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700121LIST_HEAD(qpnp_vadc_device_list);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700122
123static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
124 [SCALE_DEFAULT] = {qpnp_adc_scale_default},
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700125 [SCALE_BATT_THERM] = {qpnp_adc_scale_batt_therm},
126 [SCALE_PMIC_THERM] = {qpnp_adc_scale_pmic_therm},
127 [SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700128 [SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
129 [SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
Siddartha Mohanadossb99cfa92013-05-01 20:19:58 -0700130 [SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
Xu Kai81c60522013-07-27 14:26:04 +0800131 [SCALE_QRD_SKUAA_BATT_THERM] = {qpnp_adc_scale_qrd_skuaa_batt_therm},
Wu Fenglin2c6ef8f2013-12-17 11:33:33 +0800132 [SCALE_QRD_SKUG_BATT_THERM] = {qpnp_adc_scale_qrd_skug_batt_therm},
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700133};
134
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700135static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
136 u8 *data)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700137{
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700138 int rc;
139
140 rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700141 (vadc->adc->offset + reg), data, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700142 if (rc < 0) {
143 pr_err("qpnp adc read reg %d failed with %d\n", reg, rc);
144 return rc;
145 }
146
147 return 0;
148}
149
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700150static int32_t qpnp_vadc_write_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
151 u8 data)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700152{
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700153 int rc;
154 u8 *buf;
155
156 buf = &data;
157
158 rc = spmi_ext_register_writel(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700159 (vadc->adc->offset + reg), buf, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700160 if (rc < 0) {
161 pr_err("qpnp adc write reg %d failed with %d\n", reg, rc);
162 return rc;
163 }
164
165 return 0;
166}
167
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700168static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc)
Siddartha Mohanadoss22559462013-05-15 15:30:28 -0700169{
170 int rc = 0;
171 u8 data = 0;
172
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700173 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
Siddartha Mohanadoss22559462013-05-15 15:30:28 -0700174 if (rc < 0) {
175 pr_err("VADC write access failed\n");
176 return rc;
177 }
178
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700179 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_PERH_RESET_CTL3, &data);
Siddartha Mohanadoss22559462013-05-15 15:30:28 -0700180 if (rc < 0) {
181 pr_err("VADC perh reset ctl3 read failed\n");
182 return rc;
183 }
184
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700185 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
Siddartha Mohanadoss22559462013-05-15 15:30:28 -0700186 if (rc < 0) {
187 pr_err("VADC write access failed\n");
188 return rc;
189 }
190
191 data |= QPNP_FOLLOW_WARM_RB;
192
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700193 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_PERH_RESET_CTL3, data);
Siddartha Mohanadoss22559462013-05-15 15:30:28 -0700194 if (rc < 0) {
195 pr_err("VADC perh reset ctl3 write failed\n");
196 return rc;
197 }
198
199 return 0;
200}
201
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700202static int32_t qpnp_vadc_enable(struct qpnp_vadc_chip *vadc, bool state)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700203{
204 int rc = 0;
205 u8 data = 0;
206
207 data = QPNP_VADC_ADC_EN;
208 if (state) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700209 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_EN_CTL1,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700210 data);
211 if (rc < 0) {
212 pr_err("VADC enable failed\n");
213 return rc;
214 }
215 } else {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700216 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_EN_CTL1,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700217 (~data & QPNP_VADC_ADC_EN));
218 if (rc < 0) {
219 pr_err("VADC disable failed\n");
220 return rc;
221 }
222 }
223
224 return 0;
225}
226
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700227static int32_t qpnp_vadc_status_debug(struct qpnp_vadc_chip *vadc)
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800228{
229 int rc = 0;
230 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0, status2 = 0;
231
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700232 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_MODE_CTL, &mode);
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800233 if (rc < 0) {
234 pr_err("mode ctl register read failed with %d\n", rc);
235 return rc;
236 }
237
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700238 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_ADC_DIG_PARAM, &dig);
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800239 if (rc < 0) {
240 pr_err("digital param read failed with %d\n", rc);
241 return rc;
242 }
243
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700244 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_ADC_CH_SEL_CTL, &chan);
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800245 if (rc < 0) {
246 pr_err("channel read failed with %d\n", rc);
247 return rc;
248 }
249
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700250 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800251 if (rc < 0) {
252 pr_err("status1 read failed with %d\n", rc);
253 return rc;
254 }
255
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700256 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS2, &status2);
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800257 if (rc < 0) {
258 pr_err("status2 read failed with %d\n", rc);
259 return rc;
260 }
261
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700262 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_EN_CTL1, &en);
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800263 if (rc < 0) {
264 pr_err("en read failed with %d\n", rc);
265 return rc;
266 }
267
268 pr_err("EOC not set - status1/2:%x/%x, dig:%x, ch:%x, mode:%x, en:%x\n",
269 status1, status2, dig, chan, mode, en);
270
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700271 rc = qpnp_vadc_enable(vadc, false);
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800272 if (rc < 0) {
273 pr_err("VADC disable failed with %d\n", rc);
274 return rc;
275 }
276
277 return 0;
278}
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700279static int32_t qpnp_vadc_configure(struct qpnp_vadc_chip *vadc,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700280 struct qpnp_adc_amux_properties *chan_prop)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700281{
282 u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700283 u8 mode_ctrl = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700284 int rc = 0;
285
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700286 /* Mode selection */
Siddartha Mohanadoss429b4492012-12-11 13:29:58 -0800287 mode_ctrl |= ((chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT) |
288 (QPNP_VADC_ADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700289 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_MODE_CTL, mode_ctrl);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700290 if (rc < 0) {
291 pr_err("Mode configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700292 return rc;
293 }
294
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700295
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700296 /* Channel selection */
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700297 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ADC_CH_SEL_CTL,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700298 chan_prop->amux_channel);
299 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700300 pr_err("Channel configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700301 return rc;
302 }
303
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700304 /* Digital parameter setup */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700305 decimation = chan_prop->decimation <<
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700306 QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700307 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ADC_DIG_PARAM, decimation);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700308 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700309 pr_err("Digital parameter configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700310 return rc;
311 }
312
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700313 /* HW settling time delay */
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700314 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HW_SETTLE_DELAY,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700315 chan_prop->hw_settle_time);
316 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700317 pr_err("HW settling time setup error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700318 return rc;
319 }
320
321 if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
322 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700323 /* Normal measurement mode */
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700324 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_FAST_AVG_CTL,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700325 chan_prop->fast_avg_setup);
326 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700327 pr_err("Fast averaging configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700328 return rc;
329 }
330 } else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
331 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700332 /* Conversion sequence mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700333 conv_sequence = ((ADC_SEQ_HOLD_100US <<
334 QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
335 ADC_CONV_SEQ_TIMEOUT_5MS);
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700336 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_CONV_SEQ_CTL,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700337 conv_sequence);
338 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700339 pr_err("Conversion sequence error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700340 return rc;
341 }
342
343 conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
344 QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
345 chan_prop->trigger_channel);
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700346 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_CONV_SEQ_TRIG_CTL,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700347 conv_sequence_trig);
348 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700349 pr_err("Conversion trigger error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700350 return rc;
351 }
352 }
353
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -0700354 if (!vadc->vadc_poll_eoc)
355 INIT_COMPLETION(vadc->adc->adc_rslt_completion);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700356
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700357 rc = qpnp_vadc_enable(vadc, true);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700358 if (rc)
359 return rc;
360
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800361 if (!vadc->vadc_iadc_sync_lock) {
362 /* Request conversion */
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700363 rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_CONV_REQ,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800364 QPNP_VADC_CONV_REQ_SET);
365 if (rc < 0) {
366 pr_err("Request conversion failed\n");
367 return rc;
368 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700369 }
370
371 return 0;
372}
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700373
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700374static int32_t qpnp_vadc_read_conversion_result(struct qpnp_vadc_chip *vadc,
375 int32_t *data)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700376{
377 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700378 int rc = 0, status = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700379
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700380 status = qpnp_vadc_read_reg(vadc, QPNP_VADC_DATA0, &rslt_lsb);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700381 if (status < 0) {
382 pr_err("qpnp adc result read failed for data0\n");
383 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700384 }
385
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700386 status = qpnp_vadc_read_reg(vadc, QPNP_VADC_DATA1, &rslt_msb);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700387 if (status < 0) {
388 pr_err("qpnp adc result read failed for data1\n");
389 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700390 }
391
392 *data = (rslt_msb << 8) | rslt_lsb;
393
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700394 status = qpnp_vadc_check_result(data);
395 if (status < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700396 pr_err("VADC data check failed\n");
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700397 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700398 }
399
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700400fail:
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700401 rc = qpnp_vadc_enable(vadc, false);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700402 if (rc)
403 return rc;
404
405 return status;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700406}
407
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700408static int32_t qpnp_vadc_read_status(struct qpnp_vadc_chip *vadc, int mode_sel)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700409{
410 u8 status1, status2, status2_conv_seq_state;
411 u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
412 int rc;
413
414 switch (mode_sel) {
415 case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700416 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700417 if (rc) {
418 pr_err("qpnp_vadc read mask interrupt failed\n");
419 return rc;
420 }
421
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700422 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS2, &status2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700423 if (rc) {
424 pr_err("qpnp_vadc read mask interrupt failed\n");
425 return rc;
426 }
427
428 if (!(status2 & ~QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS) &&
429 (status1 & (~QPNP_VADC_STATUS1_REQ_STS |
430 QPNP_VADC_STATUS1_EOC))) {
431 rc = status_err;
432 return rc;
433 }
434
435 status2_conv_seq_state = status2 >>
436 QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT;
437 if (status2_conv_seq_state != ADC_CONV_SEQ_IDLE) {
438 pr_err("qpnp vadc seq error with status %d\n",
439 status2);
440 rc = -EINVAL;
441 return rc;
442 }
443 }
444
445 return 0;
446}
447
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700448static int qpnp_vadc_is_valid(struct qpnp_vadc_chip *vadc)
449{
450 struct qpnp_vadc_chip *vadc_chip = NULL;
451
452 list_for_each_entry(vadc_chip, &qpnp_vadc_device_list, list)
453 if (vadc == vadc_chip)
454 return 0;
455
456 return -EINVAL;
457}
458
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700459static void qpnp_vadc_work(struct work_struct *work)
460{
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700461 struct qpnp_vadc_chip *vadc = container_of(work,
462 struct qpnp_vadc_chip, trigger_completion_work);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700463
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700464 if (qpnp_vadc_is_valid(vadc) < 0)
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800465 return;
466
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700467 complete(&vadc->adc->adc_rslt_completion);
468
469 return;
470}
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700471
472static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
473{
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700474 struct qpnp_vadc_chip *vadc = dev_id;
475
476 schedule_work(&vadc->trigger_completion_work);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700477
478 return IRQ_HANDLED;
479}
480
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700481static int32_t qpnp_vadc_version_check(struct qpnp_vadc_chip *dev)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700482{
483 uint8_t revision;
484 int rc;
485
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700486 rc = qpnp_vadc_read_reg(dev, QPNP_VADC_REVISION2, &revision);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700487 if (rc < 0) {
488 pr_err("qpnp adc result read failed with %d\n", rc);
489 return rc;
490 }
491
492 if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
493 pr_err("VADC Version not supported\n");
494 return -EINVAL;
495 }
496
497 return 0;
498}
499
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700500#define QPNP_VBAT_COEFF_1 3000
501#define QPNP_VBAT_COEFF_2 45810000
502#define QPNP_VBAT_COEFF_3 100000
503#define QPNP_VBAT_COEFF_4 3500
504#define QPNP_VBAT_COEFF_5 80000000
505#define QPNP_VBAT_COEFF_6 4400
506#define QPNP_VBAT_COEFF_7 32200000
507#define QPNP_VBAT_COEFF_8 3880
508#define QPNP_VBAT_COEFF_9 5770
509#define QPNP_VBAT_COEFF_10 3660
510#define QPNP_VBAT_COEFF_11 5320
511#define QPNP_VBAT_COEFF_12 8060000
512#define QPNP_VBAT_COEFF_13 102640000
513#define QPNP_VBAT_COEFF_14 22220000
514#define QPNP_VBAT_COEFF_15 83060000
Xiaozhe Shi80754222013-10-30 14:11:41 -0700515#define QPNP_VBAT_COEFF_16 2810
516#define QPNP_VBAT_COEFF_17 5260
517#define QPNP_VBAT_COEFF_18 8027
518#define QPNP_VBAT_COEFF_19 2347
519#define QPNP_VBAT_COEFF_20 6043
520#define QPNP_VBAT_COEFF_21 1914
521#define QPNP_VBAT_OFFSET_SMIC 9446
522#define QPNP_VBAT_OFFSET_GF 9441
523#define QPNP_OCV_OFFSET_SMIC 4596
524#define QPNP_OCV_OFFSET_GF 5896
Siddartha Mohanadoss03d8c6c2014-02-03 17:12:19 -0800525#define QPNP_VBAT_COEFF_22 6800
526#define QPNP_VBAT_COEFF_23 3500
527#define QPNP_VBAT_COEFF_24 4360
528#define QPNP_VBAT_COEFF_25 8060
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700529
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700530static int32_t qpnp_ocv_comp(int64_t *result,
531 struct qpnp_vadc_chip *vadc, int64_t die_temp)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700532{
533 int64_t temp_var = 0;
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700534 int64_t old = *result;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700535 int version;
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700536
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700537 version = qpnp_adc_get_revid_version(vadc->dev);
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700538 if (version == -EINVAL)
539 return 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700540
Xiaozhe Shi80754222013-10-30 14:11:41 -0700541 if (version == QPNP_REV_ID_8110_2_0) {
542 if (die_temp < -20000)
543 die_temp = -20000;
Siddartha Mohanadoss03d8c6c2014-02-03 17:12:19 -0800544 } else if (version == QPNP_REV_ID_8026_2_2) {
545 if (die_temp > 25000)
546 return 0;
Xiaozhe Shi80754222013-10-30 14:11:41 -0700547 } else {
548 if (die_temp < 25000)
549 return 0;
550 if (die_temp > 60000)
551 die_temp = 60000;
552 }
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700553
554 switch (version) {
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700555 case QPNP_REV_ID_8941_3_1:
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700556 switch (vadc->id) {
557 case COMP_ID_TSMC:
558 temp_var = (((die_temp *
559 (-QPNP_VBAT_COEFF_4))
560 + QPNP_VBAT_COEFF_5));
561 break;
562 default:
563 case COMP_ID_GF:
564 temp_var = (((die_temp *
565 (-QPNP_VBAT_COEFF_1))
566 + QPNP_VBAT_COEFF_2));
567 break;
568 }
569 break;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700570 case QPNP_REV_ID_8026_1_0:
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700571 switch (vadc->id) {
572 case COMP_ID_TSMC:
573 temp_var = (((die_temp *
574 (-QPNP_VBAT_COEFF_10))
575 - QPNP_VBAT_COEFF_14));
576 break;
577 default:
578 case COMP_ID_GF:
579 temp_var = (((die_temp *
580 (-QPNP_VBAT_COEFF_8))
581 + QPNP_VBAT_COEFF_12));
582 break;
583 }
584 break;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700585 case QPNP_REV_ID_8026_2_0:
586 case QPNP_REV_ID_8026_2_1:
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700587 switch (vadc->id) {
588 case COMP_ID_TSMC:
Xiaozhe Shi80754222013-10-30 14:11:41 -0700589 temp_var = ((die_temp - 25000) *
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700590 (-QPNP_VBAT_COEFF_10));
591 break;
592 default:
593 case COMP_ID_GF:
Xiaozhe Shi80754222013-10-30 14:11:41 -0700594 temp_var = ((die_temp - 25000) *
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700595 (-QPNP_VBAT_COEFF_8));
596 break;
597 }
598 break;
Siddartha Mohanadoss03d8c6c2014-02-03 17:12:19 -0800599 case QPNP_REV_ID_8026_2_2:
600 switch (vadc->id) {
601 case COMP_ID_TSMC:
602 *result -= QPNP_VBAT_COEFF_22;
603 temp_var = (die_temp - 25000) *
604 QPNP_VBAT_COEFF_24;
605 break;
606 default:
607 case COMP_ID_GF:
608 *result -= QPNP_VBAT_COEFF_22;
609 temp_var = (die_temp - 25000) *
610 QPNP_VBAT_COEFF_25;
611 break;
612 }
Xiaozhe Shi80754222013-10-30 14:11:41 -0700613 case QPNP_REV_ID_8110_2_0:
614 switch (vadc->id) {
615 case COMP_ID_SMIC:
616 *result -= QPNP_OCV_OFFSET_SMIC;
617 if (die_temp < 25000)
618 temp_var = QPNP_VBAT_COEFF_18;
619 else
620 temp_var = QPNP_VBAT_COEFF_19;
621 temp_var = (die_temp - 25000) * temp_var;
622 break;
623 case COMP_ID_TSMC:
624 pr_debug("No TSMC Comp Info, exiting\n");
625 return 0;
626 default:
627 case COMP_ID_GF:
628 *result -= QPNP_OCV_OFFSET_GF;
629 if (die_temp < 25000)
630 temp_var = QPNP_VBAT_COEFF_20;
631 else
632 temp_var = QPNP_VBAT_COEFF_21;
633 temp_var = (die_temp - 25000) * temp_var;
634 break;
635 }
636 break;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700637 default:
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700638 temp_var = 0;
639 break;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700640 }
641
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700642 temp_var = div64_s64(temp_var, QPNP_VBAT_COEFF_3);
643
644 temp_var = 1000000 + temp_var;
645
646 *result = *result * temp_var;
647
648 *result = div64_s64(*result, 1000000);
649 pr_debug("%lld compensated into %lld\n", old, *result);
650
651 return 0;
652}
653
654static int32_t qpnp_vbat_sns_comp(int64_t *result,
655 struct qpnp_vadc_chip *vadc, int64_t die_temp)
656{
657 int64_t temp_var = 0;
658 int64_t old = *result;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700659 int version;
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700660
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700661 version = qpnp_adc_get_revid_version(vadc->dev);
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700662 if (version == -EINVAL)
663 return 0;
664
Xiaozhe Shi80754222013-10-30 14:11:41 -0700665 if (version == QPNP_REV_ID_8110_2_0) {
666 if (die_temp < -20000)
667 die_temp = -20000;
668 } else {
669 if (die_temp < 25000)
670 return 0;
671 /* min(die_temp_c, 60_degC) */
672 if (die_temp > 60000)
673 die_temp = 60000;
674 }
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700675
676 switch (version) {
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700677 case QPNP_REV_ID_8941_3_1:
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700678 switch (vadc->id) {
679 case COMP_ID_TSMC:
680 temp_var = (die_temp *
681 (-QPNP_VBAT_COEFF_1));
682 break;
683 default:
684 case COMP_ID_GF:
685 temp_var = (((die_temp *
686 (-QPNP_VBAT_COEFF_6))
687 + QPNP_VBAT_COEFF_7));
688 break;
689 }
690 break;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700691 case QPNP_REV_ID_8026_1_0:
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700692 switch (vadc->id) {
693 case COMP_ID_TSMC:
694 temp_var = (((die_temp *
695 (-QPNP_VBAT_COEFF_11))
696 + QPNP_VBAT_COEFF_15));
697 break;
698 default:
699 case COMP_ID_GF:
700 temp_var = (((die_temp *
701 (-QPNP_VBAT_COEFF_9))
702 + QPNP_VBAT_COEFF_13));
703 break;
704 }
705 break;
Siddartha Mohanadoss93761842013-09-11 17:46:54 -0700706 case QPNP_REV_ID_8026_2_0:
707 case QPNP_REV_ID_8026_2_1:
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700708 switch (vadc->id) {
709 case COMP_ID_TSMC:
Xiaozhe Shi80754222013-10-30 14:11:41 -0700710 temp_var = ((die_temp - 25000) *
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700711 (-QPNP_VBAT_COEFF_11));
712 break;
713 default:
714 case COMP_ID_GF:
Xiaozhe Shi80754222013-10-30 14:11:41 -0700715 temp_var = ((die_temp - 25000) *
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700716 (-QPNP_VBAT_COEFF_9));
717 break;
718 }
719 break;
Siddartha Mohanadoss03d8c6c2014-02-03 17:12:19 -0800720 case QPNP_REV_ID_8026_2_2:
721 switch (vadc->id) {
722 case COMP_ID_TSMC:
723 *result -= QPNP_VBAT_COEFF_23;
724 temp_var = 0;
725 break;
726 default:
727 case COMP_ID_GF:
728 *result -= QPNP_VBAT_COEFF_23;
729 temp_var = 0;
730 break;
731 }
Xiaozhe Shi80754222013-10-30 14:11:41 -0700732 case QPNP_REV_ID_8110_2_0:
733 switch (vadc->id) {
734 case COMP_ID_SMIC:
735 *result -= QPNP_VBAT_OFFSET_SMIC;
736 temp_var = ((die_temp - 25000) *
737 (QPNP_VBAT_COEFF_17));
738 break;
739 case COMP_ID_TSMC:
740 pr_debug("No TSMC Comp Info, exiting\n");
741 return 0;
742 default:
743 case COMP_ID_GF:
744 *result -= QPNP_VBAT_OFFSET_GF;
745 temp_var = ((die_temp - 25000) *
746 (QPNP_VBAT_COEFF_16));
747 break;
748 }
749 break;
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -0700750 default:
751 temp_var = 0;
752 break;
753 }
754
755 temp_var = div64_s64(temp_var, QPNP_VBAT_COEFF_3);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700756
757 temp_var = 1000000 + temp_var;
758
759 *result = *result * temp_var;
760
761 *result = div64_s64(*result, 1000000);
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700762 pr_debug("%lld compensated into %lld\n", old, *result);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700763
764 return 0;
765}
766
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700767int32_t qpnp_vbat_sns_comp_result(struct qpnp_vadc_chip *vadc,
Xiaozhe Shi80754222013-10-30 14:11:41 -0700768 int64_t *result, bool is_pon_ocv)
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700769{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700770 struct qpnp_vadc_result die_temp_result;
771 int rc = 0;
772
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700773 rc = qpnp_vadc_is_valid(vadc);
774 if (rc < 0)
775 return rc;
776
777 rc = qpnp_vadc_conv_seq_request(vadc, ADC_SEQ_NONE,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700778 DIE_TEMP, &die_temp_result);
779 if (rc < 0) {
780 pr_err("Error reading die_temp\n");
781 return rc;
782 }
783
Xiaozhe Shi80754222013-10-30 14:11:41 -0700784 if (is_pon_ocv)
785 rc = qpnp_ocv_comp(result, vadc, die_temp_result.physical);
786 else
787 rc = qpnp_vbat_sns_comp(result, vadc,
788 die_temp_result.physical);
789
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700790 if (rc < 0)
791 pr_err("Error with vbat compensation\n");
792
793 return rc;
794}
795EXPORT_SYMBOL(qpnp_vbat_sns_comp_result);
796
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700797static void qpnp_vadc_625mv_channel_sel(struct qpnp_vadc_chip *vadc,
798 uint32_t *ref_channel_sel)
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700799{
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700800 uint32_t dt_index = 0;
801
802 /* Check if the buffered 625mV channel exists */
803 while ((vadc->adc->adc_channels[dt_index].channel_num
804 != SPARE1) && (dt_index < vadc->max_channels_available))
805 dt_index++;
806
807 if (dt_index >= vadc->max_channels_available) {
808 pr_debug("Use default 625mV ref channel\n");
809 *ref_channel_sel = REF_625MV;
810 } else {
811 pr_debug("Use buffered 625mV ref channel\n");
812 *ref_channel_sel = SPARE1;
813 }
814}
815
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700816static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700817{
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700818 struct qpnp_adc_amux_properties conv;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700819 int rc, calib_read_1, calib_read_2, count = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700820 u8 status1 = 0;
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700821 uint32_t ref_channel_sel = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700822
823 conv.amux_channel = REF_125V;
824 conv.decimation = DECIMATION_TYPE2;
825 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
826 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
827 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
828
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700829 rc = qpnp_vadc_configure(vadc, &conv);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700830 if (rc) {
831 pr_err("qpnp_vadc configure failed with %d\n", rc);
832 goto calib_fail;
833 }
834
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700835 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700836 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700837 if (rc < 0)
838 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700839 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700840 usleep_range(QPNP_VADC_CONV_TIME_MIN,
841 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700842 count++;
843 if (count > QPNP_VADC_ERR_COUNT) {
844 rc = -ENODEV;
845 goto calib_fail;
846 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700847 }
848
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700849 rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700850 if (rc) {
851 pr_err("qpnp adc read adc failed with %d\n", rc);
852 goto calib_fail;
853 }
854
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700855 qpnp_vadc_625mv_channel_sel(vadc, &ref_channel_sel);
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700856 conv.amux_channel = ref_channel_sel;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700857 conv.decimation = DECIMATION_TYPE2;
858 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
859 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
860 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700861 rc = qpnp_vadc_configure(vadc, &conv);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700862 if (rc) {
863 pr_err("qpnp adc configure failed with %d\n", rc);
864 goto calib_fail;
865 }
866
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700867 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700868 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700869 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700870 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700871 if (rc < 0)
872 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700873 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700874 usleep_range(QPNP_VADC_CONV_TIME_MIN,
875 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700876 count++;
877 if (count > QPNP_VADC_ERR_COUNT) {
878 rc = -ENODEV;
879 goto calib_fail;
880 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700881 }
882
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700883 rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700884 if (rc) {
885 pr_err("qpnp adc read adc failed with %d\n", rc);
886 goto calib_fail;
887 }
888
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700889 pr_debug("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
Dipen Parmar454c4b12013-11-25 14:40:47 +0530890 calib_read_2, calib_read_1);
891
892 if (calib_read_1 == calib_read_2) {
893 pr_err("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
894 calib_read_2, calib_read_1);
895 rc = -EINVAL;
896 goto calib_fail;
897 }
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700898
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700899 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
900 (calib_read_1 - calib_read_2);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700901
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700902 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
903 = QPNP_ADC_625_UV;
904 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
905 calib_read_1;
906 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
907 calib_read_2;
908 /* Ratiometric Calibration */
909 conv.amux_channel = VDD_VADC;
910 conv.decimation = DECIMATION_TYPE2;
911 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
912 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
913 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700914 rc = qpnp_vadc_configure(vadc, &conv);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700915 if (rc) {
916 pr_err("qpnp adc configure failed with %d\n", rc);
917 goto calib_fail;
918 }
919
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700920 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700921 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700922 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700923 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700924 if (rc < 0)
925 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700926 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700927 usleep_range(QPNP_VADC_CONV_TIME_MIN,
928 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700929 count++;
930 if (count > QPNP_VADC_ERR_COUNT) {
931 rc = -ENODEV;
932 goto calib_fail;
933 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700934 }
935
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700936 rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700937 if (rc) {
938 pr_err("qpnp adc read adc failed with %d\n", rc);
939 goto calib_fail;
940 }
941
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700942 conv.amux_channel = GND_REF;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700943 conv.decimation = DECIMATION_TYPE2;
944 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
945 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
946 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700947 rc = qpnp_vadc_configure(vadc, &conv);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700948 if (rc) {
949 pr_err("qpnp adc configure failed with %d\n", rc);
950 goto calib_fail;
951 }
952
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700953 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700954 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700955 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700956 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700957 if (rc < 0)
958 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700959 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700960 usleep_range(QPNP_VADC_CONV_TIME_MIN,
961 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700962 count++;
963 if (count > QPNP_VADC_ERR_COUNT) {
964 rc = -ENODEV;
965 goto calib_fail;
966 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700967 }
968
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700969 rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700970 if (rc) {
971 pr_err("qpnp adc read adc failed with %d\n", rc);
972 goto calib_fail;
973 }
974
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700975 pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
976 calib_read_1, calib_read_2);
Dipen Parmar454c4b12013-11-25 14:40:47 +0530977
978 if (calib_read_1 == calib_read_2) {
979 pr_err("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
980 calib_read_1, calib_read_2);
981 rc = -EINVAL;
982 goto calib_fail;
983 }
984
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700985 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
986 (calib_read_1 - calib_read_2);
987 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
988 vadc->adc->adc_prop->adc_vdd_reference;
989 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
990 calib_read_1;
991 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
992 calib_read_2;
993
994calib_fail:
995 return rc;
996}
997
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700998int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc,
999 struct qpnp_vadc_linear_graph *param,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -08001000 enum qpnp_adc_calib_type calib_type)
1001{
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001002 int rc = 0;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -08001003
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001004 rc = qpnp_vadc_is_valid(vadc);
1005 if (rc < 0)
1006 return rc;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -08001007
1008 switch (calib_type) {
1009 case CALIB_RATIOMETRIC:
1010 param->dy =
1011 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
1012 param->dx =
1013 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
1014 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
1015 param->adc_gnd =
1016 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
1017 break;
1018 case CALIB_ABSOLUTE:
1019 param->dy =
1020 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
1021 param->dx =
1022 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
1023 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
1024 param->adc_gnd =
1025 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
1026 break;
1027 default:
1028 return -EINVAL;
1029 }
1030
1031 return 0;
1032}
1033EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
1034
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001035struct qpnp_vadc_chip *qpnp_get_vadc(struct device *dev, const char *name)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001036{
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001037 struct qpnp_vadc_chip *vadc;
1038 struct device_node *node = NULL;
1039 char prop_name[QPNP_MAX_PROP_NAME_LEN];
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001040
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001041 snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-vadc", name);
1042
1043 node = of_parse_phandle(dev->of_node, prop_name, 0);
1044 if (node == NULL)
1045 return ERR_PTR(-ENODEV);
1046
1047 list_for_each_entry(vadc, &qpnp_vadc_device_list, list)
1048 if (vadc->adc->spmi->dev.of_node == node)
1049 return vadc;
1050 return ERR_PTR(-EPROBE_DEFER);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001051}
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001052EXPORT_SYMBOL(qpnp_get_vadc);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001053
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001054int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc,
1055 enum qpnp_vadc_trigger trigger_channel,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001056 enum qpnp_vadc_channels channel,
1057 struct qpnp_vadc_result *result)
1058{
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001059 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -07001060 uint32_t ref_channel, count = 0;
1061 u8 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001062
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001063 if (qpnp_vadc_is_valid(vadc))
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001064 return -EPROBE_DEFER;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001065
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -08001066 mutex_lock(&vadc->adc->adc_lock);
1067
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -07001068 if (vadc->vadc_poll_eoc) {
1069 pr_debug("requesting vadc eoc stay awake\n");
1070 pm_stay_awake(vadc->dev);
1071 }
1072
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001073 if (!vadc->vadc_init_calib) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001074 rc = qpnp_vadc_version_check(vadc);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001075 if (rc)
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -08001076 goto fail_unlock;
1077
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001078 rc = qpnp_vadc_calib_device(vadc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001079 if (rc) {
1080 pr_err("Calibration failed\n");
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -08001081 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001082 } else
1083 vadc->vadc_init_calib = true;
1084 }
1085
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -07001086 if (channel == REF_625MV) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001087 qpnp_vadc_625mv_channel_sel(vadc, &ref_channel);
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -07001088 channel = ref_channel;
1089 }
1090
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001091 vadc->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001092
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -08001093 while ((vadc->adc->adc_channels[dt_index].channel_num
1094 != channel) && (dt_index < vadc->max_channels_available))
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001095 dt_index++;
1096
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -08001097 if (dt_index >= vadc->max_channels_available) {
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -07001098 pr_err("not a valid VADC channel\n");
1099 rc = -EINVAL;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001100 goto fail_unlock;
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -07001101 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001102
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001103 vadc->adc->amux_prop->decimation =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001104 vadc->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001105 vadc->adc->amux_prop->hw_settle_time =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001106 vadc->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001107 vadc->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001108 vadc->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001109
1110 if (trigger_channel < ADC_SEQ_NONE)
1111 vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
1112 << QPNP_VADC_OP_MODE_SHIFT);
1113 else if (trigger_channel == ADC_SEQ_NONE)
1114 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
1115 << QPNP_VADC_OP_MODE_SHIFT);
1116 else {
1117 pr_err("Invalid trigger channel:%d\n", trigger_channel);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -07001118 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001119 }
1120
1121 vadc->adc->amux_prop->trigger_channel = trigger_channel;
1122
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001123 rc = qpnp_vadc_configure(vadc, vadc->adc->amux_prop);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001124 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -07001125 pr_err("qpnp vadc configure failed with %d\n", rc);
1126 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001127 }
1128
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -07001129 if (vadc->vadc_poll_eoc) {
1130 while (status1 != QPNP_VADC_STATUS1_EOC) {
1131 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1,
1132 &status1);
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -08001133 if (rc < 0)
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -07001134 goto fail_unlock;
1135 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
1136 usleep_range(QPNP_VADC_CONV_TIME_MIN,
1137 QPNP_VADC_CONV_TIME_MAX);
1138 count++;
1139 if (count > QPNP_VADC_ERR_COUNT) {
1140 pr_err("retry error exceeded\n");
1141 rc = qpnp_vadc_status_debug(vadc);
1142 if (rc < 0)
1143 pr_err("VADC disable failed\n");
1144 rc = -EINVAL;
1145 goto fail_unlock;
1146 }
1147 }
1148 } else {
1149 rc = wait_for_completion_timeout(
1150 &vadc->adc->adc_rslt_completion,
1151 QPNP_ADC_COMPLETION_TIMEOUT);
1152 if (!rc) {
1153 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1,
1154 &status1);
1155 if (rc < 0)
1156 goto fail_unlock;
1157 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
1158 if (status1 == QPNP_VADC_STATUS1_EOC)
1159 pr_debug("End of conversion status set\n");
1160 else {
1161 rc = qpnp_vadc_status_debug(vadc);
1162 if (rc < 0)
1163 pr_err("VADC disable failed\n");
1164 rc = -EINVAL;
1165 goto fail_unlock;
1166 }
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -07001167 }
1168 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001169
1170 if (trigger_channel < ADC_SEQ_NONE) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001171 rc = qpnp_vadc_read_status(vadc,
1172 vadc->adc->amux_prop->mode_sel);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001173 if (rc)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -07001174 pr_debug("Conversion sequence timed out - %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001175 }
1176
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001177 rc = qpnp_vadc_read_conversion_result(vadc, &result->adc_code);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001178 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -07001179 pr_err("qpnp vadc read adc code failed with %d\n", rc);
1180 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001181 }
1182
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001183 amux_prescaling =
1184 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001185
Siddartha Mohanadoss630def02013-06-27 14:53:38 -07001186 if (amux_prescaling >= PATH_SCALING_NONE) {
1187 rc = -EINVAL;
1188 goto fail_unlock;
1189 }
1190
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001191 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
1192 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
1193 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
1194 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
1195
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001196 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001197 if (scale_type >= SCALE_NONE) {
1198 rc = -EBADF;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -07001199 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001200 }
1201
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001202 vadc_scale_fn[scale_type].chan(vadc, result->adc_code,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001203 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
1204
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001205fail_unlock:
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -07001206 if (vadc->vadc_poll_eoc) {
1207 pr_debug("requesting vadc eoc stay awake\n");
1208 pm_relax(vadc->dev);
1209 }
1210
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001211 mutex_unlock(&vadc->adc->adc_lock);
1212
1213 return rc;
1214}
1215EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
1216
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001217int32_t qpnp_vadc_read(struct qpnp_vadc_chip *vadc,
1218 enum qpnp_vadc_channels channel,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001219 struct qpnp_vadc_result *result)
1220{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001221 struct qpnp_vadc_result die_temp_result;
1222 int rc = 0;
1223
1224 if (channel == VBAT_SNS) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001225 rc = qpnp_vadc_conv_seq_request(vadc, ADC_SEQ_NONE,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001226 channel, result);
1227 if (rc < 0) {
1228 pr_err("Error reading vbatt\n");
1229 return rc;
1230 }
1231
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001232 rc = qpnp_vadc_conv_seq_request(vadc, ADC_SEQ_NONE,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001233 DIE_TEMP, &die_temp_result);
1234 if (rc < 0) {
1235 pr_err("Error reading die_temp\n");
1236 return rc;
1237 }
1238
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -07001239 rc = qpnp_vbat_sns_comp(&result->physical, vadc,
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001240 die_temp_result.physical);
1241 if (rc < 0)
1242 pr_err("Error with vbat compensation\n");
1243
1244 return 0;
1245 } else
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001246 return qpnp_vadc_conv_seq_request(vadc, ADC_SEQ_NONE,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001247 channel, result);
1248}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -07001249EXPORT_SYMBOL(qpnp_vadc_read);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001250
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001251static void qpnp_vadc_lock(struct qpnp_vadc_chip *vadc)
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001252{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001253 mutex_lock(&vadc->adc->adc_lock);
1254}
1255
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001256static void qpnp_vadc_unlock(struct qpnp_vadc_chip *vadc)
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001257{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001258 mutex_unlock(&vadc->adc->adc_lock);
1259}
1260
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001261int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *vadc,
1262 enum qpnp_vadc_channels channel)
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001263{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001264 int rc = 0, dt_index = 0;
1265
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001266 if (qpnp_vadc_is_valid(vadc))
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001267 return -EPROBE_DEFER;
1268
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001269 qpnp_vadc_lock(vadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001270
1271 if (!vadc->vadc_init_calib) {
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001272 rc = qpnp_vadc_version_check(vadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001273 if (rc)
1274 goto fail;
1275
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001276 rc = qpnp_vadc_calib_device(vadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001277 if (rc) {
1278 pr_err("Calibration failed\n");
1279 goto fail;
1280 } else
1281 vadc->vadc_init_calib = true;
1282 }
1283
1284 vadc->adc->amux_prop->amux_channel = channel;
1285
1286 while ((vadc->adc->adc_channels[dt_index].channel_num
1287 != channel) && (dt_index < vadc->max_channels_available))
1288 dt_index++;
1289
1290 if (dt_index >= vadc->max_channels_available) {
1291 pr_err("not a valid VADC channel\n");
1292 rc = -EINVAL;
1293 goto fail;
1294 }
1295
1296 vadc->adc->amux_prop->decimation =
1297 vadc->adc->adc_channels[dt_index].adc_decimation;
1298 vadc->adc->amux_prop->hw_settle_time =
1299 vadc->adc->adc_channels[dt_index].hw_settle_time;
1300 vadc->adc->amux_prop->fast_avg_setup =
1301 vadc->adc->adc_channels[dt_index].fast_avg_setup;
1302 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
1303 << QPNP_VADC_OP_MODE_SHIFT);
1304 vadc->vadc_iadc_sync_lock = true;
1305
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001306 rc = qpnp_vadc_configure(vadc, vadc->adc->amux_prop);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001307 if (rc) {
1308 pr_err("qpnp vadc configure failed with %d\n", rc);
1309 goto fail;
1310 }
1311
1312 return rc;
1313fail:
1314 vadc->vadc_iadc_sync_lock = false;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001315 qpnp_vadc_unlock(vadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001316 return rc;
1317}
1318EXPORT_SYMBOL(qpnp_vadc_iadc_sync_request);
1319
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001320int32_t qpnp_vadc_iadc_sync_complete_request(struct qpnp_vadc_chip *vadc,
1321 enum qpnp_vadc_channels channel,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001322 struct qpnp_vadc_result *result)
1323{
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001324 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
1325
1326 vadc->adc->amux_prop->amux_channel = channel;
1327
1328 while ((vadc->adc->adc_channels[dt_index].channel_num
1329 != channel) && (dt_index < vadc->max_channels_available))
1330 dt_index++;
1331
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001332 rc = qpnp_vadc_read_conversion_result(vadc, &result->adc_code);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001333 if (rc) {
1334 pr_err("qpnp vadc read adc code failed with %d\n", rc);
1335 goto fail;
1336 }
1337
1338 amux_prescaling =
1339 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
1340
Siddartha Mohanadoss630def02013-06-27 14:53:38 -07001341 if (amux_prescaling >= PATH_SCALING_NONE) {
1342 rc = -EINVAL;
1343 goto fail;
1344 }
1345
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001346 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
1347 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
1348 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
1349 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
1350
1351 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
1352 if (scale_type >= SCALE_NONE) {
1353 rc = -EBADF;
1354 goto fail;
1355 }
1356
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001357 vadc_scale_fn[scale_type].chan(vadc, result->adc_code,
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001358 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
1359
1360fail:
1361 vadc->vadc_iadc_sync_lock = false;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001362 qpnp_vadc_unlock(vadc);
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001363 return rc;
1364}
1365EXPORT_SYMBOL(qpnp_vadc_iadc_sync_complete_request);
1366
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001367static ssize_t qpnp_adc_show(struct device *dev,
1368 struct device_attribute *devattr, char *buf)
1369{
1370 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001371 struct qpnp_vadc_chip *vadc = dev_get_drvdata(dev);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001372 struct qpnp_vadc_result result;
1373 int rc = -1;
1374
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001375 rc = qpnp_vadc_read(vadc, attr->index, &result);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001376
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001377 if (rc) {
1378 pr_err("VADC read error with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001379 return 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001380 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001381
1382 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
1383 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
1384}
1385
1386static struct sensor_device_attribute qpnp_adc_attr =
1387 SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
1388
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001389static int32_t qpnp_vadc_init_hwmon(struct qpnp_vadc_chip *vadc,
1390 struct spmi_device *spmi)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001391{
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001392 struct device_node *child;
1393 struct device_node *node = spmi->dev.of_node;
1394 int rc = 0, i = 0, channel;
1395
1396 for_each_child_of_node(node, child) {
1397 channel = vadc->adc->adc_channels[i].channel_num;
1398 qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
1399 qpnp_adc_attr.dev_attr.attr.name =
1400 vadc->adc->adc_channels[i].name;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001401 memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
1402 sizeof(qpnp_adc_attr));
Stephen Boydd7337962012-10-30 11:10:46 -07001403 sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001404 rc = device_create_file(&spmi->dev,
1405 &vadc->sens_attr[i].dev_attr);
1406 if (rc) {
1407 dev_err(&spmi->dev,
1408 "device_create_file failed for dev %s\n",
1409 vadc->adc->adc_channels[i].name);
1410 goto hwmon_err_sens;
1411 }
1412 i++;
1413 }
1414
1415 return 0;
1416hwmon_err_sens:
Siddartha Mohanadossae1da732012-08-08 16:39:02 -07001417 pr_err("Init HWMON failed for qpnp_adc with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001418 return rc;
1419}
1420
1421static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
1422{
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001423 struct qpnp_vadc_chip *vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001424 struct qpnp_adc_drv *adc_qpnp;
1425 struct device_node *node = spmi->dev.of_node;
1426 struct device_node *child;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001427 int rc, count_adc_channel_list = 0, i = 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001428 u8 fab_id = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001429
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001430 for_each_child_of_node(node, child)
1431 count_adc_channel_list++;
1432
1433 if (!count_adc_channel_list) {
1434 pr_err("No channel listing\n");
1435 return -EINVAL;
1436 }
1437
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001438 vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_chip) +
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001439 (sizeof(struct sensor_device_attribute) *
1440 count_adc_channel_list), GFP_KERNEL);
1441 if (!vadc) {
1442 dev_err(&spmi->dev, "Unable to allocate memory\n");
1443 return -ENOMEM;
1444 }
1445
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001446 vadc->dev = &(spmi->dev);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001447 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1448 GFP_KERNEL);
1449 if (!adc_qpnp) {
1450 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001451 return -ENOMEM;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001452 }
1453
1454 vadc->adc = adc_qpnp;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001455 rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
1456 if (rc) {
1457 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001458 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001459 }
Stephen Boydbeab4502013-04-25 10:18:17 -07001460 mutex_init(&vadc->adc->adc_lock);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001461
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001462 rc = qpnp_vadc_init_hwmon(vadc, spmi);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001463 if (rc) {
1464 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001465 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001466 }
1467 vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
1468 vadc->vadc_init_calib = false;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001469 vadc->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001470 rc = qpnp_vadc_read_reg(vadc, QPNP_INT_TEST_VAL, &fab_id);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001471 if (rc < 0) {
1472 pr_err("qpnp adc comp id failed with %d\n", rc);
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001473 goto err_setup;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001474 }
1475 vadc->id = fab_id;
1476
Siddartha Mohanadossf3db6142013-08-09 16:54:47 -07001477 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_REVISION2,
1478 &vadc->revision_dig_major);
1479 if (rc < 0) {
1480 pr_err("qpnp adc dig_major rev read failed with %d\n", rc);
1481 goto err_setup;
1482 }
1483
1484 rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_REVISION3,
1485 &vadc->revision_ana_minor);
1486 if (rc < 0) {
1487 pr_err("qpnp adc ana_minor rev read failed with %d\n", rc);
1488 goto err_setup;
1489 }
1490
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001491 rc = qpnp_vadc_warm_rst_configure(vadc);
Siddartha Mohanadoss22559462013-05-15 15:30:28 -07001492 if (rc < 0) {
1493 pr_err("Setting perp reset on warm reset failed %d\n", rc);
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001494 goto err_setup;
Siddartha Mohanadoss22559462013-05-15 15:30:28 -07001495 }
1496
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001497 INIT_WORK(&vadc->trigger_completion_work, qpnp_vadc_work);
Siddartha Mohanadoss73fb1512013-08-08 22:38:13 -07001498
1499 vadc->vadc_poll_eoc = of_property_read_bool(node,
1500 "qcom,vadc-poll-eoc");
1501 if (!vadc->vadc_poll_eoc) {
1502 rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
1503 qpnp_vadc_isr, IRQF_TRIGGER_RISING,
1504 "qpnp_vadc_interrupt", vadc);
1505 if (rc) {
1506 dev_err(&spmi->dev,
1507 "failed to request adc irq with error %d\n", rc);
1508 goto err_setup;
1509 } else {
1510 enable_irq_wake(vadc->adc->adc_irq_eoc);
1511 }
1512 } else
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -07001513 device_init_wakeup(vadc->dev, 1);
1514
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001515 vadc->vadc_iadc_sync_lock = false;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001516 dev_set_drvdata(&spmi->dev, vadc);
1517 list_add(&vadc->list, &qpnp_vadc_device_list);
1518
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001519 return 0;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001520
1521err_setup:
1522 for_each_child_of_node(node, child) {
1523 device_remove_file(&spmi->dev,
1524 &vadc->sens_attr[i].dev_attr);
1525 i++;
1526 }
1527 hwmon_device_unregister(vadc->vadc_hwmon);
1528
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001529 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001530}
1531
1532static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
1533{
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001534 struct qpnp_vadc_chip *vadc = dev_get_drvdata(&spmi->dev);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001535 struct device_node *node = spmi->dev.of_node;
1536 struct device_node *child;
1537 int i = 0;
1538
1539 for_each_child_of_node(node, child) {
1540 device_remove_file(&spmi->dev,
1541 &vadc->sens_attr[i].dev_attr);
1542 i++;
1543 }
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001544 hwmon_device_unregister(vadc->vadc_hwmon);
1545 list_del(&vadc->list);
Siddartha Mohanadoss462088b2013-07-27 19:58:09 -07001546 if (vadc->vadc_poll_eoc)
1547 pm_relax(vadc->dev);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001548 dev_set_drvdata(&spmi->dev, NULL);
1549
1550 return 0;
1551}
1552
1553static const struct of_device_id qpnp_vadc_match_table[] = {
1554 { .compatible = "qcom,qpnp-vadc",
1555 },
1556 {}
1557};
1558
1559static struct spmi_driver qpnp_vadc_driver = {
1560 .driver = {
1561 .name = "qcom,qpnp-vadc",
1562 .of_match_table = qpnp_vadc_match_table,
1563 },
1564 .probe = qpnp_vadc_probe,
1565 .remove = qpnp_vadc_remove,
1566};
1567
1568static int __init qpnp_vadc_init(void)
1569{
1570 return spmi_driver_register(&qpnp_vadc_driver);
1571}
1572module_init(qpnp_vadc_init);
1573
1574static void __exit qpnp_vadc_exit(void)
1575{
1576 spmi_driver_unregister(&qpnp_vadc_driver);
1577}
1578module_exit(qpnp_vadc_exit);
1579
1580MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
1581MODULE_LICENSE("GPL v2");