blob: c59aa5b631e720ad0d156ff47e8bb786dcd7639b [file] [log] [blame]
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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 Mohanadoss5ace1102012-08-20 23:18:10 -0700512int32_t qpnp_vadc_is_ready(void)
513{
514 struct qpnp_vadc_drv *vadc = qpnp_vadc;
515
516 if (!vadc || !vadc->vadc_initialized)
517 return -EPROBE_DEFER;
518 else
519 return 0;
520}
521EXPORT_SYMBOL(qpnp_vadc_is_ready);
522
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700523int32_t qpnp_vadc_conv_seq_request(enum qpnp_vadc_trigger trigger_channel,
524 enum qpnp_vadc_channels channel,
525 struct qpnp_vadc_result *result)
526{
527 struct qpnp_vadc_drv *vadc = qpnp_vadc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700528 int rc = 0, scale_type, amux_prescaling, dt_index = 0;
529
530 if (!vadc || !vadc->vadc_initialized)
531 return -EPROBE_DEFER;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700532
533 if (!vadc->vadc_init_calib) {
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700534 rc = qpnp_vadc_version_check();
535 if (rc)
536 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700537 rc = qpnp_vadc_calib_device();
538 if (rc) {
539 pr_err("Calibration failed\n");
540 return rc;
541 } else
542 vadc->vadc_init_calib = true;
543 }
544
545 mutex_lock(&vadc->adc->adc_lock);
546
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700547 vadc->adc->amux_prop->amux_channel = channel;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700548
549 while (vadc->adc->adc_channels[dt_index].channel_num
550 != channel || dt_index > vadc->max_channels_available)
551 dt_index++;
552
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700553 if (dt_index > vadc->max_channels_available) {
554 pr_err("not a valid VADC channel\n");
555 rc = -EINVAL;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700556 goto fail_unlock;
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700557 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700558
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700559 vadc->adc->amux_prop->decimation =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700560 vadc->adc->adc_channels[dt_index].adc_decimation;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700561 vadc->adc->amux_prop->hw_settle_time =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700562 vadc->adc->adc_channels[dt_index].hw_settle_time;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700563 vadc->adc->amux_prop->fast_avg_setup =
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700564 vadc->adc->adc_channels[dt_index].fast_avg_setup;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700565
566 if (trigger_channel < ADC_SEQ_NONE)
567 vadc->adc->amux_prop->mode_sel = (ADC_OP_CONVERSION_SEQUENCER
568 << QPNP_VADC_OP_MODE_SHIFT);
569 else if (trigger_channel == ADC_SEQ_NONE)
570 vadc->adc->amux_prop->mode_sel = (ADC_OP_NORMAL_MODE
571 << QPNP_VADC_OP_MODE_SHIFT);
572 else {
573 pr_err("Invalid trigger channel:%d\n", trigger_channel);
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700574 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700575 }
576
577 vadc->adc->amux_prop->trigger_channel = trigger_channel;
578
579 rc = qpnp_vadc_configure(vadc->adc->amux_prop);
580 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700581 pr_err("qpnp vadc configure failed with %d\n", rc);
582 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700583 }
584
Siddartha Mohanadoss1a0d2032012-11-01 11:22:29 -0700585 rc = wait_for_completion_timeout(&vadc->adc->adc_rslt_completion,
586 QPNP_ADC_COMPLETION_TIMEOUT);
587 if (!rc) {
588 u8 status1 = 0;
589 rc = qpnp_vadc_read_reg(QPNP_VADC_STATUS1, &status1);
590 if (rc < 0)
591 goto fail_unlock;
592 status1 &= (QPNP_VADC_STATUS1_REQ_STS | QPNP_VADC_STATUS1_EOC);
593 if (status1 == QPNP_VADC_STATUS1_EOC)
594 pr_debug("End of conversion status set\n");
595 else {
596 pr_err("EOC interrupt not received\n");
597 rc = -EINVAL;
598 goto fail_unlock;
599 }
600 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700601
602 if (trigger_channel < ADC_SEQ_NONE) {
603 rc = qpnp_vadc_read_status(vadc->adc->amux_prop->mode_sel);
604 if (rc)
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700605 pr_debug("Conversion sequence timed out - %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700606 }
607
608 rc = qpnp_vadc_read_conversion_result(&result->adc_code);
609 if (rc) {
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700610 pr_err("qpnp vadc read adc code failed with %d\n", rc);
611 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700612 }
613
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700614 amux_prescaling =
615 vadc->adc->adc_channels[dt_index].chan_path_prescaling;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700616
617 vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
618 qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
619 vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
620 qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
621
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700622 scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700623 if (scale_type >= SCALE_NONE) {
624 rc = -EBADF;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700625 goto fail_unlock;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700626 }
627
628 vadc_scale_fn[scale_type].chan(result->adc_code,
629 vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
630
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700631fail_unlock:
632 mutex_unlock(&vadc->adc->adc_lock);
633
634 return rc;
635}
636EXPORT_SYMBOL(qpnp_vadc_conv_seq_request);
637
638int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
639 struct qpnp_vadc_result *result)
640{
641 return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
642 channel, result);
643}
644EXPORT_SYMBOL_GPL(qpnp_vadc_read);
645
646static ssize_t qpnp_adc_show(struct device *dev,
647 struct device_attribute *devattr, char *buf)
648{
649 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
650 struct qpnp_vadc_result result;
651 int rc = -1;
652
653 rc = qpnp_vadc_read(attr->index, &result);
654
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700655 if (rc) {
656 pr_err("VADC read error with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700657 return 0;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700658 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700659
660 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
661 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
662}
663
664static struct sensor_device_attribute qpnp_adc_attr =
665 SENSOR_ATTR(NULL, S_IRUGO, qpnp_adc_show, NULL, 0);
666
667static int32_t qpnp_vadc_init_hwmon(struct spmi_device *spmi)
668{
669 struct qpnp_vadc_drv *vadc = qpnp_vadc;
670 struct device_node *child;
671 struct device_node *node = spmi->dev.of_node;
672 int rc = 0, i = 0, channel;
673
674 for_each_child_of_node(node, child) {
675 channel = vadc->adc->adc_channels[i].channel_num;
676 qpnp_adc_attr.index = vadc->adc->adc_channels[i].channel_num;
677 qpnp_adc_attr.dev_attr.attr.name =
678 vadc->adc->adc_channels[i].name;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700679 memcpy(&vadc->sens_attr[i], &qpnp_adc_attr,
680 sizeof(qpnp_adc_attr));
Stephen Boydd7337962012-10-30 11:10:46 -0700681 sysfs_attr_init(&vadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700682 rc = device_create_file(&spmi->dev,
683 &vadc->sens_attr[i].dev_attr);
684 if (rc) {
685 dev_err(&spmi->dev,
686 "device_create_file failed for dev %s\n",
687 vadc->adc->adc_channels[i].name);
688 goto hwmon_err_sens;
689 }
690 i++;
691 }
692
693 return 0;
694hwmon_err_sens:
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700695 pr_err("Init HWMON failed for qpnp_adc with %d\n", rc);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700696 return rc;
697}
698
699static int __devinit qpnp_vadc_probe(struct spmi_device *spmi)
700{
701 struct qpnp_vadc_drv *vadc;
702 struct qpnp_adc_drv *adc_qpnp;
703 struct device_node *node = spmi->dev.of_node;
704 struct device_node *child;
705 int rc, count_adc_channel_list = 0;
706
707 if (!node)
708 return -EINVAL;
709
710 if (qpnp_vadc) {
711 pr_err("VADC already in use\n");
712 return -EBUSY;
713 }
714
715 for_each_child_of_node(node, child)
716 count_adc_channel_list++;
717
718 if (!count_adc_channel_list) {
719 pr_err("No channel listing\n");
720 return -EINVAL;
721 }
722
723 vadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_vadc_drv) +
724 (sizeof(struct sensor_device_attribute) *
725 count_adc_channel_list), GFP_KERNEL);
726 if (!vadc) {
727 dev_err(&spmi->dev, "Unable to allocate memory\n");
728 return -ENOMEM;
729 }
730
731 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
732 GFP_KERNEL);
733 if (!adc_qpnp) {
734 dev_err(&spmi->dev, "Unable to allocate memory\n");
735 return -ENOMEM;
736 }
737
738 vadc->adc = adc_qpnp;
739
740 rc = qpnp_adc_get_devicetree_data(spmi, vadc->adc);
741 if (rc) {
742 dev_err(&spmi->dev, "failed to read device tree\n");
743 return rc;
744 }
745
746 rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq,
747 qpnp_vadc_isr, IRQF_TRIGGER_RISING,
748 "qpnp_vadc_interrupt", vadc);
749 if (rc) {
750 dev_err(&spmi->dev,
751 "failed to request adc irq with error %d\n", rc);
752 return rc;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700753 } else {
754 enable_irq_wake(vadc->adc->adc_irq);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700755 }
756
757 qpnp_vadc = vadc;
758 dev_set_drvdata(&spmi->dev, vadc);
759 rc = qpnp_vadc_init_hwmon(spmi);
760 if (rc) {
761 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -0700762 return rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700763 }
764 vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
765 vadc->vadc_init_calib = false;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700766 vadc->max_channels_available = count_adc_channel_list;
Siddartha Mohanadoss0ee28122012-11-01 10:35:01 -0700767 vadc->vadc_initialized = true;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700768
769 return 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700770}
771
772static int __devexit qpnp_vadc_remove(struct spmi_device *spmi)
773{
774 struct qpnp_vadc_drv *vadc = dev_get_drvdata(&spmi->dev);
775 struct device_node *node = spmi->dev.of_node;
776 struct device_node *child;
777 int i = 0;
778
779 for_each_child_of_node(node, child) {
780 device_remove_file(&spmi->dev,
781 &vadc->sens_attr[i].dev_attr);
782 i++;
783 }
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700784 vadc->vadc_initialized = false;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700785 dev_set_drvdata(&spmi->dev, NULL);
786
787 return 0;
788}
789
790static const struct of_device_id qpnp_vadc_match_table[] = {
791 { .compatible = "qcom,qpnp-vadc",
792 },
793 {}
794};
795
796static struct spmi_driver qpnp_vadc_driver = {
797 .driver = {
798 .name = "qcom,qpnp-vadc",
799 .of_match_table = qpnp_vadc_match_table,
800 },
801 .probe = qpnp_vadc_probe,
802 .remove = qpnp_vadc_remove,
803};
804
805static int __init qpnp_vadc_init(void)
806{
807 return spmi_driver_register(&qpnp_vadc_driver);
808}
809module_init(qpnp_vadc_init);
810
811static void __exit qpnp_vadc_exit(void)
812{
813 spmi_driver_unregister(&qpnp_vadc_driver);
814}
815module_exit(qpnp_vadc_exit);
816
817MODULE_DESCRIPTION("QPNP PMIC Voltage ADC driver");
818MODULE_LICENSE("GPL v2");