blob: b3b3b5ec29c298a2cff4df4fd22962f1902a3323 [file] [log] [blame]
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001/* Copyright (c) 2012-2013, 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 Mohanadoss4e64f8c2013-04-08 15:57:32 -070086#define QPNP_INT_TEST_VAL 0xE1
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070087
88#define QPNP_VADC_DATA0 0x60
89#define QPNP_VADC_DATA1 0x61
90#define QPNP_VADC_CONV_TIMEOUT_ERR 2
91#define QPNP_VADC_CONV_TIME_MIN 2000
92#define QPNP_VADC_CONV_TIME_MAX 2100
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -070093#define QPNP_ADC_COMPLETION_TIMEOUT HZ
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -070094#define QPNP_VADC_ERR_COUNT 5
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070095
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070096struct qpnp_vadc_drv {
97 struct qpnp_adc_drv *adc;
98 struct dentry *dent;
99 struct device *vadc_hwmon;
100 bool vadc_init_calib;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700101 bool vadc_initialized;
102 int max_channels_available;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800103 bool vadc_iadc_sync_lock;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700104 u8 id;
105 struct sensor_device_attribute sens_attr[0];
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700106};
107
108struct qpnp_vadc_drv *qpnp_vadc;
109
110static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
111 [SCALE_DEFAULT] = {qpnp_adc_scale_default},
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700112 [SCALE_BATT_THERM] = {qpnp_adc_scale_batt_therm},
113 [SCALE_PMIC_THERM] = {qpnp_adc_scale_pmic_therm},
114 [SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700115 [SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
116 [SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
Siddartha Mohanadossb99cfa92013-05-01 20:19:58 -0700117 [SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700118};
119
120static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
121{
122 struct qpnp_vadc_drv *vadc = qpnp_vadc;
123 int rc;
124
125 rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700126 (vadc->adc->offset + reg), data, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700127 if (rc < 0) {
128 pr_err("qpnp adc read reg %d failed with %d\n", reg, rc);
129 return rc;
130 }
131
132 return 0;
133}
134
135static int32_t qpnp_vadc_write_reg(int16_t reg, u8 data)
136{
137 struct qpnp_vadc_drv *vadc = qpnp_vadc;
138 int rc;
139 u8 *buf;
140
141 buf = &data;
142
143 rc = spmi_ext_register_writel(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700144 (vadc->adc->offset + reg), buf, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700145 if (rc < 0) {
146 pr_err("qpnp adc write reg %d failed with %d\n", reg, rc);
147 return rc;
148 }
149
150 return 0;
151}
152
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700153static int32_t qpnp_vadc_enable(bool state)
154{
155 int rc = 0;
156 u8 data = 0;
157
158 data = QPNP_VADC_ADC_EN;
159 if (state) {
160 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
161 data);
162 if (rc < 0) {
163 pr_err("VADC enable failed\n");
164 return rc;
165 }
166 } else {
167 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
168 (~data & QPNP_VADC_ADC_EN));
169 if (rc < 0) {
170 pr_err("VADC disable failed\n");
171 return rc;
172 }
173 }
174
175 return 0;
176}
177
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800178static int32_t qpnp_vadc_status_debug(void)
179{
180 int rc = 0;
181 u8 mode = 0, status1 = 0, chan = 0, dig = 0, en = 0, status2 = 0;
182
183 rc = qpnp_vadc_read_reg(QPNP_VADC_MODE_CTL, &mode);
184 if (rc < 0) {
185 pr_err("mode ctl register read failed with %d\n", rc);
186 return rc;
187 }
188
189 rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_DIG_PARAM, &dig);
190 if (rc < 0) {
191 pr_err("digital param read failed with %d\n", rc);
192 return rc;
193 }
194
195 rc = qpnp_vadc_read_reg(QPNP_VADC_ADC_CH_SEL_CTL, &chan);
196 if (rc < 0) {
197 pr_err("channel read failed with %d\n", rc);
198 return rc;
199 }
200
201 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
202 if (rc < 0) {
203 pr_err("status1 read failed with %d\n", rc);
204 return rc;
205 }
206
207 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
208 if (rc < 0) {
209 pr_err("status2 read failed with %d\n", rc);
210 return rc;
211 }
212
213 rc = qpnp_vadc_read_reg(QPNP_VADC_EN_CTL1, &en);
214 if (rc < 0) {
215 pr_err("en read failed with %d\n", rc);
216 return rc;
217 }
218
219 pr_err("EOC not set - status1/2:%x/%x, dig:%x, ch:%x, mode:%x, en:%x\n",
220 status1, status2, dig, chan, mode, en);
221
222 rc = qpnp_vadc_enable(false);
223 if (rc < 0) {
224 pr_err("VADC disable failed with %d\n", rc);
225 return rc;
226 }
227
228 return 0;
229}
Siddartha Mohanadoss8dbb5c22012-12-11 14:50:45 -0800230static int32_t qpnp_vadc_configure(
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700231 struct qpnp_adc_amux_properties *chan_prop)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700232{
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700233 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700234 u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700235 u8 mode_ctrl = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700236 int rc = 0;
237
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700238 /* Mode selection */
Siddartha Mohanadoss429b4492012-12-11 13:29:58 -0800239 mode_ctrl |= ((chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT) |
240 (QPNP_VADC_ADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700241 rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
242 if (rc < 0) {
243 pr_err("Mode configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700244 return rc;
245 }
246
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700247
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700248 /* Channel selection */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700249 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
250 chan_prop->amux_channel);
251 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700252 pr_err("Channel configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700253 return rc;
254 }
255
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700256 /* Digital parameter setup */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700257 decimation = chan_prop->decimation <<
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700258 QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
259 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
260 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700261 pr_err("Digital parameter configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700262 return rc;
263 }
264
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700265 /* HW settling time delay */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700266 rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
267 chan_prop->hw_settle_time);
268 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700269 pr_err("HW settling time setup error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700270 return rc;
271 }
272
273 if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
274 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700275 /* Normal measurement mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700276 rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
277 chan_prop->fast_avg_setup);
278 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700279 pr_err("Fast averaging configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700280 return rc;
281 }
282 } else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
283 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700284 /* Conversion sequence mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700285 conv_sequence = ((ADC_SEQ_HOLD_100US <<
286 QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
287 ADC_CONV_SEQ_TIMEOUT_5MS);
288 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
289 conv_sequence);
290 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700291 pr_err("Conversion sequence error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700292 return rc;
293 }
294
295 conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
296 QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
297 chan_prop->trigger_channel);
298 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
299 conv_sequence_trig);
300 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700301 pr_err("Conversion trigger error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700302 return rc;
303 }
304 }
305
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700306 INIT_COMPLETION(vadc->adc->adc_rslt_completion);
307
308 rc = qpnp_vadc_enable(true);
309 if (rc)
310 return rc;
311
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800312 if (!vadc->vadc_iadc_sync_lock) {
313 /* Request conversion */
314 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ,
315 QPNP_VADC_CONV_REQ_SET);
316 if (rc < 0) {
317 pr_err("Request conversion failed\n");
318 return rc;
319 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700320 }
321
322 return 0;
323}
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700324
325static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
326{
327 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700328 int rc = 0, status = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700329
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700330 status = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
331 if (status < 0) {
332 pr_err("qpnp adc result read failed for data0\n");
333 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700334 }
335
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700336 status = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
337 if (status < 0) {
338 pr_err("qpnp adc result read failed for data1\n");
339 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700340 }
341
342 *data = (rslt_msb << 8) | rslt_lsb;
343
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700344 status = qpnp_vadc_check_result(data);
345 if (status < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700346 pr_err("VADC data check failed\n");
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700347 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700348 }
349
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700350fail:
351 rc = qpnp_vadc_enable(false);
352 if (rc)
353 return rc;
354
355 return status;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700356}
357
358static int32_t qpnp_vadc_read_status(int mode_sel)
359{
360 u8 status1, status2, status2_conv_seq_state;
361 u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
362 int rc;
363
364 switch (mode_sel) {
365 case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
366 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
367 if (rc) {
368 pr_err("qpnp_vadc read mask interrupt failed\n");
369 return rc;
370 }
371
372 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
373 if (rc) {
374 pr_err("qpnp_vadc read mask interrupt failed\n");
375 return rc;
376 }
377
378 if (!(status2 & ~QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS) &&
379 (status1 & (~QPNP_VADC_STATUS1_REQ_STS |
380 QPNP_VADC_STATUS1_EOC))) {
381 rc = status_err;
382 return rc;
383 }
384
385 status2_conv_seq_state = status2 >>
386 QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT;
387 if (status2_conv_seq_state != ADC_CONV_SEQ_IDLE) {
388 pr_err("qpnp vadc seq error with status %d\n",
389 status2);
390 rc = -EINVAL;
391 return rc;
392 }
393 }
394
395 return 0;
396}
397
398static void qpnp_vadc_work(struct work_struct *work)
399{
400 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700401
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -0800402 if (!vadc || !vadc->vadc_initialized)
403 return;
404
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700405 complete(&vadc->adc->adc_rslt_completion);
406
407 return;
408}
409DECLARE_WORK(trigger_completion_work, qpnp_vadc_work);
410
411static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
412{
413 schedule_work(&trigger_completion_work);
414
415 return IRQ_HANDLED;
416}
417
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700418static int32_t qpnp_vadc_version_check(void)
419{
420 uint8_t revision;
421 int rc;
422
423 rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
424 if (rc < 0) {
425 pr_err("qpnp adc result read failed with %d\n", rc);
426 return rc;
427 }
428
429 if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
430 pr_err("VADC Version not supported\n");
431 return -EINVAL;
432 }
433
434 return 0;
435}
436
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700437static int32_t qpnp_vbat_sns_comp(int64_t *result, u8 id, int64_t die_temp)
438{
439 int64_t temp_var = 0;
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700440 int64_t old = *result;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700441
442 if (die_temp < 25000)
443 return 0;
444
445 switch (id) {
446 case COMP_ID_TSMC:
447 temp_var = (((die_temp *
448 (-QPNP_VBAT_SNS_COEFF_1_TYPEB))
449 + QPNP_VBAT_SNS_COEFF_2_TYPEB));
450 break;
451 default:
452 case COMP_ID_GF:
453 temp_var = (((die_temp *
454 (-QPNP_VBAT_SNS_COEFF_1_TYPEA))
455 + QPNP_VBAT_SNS_COEFF_2_TYPEA));
456 break;
457 }
458
459 temp_var = div64_s64(temp_var, QPNP_VBAT_SNS_COEFF_3);
460
461 temp_var = 1000000 + temp_var;
462
463 *result = *result * temp_var;
464
465 *result = div64_s64(*result, 1000000);
Xiaozhe Shi62ad5e12013-05-13 12:37:41 -0700466 pr_debug("%lld compensated into %lld\n", old, *result);
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700467
468 return 0;
469}
470
471int32_t qpnp_vbat_sns_comp_result(int64_t *result)
472{
473 struct qpnp_vadc_drv *vadc = qpnp_vadc;
474 struct qpnp_vadc_result die_temp_result;
475 int rc = 0;
476
477 rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
478 DIE_TEMP, &die_temp_result);
479 if (rc < 0) {
480 pr_err("Error reading die_temp\n");
481 return rc;
482 }
483
484 rc = qpnp_vbat_sns_comp(result, vadc->id,
485 die_temp_result.physical);
486 if (rc < 0)
487 pr_err("Error with vbat compensation\n");
488
489 return rc;
490}
491EXPORT_SYMBOL(qpnp_vbat_sns_comp_result);
492
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700493static void qpnp_vadc_625mv_channel_sel(uint32_t *ref_channel_sel)
494{
495 struct qpnp_vadc_drv *vadc = qpnp_vadc;
496 uint32_t dt_index = 0;
497
498 /* Check if the buffered 625mV channel exists */
499 while ((vadc->adc->adc_channels[dt_index].channel_num
500 != SPARE1) && (dt_index < vadc->max_channels_available))
501 dt_index++;
502
503 if (dt_index >= vadc->max_channels_available) {
504 pr_debug("Use default 625mV ref channel\n");
505 *ref_channel_sel = REF_625MV;
506 } else {
507 pr_debug("Use buffered 625mV ref channel\n");
508 *ref_channel_sel = SPARE1;
509 }
510}
511
512static int32_t qpnp_vadc_calib_device(void)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700513{
514 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700515 struct qpnp_adc_amux_properties conv;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700516 int rc, calib_read_1, calib_read_2, count = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700517 u8 status1 = 0;
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700518 uint32_t ref_channel_sel = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700519
520 conv.amux_channel = REF_125V;
521 conv.decimation = DECIMATION_TYPE2;
522 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
523 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
524 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
525
526 rc = qpnp_vadc_configure(&conv);
527 if (rc) {
528 pr_err("qpnp_vadc configure failed with %d\n", rc);
529 goto calib_fail;
530 }
531
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700532 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700533 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
534 if (rc < 0)
535 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700536 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700537 usleep_range(QPNP_VADC_CONV_TIME_MIN,
538 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700539 count++;
540 if (count > QPNP_VADC_ERR_COUNT) {
541 rc = -ENODEV;
542 goto calib_fail;
543 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700544 }
545
546 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
547 if (rc) {
548 pr_err("qpnp adc read adc failed with %d\n", rc);
549 goto calib_fail;
550 }
551
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700552 qpnp_vadc_625mv_channel_sel(&ref_channel_sel);
553 conv.amux_channel = ref_channel_sel;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700554 conv.decimation = DECIMATION_TYPE2;
555 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
556 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
557 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
558 rc = qpnp_vadc_configure(&conv);
559 if (rc) {
560 pr_err("qpnp adc configure failed with %d\n", rc);
561 goto calib_fail;
562 }
563
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700564 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700565 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700566 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700567 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
568 if (rc < 0)
569 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700570 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700571 usleep_range(QPNP_VADC_CONV_TIME_MIN,
572 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700573 count++;
574 if (count > QPNP_VADC_ERR_COUNT) {
575 rc = -ENODEV;
576 goto calib_fail;
577 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700578 }
579
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700580 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700581 if (rc) {
582 pr_err("qpnp adc read adc failed with %d\n", rc);
583 goto calib_fail;
584 }
585
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700586 pr_debug("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
587 calib_read_1, calib_read_2);
588
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700589 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
590 (calib_read_1 - calib_read_2);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700591
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700592 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
593 = QPNP_ADC_625_UV;
594 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
595 calib_read_1;
596 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
597 calib_read_2;
598 /* Ratiometric Calibration */
599 conv.amux_channel = VDD_VADC;
600 conv.decimation = DECIMATION_TYPE2;
601 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
602 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
603 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
604 rc = qpnp_vadc_configure(&conv);
605 if (rc) {
606 pr_err("qpnp adc configure failed with %d\n", rc);
607 goto calib_fail;
608 }
609
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700610 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700611 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700612 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700613 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
614 if (rc < 0)
615 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700616 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700617 usleep_range(QPNP_VADC_CONV_TIME_MIN,
618 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700619 count++;
620 if (count > QPNP_VADC_ERR_COUNT) {
621 rc = -ENODEV;
622 goto calib_fail;
623 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700624 }
625
626 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
627 if (rc) {
628 pr_err("qpnp adc read adc failed with %d\n", rc);
629 goto calib_fail;
630 }
631
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700632 conv.amux_channel = GND_REF;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700633 conv.decimation = DECIMATION_TYPE2;
634 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
635 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
636 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
637 rc = qpnp_vadc_configure(&conv);
638 if (rc) {
639 pr_err("qpnp adc configure failed with %d\n", rc);
640 goto calib_fail;
641 }
642
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700643 status1 = 0;
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700644 count = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700645 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700646 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
647 if (rc < 0)
648 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700649 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700650 usleep_range(QPNP_VADC_CONV_TIME_MIN,
651 QPNP_VADC_CONV_TIME_MAX);
Siddartha Mohanadoss73ae69b2013-04-03 17:34:03 -0700652 count++;
653 if (count > QPNP_VADC_ERR_COUNT) {
654 rc = -ENODEV;
655 goto calib_fail;
656 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700657 }
658
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700659 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700660 if (rc) {
661 pr_err("qpnp adc read adc failed with %d\n", rc);
662 goto calib_fail;
663 }
664
Siddartha Mohanadossb2a42372013-03-26 15:53:41 -0700665 pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n",
666 calib_read_1, calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700667 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
668 (calib_read_1 - calib_read_2);
669 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
670 vadc->adc->adc_prop->adc_vdd_reference;
671 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
672 calib_read_1;
673 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
674 calib_read_2;
675
676calib_fail:
677 return rc;
678}
679
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800680int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
681 enum qpnp_adc_calib_type calib_type)
682{
683
684 struct qpnp_vadc_drv *vadc = qpnp_vadc;
685
686 switch (calib_type) {
687 case CALIB_RATIOMETRIC:
688 param->dy =
689 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
690 param->dx =
691 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
692 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
693 param->adc_gnd =
694 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
695 break;
696 case CALIB_ABSOLUTE:
697 param->dy =
698 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
699 param->dx =
700 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
701 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
702 param->adc_gnd =
703 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
704 break;
705 default:
706 return -EINVAL;
707 }
708
709 return 0;
710}
711EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
712
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700713int32_t qpnp_vadc_is_ready(void)
714{
715 struct qpnp_vadc_drv *vadc = qpnp_vadc;
716
717 if (!vadc || !vadc->vadc_initialized)
718 return -EPROBE_DEFER;
719 else
720 return 0;
721}
722EXPORT_SYMBOL(qpnp_vadc_is_ready);
723
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700724int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
725 enum qpnp_vadc_channels channel,
726 struct qpnp_vadc_result *result)
727{
728 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700729 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700730 uint32_t ref_channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700731
732 if (!vadc || !vadc->vadc_initialized)
733 return -EPROBE_DEFER;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700734
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800735 mutex_lock(&vadc->adc->adc_lock);
736
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700737 if (!vadc->vadc_init_calib) {
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700738 rc = qpnp_vadc_version_check();
739 if (rc)
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800740 goto fail_unlock;
741
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700742 rc = qpnp_vadc_calib_device();
743 if (rc) {
744 pr_err("Calibration failed\n");
Siddartha Mohanadoss64bc4f52012-12-19 20:26:32 -0800745 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700746 } else
747 vadc->vadc_init_calib = true;
748 }
749
Siddartha Mohanadoss9edb61e2013-04-29 13:52:52 -0700750 if (channel == REF_625MV) {
751 qpnp_vadc_625mv_channel_sel(&ref_channel);
752 channel = ref_channel;
753 }
754
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700755 vadc->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700756
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800757 while ((vadc->adc->adc_channels[dt_index].channel_num
758 != channel) && (dt_index < vadc->max_channels_available))
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700759 dt_index++;
760
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800761 if (dt_index >= vadc->max_channels_available) {
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700762 pr_err("not a valid VADC channel\n");
763 rc = -EINVAL;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700764 goto fail_unlock;
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700765 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700766
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700767 vadc->adc->amux_prop->decimation =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700768 vadc->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700769 vadc->adc->amux_prop->hw_settle_time =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700770 vadc->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700771 vadc->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700772 vadc->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700773
774 if (trigger_channel < ADC_SEQ_NONE)
775 vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
776 << QPNP_VADC_OP_MODE_SHIFT);
777 else if (trigger_channel == ADC_SEQ_NONE)
778 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
779 << QPNP_VADC_OP_MODE_SHIFT);
780 else {
781 pr_err("Invalid trigger channel:%d\n", trigger_channel);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700782 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700783 }
784
785 vadc->adc->amux_prop->trigger_channel = trigger_channel;
786
787 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
788 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700789 pr_err("qpnp vadc configure failed with %d\n", rc);
790 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700791 }
792
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700793 rc = wait_for_completion_timeout(&vadc->adc->adc_rslt_completion,
794 QPNP_ADC_COMPLETION_TIMEOUT);
795 if (!rc) {
796 u8 status1 = 0;
797 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
798 if (rc < 0)
799 goto fail_unlock;
800 status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
801 if (status1 == QPNP_VADC_STATUS1_EOC)
802 pr_debug("End of conversion status set\n");
803 else {
Siddartha Mohanadoss9cb2c652012-12-14 19:18:18 -0800804 rc = qpnp_vadc_status_debug();
805 if (rc < 0)
806 pr_err("VADC disable failed\n");
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700807 rc = -EINVAL;
808 goto fail_unlock;
809 }
810 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700811
812 if (trigger_channel < ADC_SEQ_NONE) {
813 rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
814 if (rc)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700815 pr_debug("Conversion sequence timed out - %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700816 }
817
818 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
819 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700820 pr_err("qpnp vadc read adc code failed with %d\n", rc);
821 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700822 }
823
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700824 amux_prescaling =
825 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700826
827 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
828 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
829 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
830 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
831
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700832 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700833 if (scale_type >= SCALE_NONE) {
834 rc = -EBADF;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700835 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700836 }
837
838 vadc_scale_fn[scale_type].chan(result->adc_code,
839 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
840
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700841fail_unlock:
842 mutex_unlock(&vadc->adc->adc_lock);
843
844 return rc;
845}
846EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
847
848int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
849 struct qpnp_vadc_result *result)
850{
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -0700851 struct qpnp_vadc_drv *vadc = qpnp_vadc;
852 enum qpnp_vadc_channels;
853 struct qpnp_vadc_result die_temp_result;
854 int rc = 0;
855
856 if (channel == VBAT_SNS) {
857 rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
858 channel, result);
859 if (rc < 0) {
860 pr_err("Error reading vbatt\n");
861 return rc;
862 }
863
864 rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
865 DIE_TEMP, &die_temp_result);
866 if (rc < 0) {
867 pr_err("Error reading die_temp\n");
868 return rc;
869 }
870
871 rc = qpnp_vbat_sns_comp(&result->physical, vadc->id,
872 die_temp_result.physical);
873 if (rc < 0)
874 pr_err("Error with vbat compensation\n");
875
876 return 0;
877 } else
878 return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700879 channel, result);
880}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700881EXPORT_SYMBOL(qpnp_vadc_read);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700882
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -0800883static void qpnp_vadc_lock(void)
884{
885 struct qpnp_vadc_drv *vadc = qpnp_vadc;
886
887 mutex_lock(&vadc->adc->adc_lock);
888}
889
890static void qpnp_vadc_unlock(void)
891{
892 struct qpnp_vadc_drv *vadc = qpnp_vadc;
893
894 mutex_unlock(&vadc->adc->adc_lock);
895}
896
897int32_t qpnp_vadc_iadc_sync_request(enum qpnp_vadc_channels channel)
898{
899 struct qpnp_vadc_drv *vadc = qpnp_vadc;
900 int rc = 0, dt_index = 0;
901
902 if (!vadc || !vadc->vadc_initialized)
903 return -EPROBE_DEFER;
904
905 qpnp_vadc_lock();
906
907 if (!vadc->vadc_init_calib) {
908 rc = qpnp_vadc_version_check();
909 if (rc)
910 goto fail;
911
912 rc = qpnp_vadc_calib_device();
913 if (rc) {
914 pr_err("Calibration failed\n");
915 goto fail;
916 } else
917 vadc->vadc_init_calib = true;
918 }
919
920 vadc->adc->amux_prop->amux_channel = channel;
921
922 while ((vadc->adc->adc_channels[dt_index].channel_num
923 != channel) && (dt_index < vadc->max_channels_available))
924 dt_index++;
925
926 if (dt_index >= vadc->max_channels_available) {
927 pr_err("not a valid VADC channel\n");
928 rc = -EINVAL;
929 goto fail;
930 }
931
932 vadc->adc->amux_prop->decimation =
933 vadc->adc->adc_channels[dt_index].adc_decimation;
934 vadc->adc->amux_prop->hw_settle_time =
935 vadc->adc->adc_channels[dt_index].hw_settle_time;
936 vadc->adc->amux_prop->fast_avg_setup =
937 vadc->adc->adc_channels[dt_index].fast_avg_setup;
938 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
939 << QPNP_VADC_OP_MODE_SHIFT);
940 vadc->vadc_iadc_sync_lock = true;
941
942 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
943 if (rc) {
944 pr_err("qpnp vadc configure failed with %d\n", rc);
945 goto fail;
946 }
947
948 return rc;
949fail:
950 vadc->vadc_iadc_sync_lock = false;
951 qpnp_vadc_unlock();
952 return rc;
953}
954EXPORT_SYMBOL(qpnp_vadc_iadc_sync_request);
955
956int32_t qpnp_vadc_iadc_sync_complete_request(enum qpnp_vadc_channels channel,
957 struct qpnp_vadc_result *result)
958{
959 struct qpnp_vadc_drv *vadc = qpnp_vadc;
960 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
961
962 vadc->adc->amux_prop->amux_channel = channel;
963
964 while ((vadc->adc->adc_channels[dt_index].channel_num
965 != channel) && (dt_index < vadc->max_channels_available))
966 dt_index++;
967
968 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
969 if (rc) {
970 pr_err("qpnp vadc read adc code failed with %d\n", rc);
971 goto fail;
972 }
973
974 amux_prescaling =
975 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
976
977 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
978 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
979 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
980 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
981
982 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
983 if (scale_type >= SCALE_NONE) {
984 rc = -EBADF;
985 goto fail;
986 }
987
988 vadc_scale_fn[scale_type].chan(result->adc_code,
989 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
990
991fail:
992 vadc->vadc_iadc_sync_lock = false;
993 qpnp_vadc_unlock();
994 return rc;
995}
996EXPORT_SYMBOL(qpnp_vadc_iadc_sync_complete_request);
997
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700998static ssize_t qpnp_adc_show(struct device *dev,
999 struct device_attribute *devattr, char *buf)
1000{
1001 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
1002 struct qpnp_vadc_result result;
1003 int rc = -1;
1004
1005 rc = qpnp_vadc_read(attr->index, &result);
1006
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001007 if (rc) {
1008 pr_err("VADC read error with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001009 return 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001010 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001011
1012 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
1013 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
1014}
1015
1016static struct sensor_device_attribute qpnp_adc_attr =
1017 SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
1018
1019static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
1020{
1021 struct qpnp_vadc_drv *vadc = qpnp_vadc;
1022 struct device_node *child;
1023 struct device_node *node = spmi->dev.of_node;
1024 int rc = 0, i = 0, channel;
1025
1026 for_each_child_of_node(node, child) {
1027 channel = vadc->adc->adc_channels[i].channel_num;
1028 qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
1029 qpnp_adc_attr.dev_attr.attr.name =
1030 vadc->adc->adc_channels[i].name;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001031 memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
1032 sizeof(qpnp_adc_attr));
Stephen Boydd7337962012-10-30 11:10:46 -07001033 sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001034 rc = device_create_file(&spmi->dev,
1035 &vadc->sens_attr[i].dev_attr);
1036 if (rc) {
1037 dev_err(&spmi->dev,
1038 "device_create_file failed for dev %s\n",
1039 vadc->adc->adc_channels[i].name);
1040 goto hwmon_err_sens;
1041 }
1042 i++;
1043 }
1044
1045 return 0;
1046hwmon_err_sens:
Siddartha Mohanadossae1da732012-08-08 16:39:02 -07001047 pr_err("Init HWMON failed for qpnp_adc with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001048 return rc;
1049}
1050
1051static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
1052{
1053 struct qpnp_vadc_drv *vadc;
1054 struct qpnp_adc_drv *adc_qpnp;
1055 struct device_node *node = spmi->dev.of_node;
1056 struct device_node *child;
1057 int rc, count_adc_channel_list = 0;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001058 u8 fab_id = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001059
1060 if (!node)
1061 return -EINVAL;
1062
1063 if (qpnp_vadc) {
1064 pr_err("VADC already in use\n");
1065 return -EBUSY;
1066 }
1067
1068 for_each_child_of_node(node, child)
1069 count_adc_channel_list++;
1070
1071 if (!count_adc_channel_list) {
1072 pr_err("No channel listing\n");
1073 return -EINVAL;
1074 }
1075
1076 vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
1077 (sizeof(struct sensor_device_attribute) *
1078 count_adc_channel_list), GFP_KERNEL);
1079 if (!vadc) {
1080 dev_err(&spmi->dev, "Unable to allocate memory\n");
1081 return -ENOMEM;
1082 }
1083
1084 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1085 GFP_KERNEL);
1086 if (!adc_qpnp) {
1087 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001088 rc = -ENOMEM;
1089 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001090 }
1091
1092 vadc->adc = adc_qpnp;
1093
1094 rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
1095 if (rc) {
1096 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001097 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001098 }
Stephen Boydbeab4502013-04-25 10:18:17 -07001099 mutex_init(&vadc->adc->adc_lock);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001100
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001101 rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001102 qpnp_vadc_isr, IRQF_TRIGGER_RISING,
1103 "qpnp_vadc_interrupt", vadc);
1104 if (rc) {
1105 dev_err(&spmi->dev,
1106 "failed to request adc irq with error %d\n", rc);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001107 goto fail;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001108 } else {
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001109 enable_irq_wake(vadc->adc->adc_irq_eoc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001110 }
1111
1112 qpnp_vadc = vadc;
1113 dev_set_drvdata(&spmi->dev, vadc);
1114 rc = qpnp_vadc_init_hwmon(spmi);
1115 if (rc) {
1116 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001117 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001118 }
1119 vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
1120 vadc->vadc_init_calib = false;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001121 vadc->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss4e64f8c2013-04-08 15:57:32 -07001122 rc = qpnp_vadc_read_reg(QPNP_INT_TEST_VAL, &fab_id);
1123 if (rc < 0) {
1124 pr_err("qpnp adc comp id failed with %d\n", rc);
1125 return rc;
1126 }
1127 vadc->id = fab_id;
1128
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -07001129 vadc->vadc_initialized = true;
Siddartha Mohanadossa32ea2a2013-02-12 09:58:31 -08001130 vadc->vadc_iadc_sync_lock = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001131
1132 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001133fail:
1134 qpnp_vadc = NULL;
1135 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001136}
1137
1138static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
1139{
1140 struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
1141 struct device_node *node = spmi->dev.of_node;
1142 struct device_node *child;
1143 int i = 0;
1144
1145 for_each_child_of_node(node, child) {
1146 device_remove_file(&spmi->dev,
1147 &vadc->sens_attr[i].dev_attr);
1148 i++;
1149 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -07001150 vadc->vadc_initialized = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001151 dev_set_drvdata(&spmi->dev, NULL);
1152
1153 return 0;
1154}
1155
1156static const struct of_device_id qpnp_vadc_match_table[] = {
1157 { .compatible = "qcom,qpnp-vadc",
1158 },
1159 {}
1160};
1161
1162static struct spmi_driver qpnp_vadc_driver = {
1163 .driver = {
1164 .name = "qcom,qpnp-vadc",
1165 .of_match_table = qpnp_vadc_match_table,
1166 },
1167 .probe = qpnp_vadc_probe,
1168 .remove = qpnp_vadc_remove,
1169};
1170
1171static int __init qpnp_vadc_init(void)
1172{
1173 return spmi_driver_register(&qpnp_vadc_driver);
1174}
1175module_init(qpnp_vadc_init);
1176
1177static void __exit qpnp_vadc_exit(void)
1178{
1179 spmi_driver_unregister(&qpnp_vadc_driver);
1180}
1181module_exit(qpnp_vadc_exit);
1182
1183MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
1184MODULE_LICENSE("GPL v2");