blob: b71c9982811ceac0178941938c01588b64bb2158 [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 Mohanadoss5ace1102012-08-20 23:18:10 -0700182 mode_ctrl = chan_prop->mode_sel << QPNP_VADC_OP_MODE_SHIFT;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700183 rc = qpnp_vadc_write_reg(QPNP_VADC_MODE_CTL, mode_ctrl);
184 if (rc < 0) {
185 pr_err("Mode configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700186 return rc;
187 }
188
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700189
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700190 /* Channel selection */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700191 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_CH_SEL_CTL,
192 chan_prop->amux_channel);
193 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700194 pr_err("Channel configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700195 return rc;
196 }
197
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700198 /* Digital parameter setup */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700199 decimation = chan_prop->decimation <<
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700200 QPNP_VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
201 rc = qpnp_vadc_write_reg(QPNP_VADC_ADC_DIG_PARAM, decimation);
202 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700203 pr_err("Digital parameter configure write error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700204 return rc;
205 }
206
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700207 /* HW settling time delay */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700208 rc = qpnp_vadc_write_reg(QPNP_VADC_HW_SETTLE_DELAY,
209 chan_prop->hw_settle_time);
210 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700211 pr_err("HW settling time setup error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700212 return rc;
213 }
214
215 if (chan_prop->mode_sel == (ADC_OP_NORMAL_MODE <<
216 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700217 /* Normal measurement mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700218 rc = qpnp_vadc_write_reg(QPNP_VADC_FAST_AVG_CTL,
219 chan_prop->fast_avg_setup);
220 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700221 pr_err("Fast averaging configure error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700222 return rc;
223 }
224 } else if (chan_prop->mode_sel == (ADC_OP_CONVERSION_SEQUENCER <<
225 QPNP_VADC_OP_MODE_SHIFT)) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700226 /* Conversion sequence mode */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700227 conv_sequence = ((ADC_SEQ_HOLD_100US <<
228 QPNP_VADC_CONV_SEQ_HOLDOFF_SHIFT) |
229 ADC_CONV_SEQ_TIMEOUT_5MS);
230 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_CTL,
231 conv_sequence);
232 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700233 pr_err("Conversion sequence error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700234 return rc;
235 }
236
237 conv_sequence_trig = ((QPNP_VADC_CONV_SEQ_RISING_EDGE <<
238 QPNP_VADC_CONV_SEQ_EDGE_SHIFT) |
239 chan_prop->trigger_channel);
240 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_SEQ_TRIG_CTL,
241 conv_sequence_trig);
242 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700243 pr_err("Conversion trigger error\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700244 return rc;
245 }
246 }
247
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700248 INIT_COMPLETION(vadc->adc->adc_rslt_completion);
249
250 rc = qpnp_vadc_enable(true);
251 if (rc)
252 return rc;
253
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700254 /* Request conversion */
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700255 rc = qpnp_vadc_write_reg(QPNP_VADC_CONV_REQ, QPNP_VADC_CONV_REQ_SET);
256 if (rc < 0) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700257 pr_err("Request conversion failed\n");
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700258 return rc;
259 }
260
261 return 0;
262}
263EXPORT_SYMBOL(qpnp_vadc_configure);
264
265static int32_t qpnp_vadc_read_conversion_result(int32_t *data)
266{
267 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700268 int rc = 0, status = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700269
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700270 status = qpnp_vadc_read_reg(QPNP_VADC_DATA0, &rslt_lsb);
271 if (status < 0) {
272 pr_err("qpnp adc result read failed for data0\n");
273 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700274 }
275
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700276 status = qpnp_vadc_read_reg(QPNP_VADC_DATA1, &rslt_msb);
277 if (status < 0) {
278 pr_err("qpnp adc result read failed for data1\n");
279 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700280 }
281
282 *data = (rslt_msb << 8) | rslt_lsb;
283
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700284 status = qpnp_vadc_check_result(data);
285 if (status < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700286 pr_err("VADC data check failed\n");
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700287 goto fail;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700288 }
289
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700290fail:
291 rc = qpnp_vadc_enable(false);
292 if (rc)
293 return rc;
294
295 return status;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700296}
297
298static int32_t qpnp_vadc_read_status(int mode_sel)
299{
300 u8 status1, status2, status2_conv_seq_state;
301 u8 status_err = QPNP_VADC_CONV_TIMEOUT_ERR;
302 int rc;
303
304 switch (mode_sel) {
305 case (ADC_OP_CONVERSION_SEQUENCER << QPNP_VADC_OP_MODE_SHIFT):
306 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
307 if (rc) {
308 pr_err("qpnp_vadc read mask interrupt failed\n");
309 return rc;
310 }
311
312 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS2, &status2);
313 if (rc) {
314 pr_err("qpnp_vadc read mask interrupt failed\n");
315 return rc;
316 }
317
318 if (!(status2 & ~QPNP_VADC_STATUS2_CONV_SEQ_TIMEOUT_STS) &&
319 (status1 & (~QPNP_VADC_STATUS1_REQ_STS |
320 QPNP_VADC_STATUS1_EOC))) {
321 rc = status_err;
322 return rc;
323 }
324
325 status2_conv_seq_state = status2 >>
326 QPNP_VADC_STATUS2_CONV_SEQ_STATE_SHIFT;
327 if (status2_conv_seq_state != ADC_CONV_SEQ_IDLE) {
328 pr_err("qpnp vadc seq error with status %d\n",
329 status2);
330 rc = -EINVAL;
331 return rc;
332 }
333 }
334
335 return 0;
336}
337
338static void qpnp_vadc_work(struct work_struct *work)
339{
340 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700341
342 complete(&vadc->adc->adc_rslt_completion);
343
344 return;
345}
346DECLARE_WORK(trigger_completion_work, qpnp_vadc_work);
347
348static irqreturn_t qpnp_vadc_isr(int irq, void *dev_id)
349{
350 schedule_work(&trigger_completion_work);
351
352 return IRQ_HANDLED;
353}
354
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700355static int32_t qpnp_vadc_version_check(void)
356{
357 uint8_t revision;
358 int rc;
359
360 rc = qpnp_vadc_read_reg(QPNP_VADC_REVISION2, &revision);
361 if (rc < 0) {
362 pr_err("qpnp adc result read failed with %d\n", rc);
363 return rc;
364 }
365
366 if (revision < QPNP_VADC_SUPPORTED_REVISION2) {
367 pr_err("VADC Version not supported\n");
368 return -EINVAL;
369 }
370
371 return 0;
372}
373
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700374static uint32_t qpnp_vadc_calib_device(void)
375{
376 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700377 struct qpnp_adc_amux_properties conv;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700378 int rc, calib_read_1, calib_read_2;
379 u8 status1 = 0;
380
381 conv.amux_channel = REF_125V;
382 conv.decimation = DECIMATION_TYPE2;
383 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
384 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
385 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
386
387 rc = qpnp_vadc_configure(&conv);
388 if (rc) {
389 pr_err("qpnp_vadc configure failed with %d\n", rc);
390 goto calib_fail;
391 }
392
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700393 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700394 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
395 if (rc < 0)
396 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700397 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700398 usleep_range(QPNP_VADC_CONV_TIME_MIN,
399 QPNP_VADC_CONV_TIME_MAX);
400 }
401
402 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
403 if (rc) {
404 pr_err("qpnp adc read adc failed with %d\n", rc);
405 goto calib_fail;
406 }
407
408 conv.amux_channel = REF_625MV;
409 conv.decimation = DECIMATION_TYPE2;
410 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
411 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
412 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
413 rc = qpnp_vadc_configure(&conv);
414 if (rc) {
415 pr_err("qpnp adc configure failed with %d\n", rc);
416 goto calib_fail;
417 }
418
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700419 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700420 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700421 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
422 if (rc < 0)
423 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700424 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700425 usleep_range(QPNP_VADC_CONV_TIME_MIN,
426 QPNP_VADC_CONV_TIME_MAX);
427 }
428
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700429 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700430 if (rc) {
431 pr_err("qpnp adc read adc failed with %d\n", rc);
432 goto calib_fail;
433 }
434
435 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
436 (calib_read_1 - calib_read_2);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700437
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700438 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
439 = QPNP_ADC_625_UV;
440 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
441 calib_read_1;
442 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
443 calib_read_2;
444 /* Ratiometric Calibration */
445 conv.amux_channel = VDD_VADC;
446 conv.decimation = DECIMATION_TYPE2;
447 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
448 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
449 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
450 rc = qpnp_vadc_configure(&conv);
451 if (rc) {
452 pr_err("qpnp adc configure failed with %d\n", rc);
453 goto calib_fail;
454 }
455
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700456 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700457 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700458 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
459 if (rc < 0)
460 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700461 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700462 usleep_range(QPNP_VADC_CONV_TIME_MIN,
463 QPNP_VADC_CONV_TIME_MAX);
464 }
465
466 rc = qpnp_vadc_read_conversion_result(&calib_read_1);
467 if (rc) {
468 pr_err("qpnp adc read adc failed with %d\n", rc);
469 goto calib_fail;
470 }
471
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700472 conv.amux_channel = GND_REF;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700473 conv.decimation = DECIMATION_TYPE2;
474 conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
475 conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
476 conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
477 rc = qpnp_vadc_configure(&conv);
478 if (rc) {
479 pr_err("qpnp adc configure failed with %d\n", rc);
480 goto calib_fail;
481 }
482
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700483 status1 = 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700484 while (status1 != QPNP_VADC_STATUS1_EOC) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700485 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
486 if (rc < 0)
487 return rc;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700488 status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700489 usleep_range(QPNP_VADC_CONV_TIME_MIN,
490 QPNP_VADC_CONV_TIME_MAX);
491 }
492
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700493 rc = qpnp_vadc_read_conversion_result(&calib_read_2);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700494 if (rc) {
495 pr_err("qpnp adc read adc failed with %d\n", rc);
496 goto calib_fail;
497 }
498
499 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy =
500 (calib_read_1 - calib_read_2);
501 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx =
502 vadc->adc->adc_prop->adc_vdd_reference;
503 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref =
504 calib_read_1;
505 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd =
506 calib_read_2;
507
508calib_fail:
509 return rc;
510}
511
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800512int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
513 enum qpnp_adc_calib_type calib_type)
514{
515
516 struct qpnp_vadc_drv *vadc = qpnp_vadc;
517
518 switch (calib_type) {
519 case CALIB_RATIOMETRIC:
520 param->dy =
521 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
522 param->dx =
523 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
524 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
525 param->adc_gnd =
526 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
527 break;
528 case CALIB_ABSOLUTE:
529 param->dy =
530 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
531 param->dx =
532 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
533 param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
534 param->adc_gnd =
535 vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
536 break;
537 default:
538 return -EINVAL;
539 }
540
541 return 0;
542}
543EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
544
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700545int32_t qpnp_vadc_is_ready(void)
546{
547 struct qpnp_vadc_drv *vadc = qpnp_vadc;
548
549 if (!vadc || !vadc->vadc_initialized)
550 return -EPROBE_DEFER;
551 else
552 return 0;
553}
554EXPORT_SYMBOL(qpnp_vadc_is_ready);
555
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700556int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
557 enum qpnp_vadc_channels channel,
558 struct qpnp_vadc_result *result)
559{
560 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700561 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
562
563 if (!vadc || !vadc->vadc_initialized)
564 return -EPROBE_DEFER;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700565
566 if (!vadc->vadc_init_calib) {
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700567 rc = qpnp_vadc_version_check();
568 if (rc)
569 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700570 rc = qpnp_vadc_calib_device();
571 if (rc) {
572 pr_err("Calibration failed\n");
573 return rc;
574 } else
575 vadc->vadc_init_calib = true;
576 }
577
578 mutex_lock(&vadc->adc->adc_lock);
579
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700580 vadc->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700581
582 while (vadc->adc->adc_channels[dt_index].channel_num
583 != channel || dt_index > vadc->max_channels_available)
584 dt_index++;
585
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700586 if (dt_index > vadc->max_channels_available) {
587 pr_err("not a valid VADC channel\n");
588 rc = -EINVAL;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700589 goto fail_unlock;
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700590 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700591
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700592 vadc->adc->amux_prop->decimation =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700593 vadc->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700594 vadc->adc->amux_prop->hw_settle_time =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700595 vadc->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700596 vadc->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700597 vadc->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700598
599 if (trigger_channel < ADC_SEQ_NONE)
600 vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
601 << QPNP_VADC_OP_MODE_SHIFT);
602 else if (trigger_channel == ADC_SEQ_NONE)
603 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
604 << QPNP_VADC_OP_MODE_SHIFT);
605 else {
606 pr_err("Invalid trigger channel:%d\n", trigger_channel);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700607 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700608 }
609
610 vadc->adc->amux_prop->trigger_channel = trigger_channel;
611
612 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
613 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700614 pr_err("qpnp vadc configure failed with %d\n", rc);
615 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700616 }
617
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700618 rc = wait_for_completion_timeout(&vadc->adc->adc_rslt_completion,
619 QPNP_ADC_COMPLETION_TIMEOUT);
620 if (!rc) {
621 u8 status1 = 0;
622 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
623 if (rc < 0)
624 goto fail_unlock;
625 status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
626 if (status1 == QPNP_VADC_STATUS1_EOC)
627 pr_debug("End of conversion status set\n");
628 else {
629 pr_err("EOC interrupt not received\n");
630 rc = -EINVAL;
631 goto fail_unlock;
632 }
633 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700634
635 if (trigger_channel < ADC_SEQ_NONE) {
636 rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
637 if (rc)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700638 pr_debug("Conversion sequence timed out - %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700639 }
640
641 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
642 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700643 pr_err("qpnp vadc read adc code failed with %d\n", rc);
644 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700645 }
646
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700647 amux_prescaling =
648 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700649
650 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
651 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
652 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
653 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
654
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700655 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700656 if (scale_type >= SCALE_NONE) {
657 rc = -EBADF;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700658 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700659 }
660
661 vadc_scale_fn[scale_type].chan(result->adc_code,
662 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
663
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700664fail_unlock:
665 mutex_unlock(&vadc->adc->adc_lock);
666
667 return rc;
668}
669EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
670
671int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
672 struct qpnp_vadc_result *result)
673{
674 return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
675 channel, result);
676}
677EXPORT_SYMBOL_GPL(qpnp_vadc_read);
678
679static ssize_t qpnp_adc_show(struct device *dev,
680 struct device_attribute *devattr, char *buf)
681{
682 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
683 struct qpnp_vadc_result result;
684 int rc = -1;
685
686 rc = qpnp_vadc_read(attr->index, &result);
687
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700688 if (rc) {
689 pr_err("VADC read error with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700690 return 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700691 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700692
693 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
694 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
695}
696
697static struct sensor_device_attribute qpnp_adc_attr =
698 SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
699
700static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
701{
702 struct qpnp_vadc_drv *vadc = qpnp_vadc;
703 struct device_node *child;
704 struct device_node *node = spmi->dev.of_node;
705 int rc = 0, i = 0, channel;
706
707 for_each_child_of_node(node, child) {
708 channel = vadc->adc->adc_channels[i].channel_num;
709 qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
710 qpnp_adc_attr.dev_attr.attr.name =
711 vadc->adc->adc_channels[i].name;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700712 memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
713 sizeof(qpnp_adc_attr));
Stephen Boydd7337962012-10-30 11:10:46 -0700714 sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700715 rc = device_create_file(&spmi->dev,
716 &vadc->sens_attr[i].dev_attr);
717 if (rc) {
718 dev_err(&spmi->dev,
719 "device_create_file failed for dev %s\n",
720 vadc->adc->adc_channels[i].name);
721 goto hwmon_err_sens;
722 }
723 i++;
724 }
725
726 return 0;
727hwmon_err_sens:
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700728 pr_err("Init HWMON failed for qpnp_adc with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700729 return rc;
730}
731
732static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
733{
734 struct qpnp_vadc_drv *vadc;
735 struct qpnp_adc_drv *adc_qpnp;
736 struct device_node *node = spmi->dev.of_node;
737 struct device_node *child;
738 int rc, count_adc_channel_list = 0;
739
740 if (!node)
741 return -EINVAL;
742
743 if (qpnp_vadc) {
744 pr_err("VADC already in use\n");
745 return -EBUSY;
746 }
747
748 for_each_child_of_node(node, child)
749 count_adc_channel_list++;
750
751 if (!count_adc_channel_list) {
752 pr_err("No channel listing\n");
753 return -EINVAL;
754 }
755
756 vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
757 (sizeof(struct sensor_device_attribute) *
758 count_adc_channel_list), GFP_KERNEL);
759 if (!vadc) {
760 dev_err(&spmi->dev, "Unable to allocate memory\n");
761 return -ENOMEM;
762 }
763
764 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
765 GFP_KERNEL);
766 if (!adc_qpnp) {
767 dev_err(&spmi->dev, "Unable to allocate memory\n");
768 return -ENOMEM;
769 }
770
771 vadc->adc = adc_qpnp;
772
773 rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
774 if (rc) {
775 dev_err(&spmi->dev, "failed to read device tree\n");
776 return rc;
777 }
778
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800779 rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700780 qpnp_vadc_isr, IRQF_TRIGGER_RISING,
781 "qpnp_vadc_interrupt", vadc);
782 if (rc) {
783 dev_err(&spmi->dev,
784 "failed to request adc irq with error %d\n", rc);
785 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700786 } else {
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800787 enable_irq_wake(vadc->adc->adc_irq_eoc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700788 }
789
790 qpnp_vadc = vadc;
791 dev_set_drvdata(&spmi->dev, vadc);
792 rc = qpnp_vadc_init_hwmon(spmi);
793 if (rc) {
794 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -0700795 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700796 }
797 vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
798 vadc->vadc_init_calib = false;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700799 vadc->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -0700800 vadc->vadc_initialized = true;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700801
802 return 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700803}
804
805static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
806{
807 struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
808 struct device_node *node = spmi->dev.of_node;
809 struct device_node *child;
810 int i = 0;
811
812 for_each_child_of_node(node, child) {
813 device_remove_file(&spmi->dev,
814 &vadc->sens_attr[i].dev_attr);
815 i++;
816 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700817 vadc->vadc_initialized = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700818 dev_set_drvdata(&spmi->dev, NULL);
819
820 return 0;
821}
822
823static const struct of_device_id qpnp_vadc_match_table[] = {
824 { .compatible = "qcom,qpnp-vadc",
825 },
826 {}
827};
828
829static struct spmi_driver qpnp_vadc_driver = {
830 .driver = {
831 .name = "qcom,qpnp-vadc",
832 .of_match_table = qpnp_vadc_match_table,
833 },
834 .probe = qpnp_vadc_probe,
835 .remove = qpnp_vadc_remove,
836};
837
838static int __init qpnp_vadc_init(void)
839{
840 return spmi_driver_register(&qpnp_vadc_driver);
841}
842module_init(qpnp_vadc_init);
843
844static void __exit qpnp_vadc_exit(void)
845{
846 spmi_driver_unregister(&qpnp_vadc_driver);
847}
848module_exit(qpnp_vadc_exit);
849
850MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
851MODULE_LICENSE("GPL v2");