blob: c9620b3b81f7d1a04db4d3c0a04883961e9175b7 [file] [log] [blame]
Siddartha Mohanadoss12109952012-11-20 14:57:51 -08001/* Copyright (c) 2012, 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
86
87#define QPNP_VADC_DATA0 0x60
88#define QPNP_VADC_DATA1 0x61
89#define QPNP_VADC_CONV_TIMEOUT_ERR 2
90#define QPNP_VADC_CONV_TIME_MIN 2000
91#define QPNP_VADC_CONV_TIME_MAX 2100
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -070092#define QPNP_ADC_COMPLETION_TIMEOUT HZ
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070093
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070094struct qpnp_vadc_drv {
95 struct qpnp_adc_drv *adc;
96 struct dentry *dent;
97 struct device *vadc_hwmon;
98 bool vadc_init_calib;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070099 bool vadc_initialized;
100 int max_channels_available;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700101 struct sensor_device_attribute sens_attr[0];
102};
103
104struct qpnp_vadc_drv *qpnp_vadc;
105
106static struct qpnp_vadc_scale_fn vadc_scale_fn[] = {
107 [SCALE_DEFAULT] = {qpnp_adc_scale_default},
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700108 [SCALE_BATT_THERM] = {qpnp_adc_scale_batt_therm},
109 [SCALE_PMIC_THERM] = {qpnp_adc_scale_pmic_therm},
110 [SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700111 [SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
112 [SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700113};
114
115static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
116{
117 struct qpnp_vadc_drv *vadc = qpnp_vadc;
118 int rc;
119
120 rc = spmi_ext_register_readl(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700121 (vadc->adc->offset + reg), data, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700122 if (rc < 0) {
123 pr_err("qpnp adc read reg %d failed with %d\n", reg, rc);
124 return rc;
125 }
126
127 return 0;
128}
129
130static int32_t qpnp_vadc_write_reg(int16_t reg, u8 data)
131{
132 struct qpnp_vadc_drv *vadc = qpnp_vadc;
133 int rc;
134 u8 *buf;
135
136 buf = &data;
137
138 rc = spmi_ext_register_writel(vadc->adc->spmi->ctrl, vadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700139 (vadc->adc->offset + reg), buf, 1);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700140 if (rc < 0) {
141 pr_err("qpnp adc write reg %d failed with %d\n", reg, rc);
142 return rc;
143 }
144
145 return 0;
146}
147
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700148static int32_t qpnp_vadc_enable(bool state)
149{
150 int rc = 0;
151 u8 data = 0;
152
153 data = QPNP_VADC_ADC_EN;
154 if (state) {
155 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
156 data);
157 if (rc < 0) {
158 pr_err("VADC enable failed\n");
159 return rc;
160 }
161 } else {
162 rc = qpnp_vadc_write_reg(QPNP_VADC_EN_CTL1,
163 (~data & QPNP_VADC_ADC_EN));
164 if (rc < 0) {
165 pr_err("VADC disable failed\n");
166 return rc;
167 }
168 }
169
170 return 0;
171}
172
173int32_t qpnp_vadc_configure(
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700174 struct qpnp_adc_amux_properties *chan_prop)
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700175{
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700176 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700177 u8 decimation = 0, conv_sequence = 0, conv_sequence_trig = 0;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700178 u8 mode_ctrl = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700179 int rc = 0;
180
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700181 /* Mode selection */
Siddartha Mohanadoss429b4492012-12-11 13:29:58 -0800182 mode_ctrl |= ((chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT) |
183 (QPNP_VADC_ADC_TRIM_EN | QPNP_VADC_AMUX_TRIM_EN));
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700184 rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
185 if (rc < 0) {
186 pr_err("Mode configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700187 return rc;
188 }
189
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700190
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700191 /* Channel selection */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700192 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
193 chan_prop->amux_channel);
194 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700195 pr_err("Channel configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700196 return rc;
197 }
198
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700199 /* Digital parameter setup */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700200 decimation = chan_prop->decimation <<
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700201 QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
202 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
203 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700204 pr_err("Digital parameter configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700205 return rc;
206 }
207
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700208 /* HW settling time delay */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700209 rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
210 chan_prop->hw_settle_time);
211 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700212 pr_err("HW settling time setup error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700213 return rc;
214 }
215
216 if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
217 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700218 /* Normal measurement mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700219 rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
220 chan_prop->fast_avg_setup);
221 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700222 pr_err("Fast averaging configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700223 return rc;
224 }
225 } else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
226 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700227 /* Conversion sequence mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700228 conv_sequence = ((ADC_SEQ_HOLD_100US <<
229 QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
230 ADC_CONV_SEQ_TIMEOUT_5MS);
231 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
232 conv_sequence);
233 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700234 pr_err("Conversion sequence error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700235 return rc;
236 }
237
238 conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
239 QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
240 chan_prop->trigger_channel);
241 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
242 conv_sequence_trig);
243 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700244 pr_err("Conversion trigger error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700245 return rc;
246 }
247 }
248
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700249 INIT_COMPLETION(vadc->adc->adc_rslt_completion);
250
251 rc = qpnp_vadc_enable(true);
252 if (rc)
253 return rc;
254
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700255 /* Request conversion */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700256 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
257 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700258 pr_err("Request conversion failed\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700259 return rc;
260 }
261
262 return 0;
263}
264EXPORT_SYMBOL(qpnp_vadc_configure);
265
266static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
267{
268 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700269 int rc = 0, status = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700270
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700271 status = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
272 if (status < 0) {
273 pr_err("qpnp adc result read failed for data0\n");
274 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700275 }
276
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700277 status = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
278 if (status < 0) {
279 pr_err("qpnp adc result read failed for data1\n");
280 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700281 }
282
283 *data = (rslt_msb << 8) | rslt_lsb;
284
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700285 status = qpnp_vadc_check_result(data);
286 if (status < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700287 pr_err("VADC data check failed\n");
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700288 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700289 }
290
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700291fail:
292 rc = qpnp_vadc_enable(false);
293 if (rc)
294 return rc;
295
296 return status;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700297}
298
299static int32_t qpnp_vadc_read_status(int mode_sel)
300{
301 u8 status1, status2, status2_conv_seq_state;
302 u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
303 int rc;
304
305 switch (mode_sel) {
306 case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
307 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
308 if (rc) {
309 pr_err("qpnp_vadc read mask interrupt failed\n");
310 return rc;
311 }
312
313 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
314 if (rc) {
315 pr_err("qpnp_vadc read mask interrupt failed\n");
316 return rc;
317 }
318
319 if (!(status2 & ~QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS) &&
320 (status1 & (~QPNP_VADC_STATUS1_REQ_STS |
321 QPNP_VADC_STATUS1_EOC))) {
322 rc = status_err;
323 return rc;
324 }
325
326 status2_conv_seq_state = status2 >>
327 QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT;
328 if (status2_conv_seq_state != ADC_CONV_SEQ_IDLE) {
329 pr_err("qpnp vadc seq error with status %d\n",
330 status2);
331 rc = -EINVAL;
332 return rc;
333 }
334 }
335
336 return 0;
337}
338
339static void qpnp_vadc_work(struct work_struct *work)
340{
341 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700342
343 complete(&vadc->adc->adc_rslt_completion);
344
345 return;
346}
347DECLARE_WORK(trigger_completion_work, qpnp_vadc_work);
348
349static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
350{
351 schedule_work(&trigger_completion_work);
352
353 return IRQ_HANDLED;
354}
355
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700356static int32_t qpnp_vadc_version_check(void)
357{
358 uint8_t revision;
359 int rc;
360
361 rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
362 if (rc < 0) {
363 pr_err("qpnp adc result read failed with %d\n", rc);
364 return rc;
365 }
366
367 if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
368 pr_err("VADC Version not supported\n");
369 return -EINVAL;
370 }
371
372 return 0;
373}
374
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700375static uint32_t qpnp_vadc_calib_device(void)
376{
377 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700378 struct qpnp_adc_amux_properties conv;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700379 int rc, calib_read_1, calib_read_2;
380 u8 status1 = 0;
381
382 conv.amux_channel = REF_125V;
383 conv.decimation = DECIMATION_TYPE2;
384 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
385 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
386 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
387
388 rc = qpnp_vadc_configure(&conv);
389 if (rc) {
390 pr_err("qpnp_vadc configure failed with %d\n", rc);
391 goto calib_fail;
392 }
393
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700394 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700395 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
396 if (rc < 0)
397 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700398 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700399 usleep_range(QPNP_VADC_CONV_TIME_MIN,
400 QPNP_VADC_CONV_TIME_MAX);
401 }
402
403 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
404 if (rc) {
405 pr_err("qpnp adc read adc failed with %d\n", rc);
406 goto calib_fail;
407 }
408
409 conv.amux_channel = REF_625MV;
410 conv.decimation = DECIMATION_TYPE2;
411 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
412 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
413 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
414 rc = qpnp_vadc_configure(&conv);
415 if (rc) {
416 pr_err("qpnp adc configure failed with %d\n", rc);
417 goto calib_fail;
418 }
419
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700420 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700421 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700422 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
423 if (rc < 0)
424 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700425 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700426 usleep_range(QPNP_VADC_CONV_TIME_MIN,
427 QPNP_VADC_CONV_TIME_MAX);
428 }
429
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700430 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700431 if (rc) {
432 pr_err("qpnp adc read adc failed with %d\n", rc);
433 goto calib_fail;
434 }
435
436 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
437 (calib_read_1 - calib_read_2);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700438
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700439 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
440 = QPNP_ADC_625_UV;
441 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
442 calib_read_1;
443 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
444 calib_read_2;
445 /* Ratiometric Calibration */
446 conv.amux_channel = VDD_VADC;
447 conv.decimation = DECIMATION_TYPE2;
448 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
449 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
450 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
451 rc = qpnp_vadc_configure(&conv);
452 if (rc) {
453 pr_err("qpnp adc configure failed with %d\n", rc);
454 goto calib_fail;
455 }
456
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700457 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700458 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700459 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
460 if (rc < 0)
461 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700462 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700463 usleep_range(QPNP_VADC_CONV_TIME_MIN,
464 QPNP_VADC_CONV_TIME_MAX);
465 }
466
467 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
468 if (rc) {
469 pr_err("qpnp adc read adc failed with %d\n", rc);
470 goto calib_fail;
471 }
472
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700473 conv.amux_channel = GND_REF;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700474 conv.decimation = DECIMATION_TYPE2;
475 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
476 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
477 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
478 rc = qpnp_vadc_configure(&conv);
479 if (rc) {
480 pr_err("qpnp adc configure failed with %d\n", rc);
481 goto calib_fail;
482 }
483
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700484 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700485 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700486 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
487 if (rc < 0)
488 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700489 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700490 usleep_range(QPNP_VADC_CONV_TIME_MIN,
491 QPNP_VADC_CONV_TIME_MAX);
492 }
493
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700494 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700495 if (rc) {
496 pr_err("qpnp adc read adc failed with %d\n", rc);
497 goto calib_fail;
498 }
499
500 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
501 (calib_read_1 - calib_read_2);
502 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
503 vadc->adc->adc_prop->adc_vdd_reference;
504 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
505 calib_read_1;
506 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
507 calib_read_2;
508
509calib_fail:
510 return rc;
511}
512
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800513int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
514 enum qpnp_adc_calib_type calib_type)
515{
516
517 struct qpnp_vadc_drv *vadc = qpnp_vadc;
518
519 switch (calib_type) {
520 case CALIB_RATIOMETRIC:
521 param->dy =
522 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
523 param->dx =
524 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
525 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
526 param->adc_gnd =
527 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
528 break;
529 case CALIB_ABSOLUTE:
530 param->dy =
531 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
532 param->dx =
533 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
534 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
535 param->adc_gnd =
536 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
537 break;
538 default:
539 return -EINVAL;
540 }
541
542 return 0;
543}
544EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
545
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700546int32_t qpnp_vadc_is_ready(void)
547{
548 struct qpnp_vadc_drv *vadc = qpnp_vadc;
549
550 if (!vadc || !vadc->vadc_initialized)
551 return -EPROBE_DEFER;
552 else
553 return 0;
554}
555EXPORT_SYMBOL(qpnp_vadc_is_ready);
556
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700557int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
558 enum qpnp_vadc_channels channel,
559 struct qpnp_vadc_result *result)
560{
561 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700562 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
563
564 if (!vadc || !vadc->vadc_initialized)
565 return -EPROBE_DEFER;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700566
567 if (!vadc->vadc_init_calib) {
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700568 rc = qpnp_vadc_version_check();
569 if (rc)
570 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700571 rc = qpnp_vadc_calib_device();
572 if (rc) {
573 pr_err("Calibration failed\n");
574 return rc;
575 } else
576 vadc->vadc_init_calib = true;
577 }
578
579 mutex_lock(&vadc->adc->adc_lock);
580
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700581 vadc->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700582
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800583 while ((vadc->adc->adc_channels[dt_index].channel_num
584 != channel) && (dt_index < vadc->max_channels_available))
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700585 dt_index++;
586
Siddartha Mohanadoss7126ce82012-12-11 14:33:11 -0800587 if (dt_index >= vadc->max_channels_available) {
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700588 pr_err("not a valid VADC channel\n");
589 rc = -EINVAL;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700590 goto fail_unlock;
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700591 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700592
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700593 vadc->adc->amux_prop->decimation =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700594 vadc->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700595 vadc->adc->amux_prop->hw_settle_time =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700596 vadc->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700597 vadc->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700598 vadc->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700599
600 if (trigger_channel < ADC_SEQ_NONE)
601 vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
602 << QPNP_VADC_OP_MODE_SHIFT);
603 else if (trigger_channel == ADC_SEQ_NONE)
604 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
605 << QPNP_VADC_OP_MODE_SHIFT);
606 else {
607 pr_err("Invalid trigger channel:%d\n", trigger_channel);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700608 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700609 }
610
611 vadc->adc->amux_prop->trigger_channel = trigger_channel;
612
613 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
614 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700615 pr_err("qpnp vadc configure failed with %d\n", rc);
616 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700617 }
618
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700619 rc = wait_for_completion_timeout(&vadc->adc->adc_rslt_completion,
620 QPNP_ADC_COMPLETION_TIMEOUT);
621 if (!rc) {
622 u8 status1 = 0;
623 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
624 if (rc < 0)
625 goto fail_unlock;
626 status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
627 if (status1 == QPNP_VADC_STATUS1_EOC)
628 pr_debug("End of conversion status set\n");
629 else {
630 pr_err("EOC interrupt not received\n");
631 rc = -EINVAL;
632 goto fail_unlock;
633 }
634 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700635
636 if (trigger_channel < ADC_SEQ_NONE) {
637 rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
638 if (rc)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700639 pr_debug("Conversion sequence timed out - %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700640 }
641
642 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
643 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700644 pr_err("qpnp vadc read adc code failed with %d\n", rc);
645 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700646 }
647
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700648 amux_prescaling =
649 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700650
651 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
652 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
653 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
654 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
655
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700656 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700657 if (scale_type >= SCALE_NONE) {
658 rc = -EBADF;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700659 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700660 }
661
662 vadc_scale_fn[scale_type].chan(result->adc_code,
663 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
664
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700665fail_unlock:
666 mutex_unlock(&vadc->adc->adc_lock);
667
668 return rc;
669}
670EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
671
672int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
673 struct qpnp_vadc_result *result)
674{
675 return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
676 channel, result);
677}
678EXPORT_SYMBOL_GPL(qpnp_vadc_read);
679
680static ssize_t qpnp_adc_show(struct device *dev,
681 struct device_attribute *devattr, char *buf)
682{
683 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
684 struct qpnp_vadc_result result;
685 int rc = -1;
686
687 rc = qpnp_vadc_read(attr->index, &result);
688
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700689 if (rc) {
690 pr_err("VADC read error with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700691 return 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700692 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700693
694 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
695 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
696}
697
698static struct sensor_device_attribute qpnp_adc_attr =
699 SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
700
701static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
702{
703 struct qpnp_vadc_drv *vadc = qpnp_vadc;
704 struct device_node *child;
705 struct device_node *node = spmi->dev.of_node;
706 int rc = 0, i = 0, channel;
707
708 for_each_child_of_node(node, child) {
709 channel = vadc->adc->adc_channels[i].channel_num;
710 qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
711 qpnp_adc_attr.dev_attr.attr.name =
712 vadc->adc->adc_channels[i].name;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700713 memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
714 sizeof(qpnp_adc_attr));
Stephen Boydd7337962012-10-30 11:10:46 -0700715 sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700716 rc = device_create_file(&spmi->dev,
717 &vadc->sens_attr[i].dev_attr);
718 if (rc) {
719 dev_err(&spmi->dev,
720 "device_create_file failed for dev %s\n",
721 vadc->adc->adc_channels[i].name);
722 goto hwmon_err_sens;
723 }
724 i++;
725 }
726
727 return 0;
728hwmon_err_sens:
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700729 pr_err("Init HWMON failed for qpnp_adc with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700730 return rc;
731}
732
733static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
734{
735 struct qpnp_vadc_drv *vadc;
736 struct qpnp_adc_drv *adc_qpnp;
737 struct device_node *node = spmi->dev.of_node;
738 struct device_node *child;
739 int rc, count_adc_channel_list = 0;
740
741 if (!node)
742 return -EINVAL;
743
744 if (qpnp_vadc) {
745 pr_err("VADC already in use\n");
746 return -EBUSY;
747 }
748
749 for_each_child_of_node(node, child)
750 count_adc_channel_list++;
751
752 if (!count_adc_channel_list) {
753 pr_err("No channel listing\n");
754 return -EINVAL;
755 }
756
757 vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
758 (sizeof(struct sensor_device_attribute) *
759 count_adc_channel_list), GFP_KERNEL);
760 if (!vadc) {
761 dev_err(&spmi->dev, "Unable to allocate memory\n");
762 return -ENOMEM;
763 }
764
765 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
766 GFP_KERNEL);
767 if (!adc_qpnp) {
768 dev_err(&spmi->dev, "Unable to allocate memory\n");
769 return -ENOMEM;
770 }
771
772 vadc->adc = adc_qpnp;
773
774 rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
775 if (rc) {
776 dev_err(&spmi->dev, "failed to read device tree\n");
777 return rc;
778 }
779
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800780 rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700781 qpnp_vadc_isr, IRQF_TRIGGER_RISING,
782 "qpnp_vadc_interrupt", vadc);
783 if (rc) {
784 dev_err(&spmi->dev,
785 "failed to request adc irq with error %d\n", rc);
786 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700787 } else {
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800788 enable_irq_wake(vadc->adc->adc_irq_eoc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700789 }
790
791 qpnp_vadc = vadc;
792 dev_set_drvdata(&spmi->dev, vadc);
793 rc = qpnp_vadc_init_hwmon(spmi);
794 if (rc) {
795 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -0700796 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700797 }
798 vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
799 vadc->vadc_init_calib = false;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700800 vadc->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -0700801 vadc->vadc_initialized = true;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700802
803 return 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700804}
805
806static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
807{
808 struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
809 struct device_node *node = spmi->dev.of_node;
810 struct device_node *child;
811 int i = 0;
812
813 for_each_child_of_node(node, child) {
814 device_remove_file(&spmi->dev,
815 &vadc->sens_attr[i].dev_attr);
816 i++;
817 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700818 vadc->vadc_initialized = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700819 dev_set_drvdata(&spmi->dev, NULL);
820
821 return 0;
822}
823
824static const struct of_device_id qpnp_vadc_match_table[] = {
825 { .compatible = "qcom,qpnp-vadc",
826 },
827 {}
828};
829
830static struct spmi_driver qpnp_vadc_driver = {
831 .driver = {
832 .name = "qcom,qpnp-vadc",
833 .of_match_table = qpnp_vadc_match_table,
834 },
835 .probe = qpnp_vadc_probe,
836 .remove = qpnp_vadc_remove,
837};
838
839static int __init qpnp_vadc_init(void)
840{
841 return spmi_driver_register(&qpnp_vadc_driver);
842}
843module_init(qpnp_vadc_init);
844
845static void __exit qpnp_vadc_exit(void)
846{
847 spmi_driver_unregister(&qpnp_vadc_driver);
848}
849module_exit(qpnp_vadc_exit);
850
851MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
852MODULE_LICENSE("GPL v2");