blob: 10c5a17b20dd34ace0cb50c26b997346c33a0a47 [file] [log] [blame]
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -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/wakelock.h>
29#include <linux/interrupt.h>
30#include <linux/completion.h>
31#include <linux/hwmon-sysfs.h>
32#include <linux/qpnp/qpnp-adc.h>
33#include <linux/platform_device.h>
34
35/* QPNP IADC register definition */
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070036#define QPNP_IADC_REVISION1 0x0
37#define QPNP_IADC_REVISION2 0x1
38#define QPNP_IADC_REVISION3 0x2
39#define QPNP_IADC_REVISION4 0x3
40#define QPNP_IADC_PERPH_TYPE 0x4
41#define QPNP_IADC_PERH_SUBTYPE 0x5
42
43#define QPNP_IADC_SUPPORTED_REVISION2 1
44
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070045#define QPNP_STATUS1 0x8
46#define QPNP_STATUS1_OP_MODE 4
47#define QPNP_STATUS1_MULTI_MEAS_EN BIT(3)
48#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
49#define QPNP_STATUS1_REQ_STS BIT(1)
50#define QPNP_STATUS1_EOC BIT(0)
51#define QPNP_STATUS2 0x9
52#define QPNP_STATUS2_CONV_SEQ_STATE_SHIFT 4
53#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
54#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
55#define QPNP_CONV_TIMEOUT_ERR 2
56
57#define QPNP_INT_RT_ST 0x10
58#define QPNP_INT_SET_TYPE 0x11
59#define QPNP_INT_SET_TYPE_LOW_THR_INT_SET BIT(4)
60#define QPNP_INT_SET_TYPE_HIGH_THR_INT_SET BIT(3)
61#define QPNP_INT_SET_TYPE_CONV_SEQ_TIMEOUT_INT_SET BIT(2)
62#define QPNP_INT_SET_TYPE_FIFO_NOT_EMPTY_INT_SET BIT(1)
63#define QPNP_INT_SET_TYPE_EOC_SET_INT_TYPE BIT(0)
64#define QPNP_INT_POLARITY_HIGH 0x12
65#define QPNP_INT_POLARITY_LOW 0x13
66#define QPNP_INT_EN_SET 0x15
67#define QPNP_INT_EN_SET_LOW_THR_INT_EN_SET BIT(4)
68#define QPNP_INT_EN_SET_HIGH_THR_INT_EN_SET BIT(3)
69#define QPNP_INT_EN_SET_CONV_SEQ_TIMEOUT_INT_EN BIT(2)
70#define QPNP_INT_EN_SET_FIFO_NOT_EMPTY_INT_EN BIT(1)
71#define QPNP_INT_EN_SET_EOC_INT_EN_SET BIT(0)
72#define QPNP_INT_CLR 0x16
73#define QPNP_INT_CLR_LOW_THR_INT_EN_CLR BIT(4)
74#define QPNP_INT_CLR_HIGH_THR_INT_EN_CLKR BIT(3)
75#define QPNP_INT_CLR_CONV_SEQ_TIMEOUT_INT_EN BIT(2)
76#define QPNP_INT_CLR_FIFO_NOT_EMPTY_INT_EN BIT(1)
77#define QPNP_INT_CLR_EOC_INT_EN_CLR BIT(0)
78#define QPNP_INT_CLR_MASK 0x1f
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070079#define QPNP_IADC_MODE_CTL 0x40
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070080#define QPNP_OP_MODE_SHIFT 4
81#define QPNP_USE_BMS_DATA BIT(4)
82#define QPNP_VADC_SYNCH_EN BIT(2)
83#define QPNP_OFFSET_RMV_EN BIT(1)
84#define QPNP_ADC_TRIM_EN BIT(0)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070085#define QPNP_IADC_EN_CTL1 0x46
86#define QPNP_IADC_ADC_EN BIT(7)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -070087#define QPNP_ADC_CH_SEL_CTL 0x48
88#define QPNP_ADC_DIG_PARAM 0x50
89#define QPNP_ADC_CLK_SEL_MASK 0x3
90#define QPNP_ADC_DEC_RATIO_SEL_MASK 0xc
91#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 2
92
93#define QPNP_HW_SETTLE_DELAY 0x51
94#define QPNP_CONV_REQ 0x52
95#define QPNP_CONV_REQ_SET BIT(7)
96#define QPNP_CONV_SEQ_CTL 0x54
97#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
98#define QPNP_CONV_SEQ_TRIG_CTL 0x55
99#define QPNP_FAST_AVG_CTL 0x5a
100
101#define QPNP_M0_LOW_THR_LSB 0x5c
102#define QPNP_M0_LOW_THR_MSB 0x5d
103#define QPNP_M0_HIGH_THR_LSB 0x5e
104#define QPNP_M0_HIGH_THR_MSB 0x5f
105#define QPNP_M1_LOW_THR_LSB 0x69
106#define QPNP_M1_LOW_THR_MSB 0x6a
107#define QPNP_M1_HIGH_THR_LSB 0x6b
108#define QPNP_M1_HIGH_THR_MSB 0x6c
109
110#define QPNP_DATA0 0x60
111#define QPNP_DATA1 0x61
112#define QPNP_CONV_TIMEOUT_ERR 2
113
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700114#define QPNP_IADC_SEC_ACCESS 0xD0
115#define QPNP_IADC_SEC_ACCESS_DATA 0xA5
116#define QPNP_IADC_MSB_OFFSET 0xF2
117#define QPNP_IADC_LSB_OFFSET 0xF3
118#define QPNP_IADC_NOMINAL_RSENSE 0xF4
119#define QPNP_IADC_ATE_GAIN_CALIB_OFFSET 0xF5
120
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700121#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
122#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
123
124#define QPNP_IADC_ADC_DIG_PARAM 0x50
125#define QPNP_IADC_CLK_SEL_SHIFT 1
126#define QPNP_IADC_DEC_RATIO_SEL 3
127
128#define QPNP_IADC_CONV_REQUEST 0x52
129#define QPNP_IADC_CONV_REQ BIT(7)
130
131#define QPNP_IADC_DATA0 0x60
132#define QPNP_IADC_DATA1 0x61
133
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700134#define QPNP_ADC_CONV_TIME_MIN 8000
135#define QPNP_ADC_CONV_TIME_MAX 8200
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700136
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700137#define QPNP_ADC_GAIN_NV 17857
138#define QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL 0
139#define QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR 10000000
140#define QPNP_IADC_NANO_VOLTS_FACTOR 1000000000
141#define QPNP_IADC_CALIB_SECONDS 300000
142#define QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT 15625
143#define QPNP_IADC_DIE_TEMP_CALIB_OFFSET 5000
144
145#define QPNP_RAW_CODE_16_BIT_MSB_MASK 0xff00
146#define QPNP_RAW_CODE_16_BIT_LSB_MASK 0xff
147#define QPNP_BIT_SHIFT_8 8
148#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700149
150struct qpnp_iadc_drv {
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700151 struct qpnp_adc_drv *adc;
152 int32_t rsense;
153 struct device *iadc_hwmon;
154 bool iadc_init_calib;
155 bool iadc_initialized;
156 int64_t die_temp_calib_offset;
157 struct delayed_work iadc_work;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700158 struct sensor_device_attribute sens_attr[0];
159};
160
161struct qpnp_iadc_drv *qpnp_iadc;
162
163static int32_t qpnp_iadc_read_reg(uint32_t reg, u8 *data)
164{
165 struct qpnp_iadc_drv *iadc = qpnp_iadc;
166 int rc;
167
168 rc = spmi_ext_register_readl(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700169 (iadc->adc->offset + reg), data, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700170 if (rc < 0) {
171 pr_err("qpnp iadc read reg %d failed with %d\n", reg, rc);
172 return rc;
173 }
174
175 return 0;
176}
177
178static int32_t qpnp_iadc_write_reg(uint32_t reg, u8 data)
179{
180 struct qpnp_iadc_drv *iadc = qpnp_iadc;
181 int rc;
182 u8 *buf;
183
184 buf = &data;
185 rc = spmi_ext_register_writel(iadc->adc->spmi->ctrl, iadc->adc->slave,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700186 (iadc->adc->offset + reg), buf, 1);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700187 if (rc < 0) {
188 pr_err("qpnp iadc write reg %d failed with %d\n", reg, rc);
189 return rc;
190 }
191
192 return 0;
193}
194
195static int32_t qpnp_iadc_configure_interrupt(void)
196{
197 int rc = 0;
198 u8 data = 0;
199
200 /* Configure interrupt as an Edge trigger */
201 rc = qpnp_iadc_write_reg(QPNP_INT_SET_TYPE,
202 QPNP_INT_CLR_MASK);
203 if (rc < 0) {
204 pr_err("%s Interrupt configure failed\n", __func__);
205 return rc;
206 }
207
208 /* Configure interrupt for rising edge trigger */
209 rc = qpnp_iadc_write_reg(QPNP_INT_POLARITY_HIGH,
210 QPNP_INT_CLR_MASK);
211 if (rc < 0) {
212 pr_err("%s Rising edge trigger configure failed\n", __func__);
213 return rc;
214 }
215
216 /* Disable low level interrupt triggering */
217 data = QPNP_INT_CLR_MASK;
218 rc = qpnp_iadc_write_reg(QPNP_INT_POLARITY_LOW,
219 (~data & QPNP_INT_CLR_MASK));
220 if (rc < 0) {
221 pr_err("%s Setting level low to disable failed\n", __func__);
222 return rc;
223 }
224
225 return 0;
226}
227
228static void trigger_iadc_completion(struct work_struct *work)
229{
230 struct qpnp_iadc_drv *iadc = qpnp_iadc;
231 int rc;
232
233 rc = qpnp_iadc_write_reg(QPNP_INT_CLR, QPNP_INT_CLR_MASK);
234 if (rc < 0)
235 pr_err("qpnp iadc interrupt mask failed with %d\n", rc);
236
237 complete(&iadc->adc->adc_rslt_completion);
238
239 return;
240}
241DECLARE_WORK(trigger_iadc_completion_work, trigger_iadc_completion);
242
243static irqreturn_t qpnp_iadc_isr(int irq, void *dev_id)
244{
245 schedule_work(&trigger_iadc_completion_work);
246
247 return IRQ_HANDLED;
248}
249
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700250static int32_t qpnp_iadc_enable(bool state)
251{
252 int rc = 0;
253 u8 data = 0;
254
255 data = QPNP_IADC_ADC_EN;
256 if (state) {
257 rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
258 data);
259 if (rc < 0) {
260 pr_err("IADC enable failed\n");
261 return rc;
262 }
263 } else {
264 rc = qpnp_iadc_write_reg(QPNP_IADC_EN_CTL1,
265 (~data & QPNP_IADC_ADC_EN));
266 if (rc < 0) {
267 pr_err("IADC disable failed\n");
268 return rc;
269 }
270 }
271
272 return 0;
273}
274
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700275static int32_t qpnp_iadc_read_conversion_result(uint16_t *data)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700276{
277 uint8_t rslt_lsb, rslt_msb;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700278 uint16_t rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700279 int32_t rc;
280
281 rc = qpnp_iadc_read_reg(QPNP_IADC_DATA0, &rslt_lsb);
282 if (rc < 0) {
283 pr_err("qpnp adc result read failed with %d\n", rc);
284 return rc;
285 }
286
287 rc = qpnp_iadc_read_reg(QPNP_IADC_DATA1, &rslt_msb);
288 if (rc < 0) {
289 pr_err("qpnp adc result read failed with %d\n", rc);
290 return rc;
291 }
292
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700293 rslt = (rslt_msb << 8) | rslt_lsb;
294 *data = rslt;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700295
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700296 rc = qpnp_iadc_enable(false);
297 if (rc)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700298 return rc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700299
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700300 return 0;
301}
302
303static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700304 uint16_t *raw_code)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700305{
306 struct qpnp_iadc_drv *iadc = qpnp_iadc;
307 u8 qpnp_iadc_mode_reg = 0, qpnp_iadc_ch_sel_reg = 0;
308 u8 qpnp_iadc_conv_req = 0, qpnp_iadc_dig_param_reg = 0;
309 int32_t rc = 0;
310
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700311 qpnp_iadc_ch_sel_reg = channel;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700312
313 qpnp_iadc_dig_param_reg |= iadc->adc->amux_prop->decimation <<
314 QPNP_IADC_DEC_RATIO_SEL;
315
316 qpnp_iadc_conv_req = QPNP_IADC_CONV_REQ;
317
318 rc = qpnp_iadc_write_reg(QPNP_INT_EN_SET,
319 QPNP_INT_EN_SET_EOC_INT_EN_SET);
320 if (rc < 0) {
321 pr_err("qpnp adc configure error for interrupt setup\n");
322 return rc;
323 }
324
325 rc = qpnp_iadc_write_reg(QPNP_IADC_MODE_CTL, qpnp_iadc_mode_reg);
326 if (rc) {
327 pr_err("qpnp adc read adc failed with %d\n", rc);
328 return rc;
329 }
330
331 rc = qpnp_iadc_write_reg(QPNP_IADC_ADC_CH_SEL_CTL,
332 qpnp_iadc_ch_sel_reg);
333 if (rc) {
334 pr_err("qpnp adc read adc failed with %d\n", rc);
335 return rc;
336 }
337
338 rc = qpnp_iadc_write_reg(QPNP_ADC_DIG_PARAM,
339 qpnp_iadc_dig_param_reg);
340 if (rc) {
341 pr_err("qpnp adc read adc failed with %d\n", rc);
342 return rc;
343 }
344
345 rc = qpnp_iadc_write_reg(QPNP_HW_SETTLE_DELAY,
346 iadc->adc->amux_prop->hw_settle_time);
347 if (rc < 0) {
348 pr_err("qpnp adc configure error for hw settling time setup\n");
349 return rc;
350 }
351
352 rc = qpnp_iadc_write_reg(QPNP_FAST_AVG_CTL,
353 iadc->adc->amux_prop->fast_avg_setup);
354 if (rc < 0) {
355 pr_err("qpnp adc fast averaging configure error\n");
356 return rc;
357 }
358
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700359 rc = qpnp_iadc_enable(true);
360 if (rc)
361 return rc;
362
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700363 rc = qpnp_iadc_write_reg(QPNP_CONV_REQ, qpnp_iadc_conv_req);
364 if (rc) {
365 pr_err("qpnp adc read adc failed with %d\n", rc);
366 return rc;
367 }
368
369 wait_for_completion(&iadc->adc->adc_rslt_completion);
370
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700371 rc = qpnp_iadc_read_conversion_result(raw_code);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700372 if (rc) {
373 pr_err("qpnp adc read adc failed with %d\n", rc);
374 return rc;
375 }
376
377 return 0;
378}
379
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700380static int32_t qpnp_convert_raw_offset_voltage(void)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700381{
382 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700383 uint32_t num = 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700384
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700385 num = iadc->adc->calib.offset_raw - iadc->adc->calib.offset_raw;
386
387 iadc->adc->calib.offset_uv = (num * QPNP_ADC_GAIN_NV)/
388 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
389
390 num = iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw;
391
392 iadc->adc->calib.gain_uv = (num * QPNP_ADC_GAIN_NV)/
393 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
394
395 return 0;
396}
397
398static int32_t qpnp_iadc_calibrate_for_trim(void)
399{
400 struct qpnp_iadc_drv *iadc = qpnp_iadc;
401 uint8_t rslt_lsb, rslt_msb;
402 int32_t rc = 0;
403 uint16_t raw_data;
404
405 rc = qpnp_iadc_configure(GAIN_CALIBRATION_17P857MV, &raw_data);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700406 if (rc < 0) {
407 pr_err("qpnp adc result read failed with %d\n", rc);
408 goto fail;
409 }
410
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700411 iadc->adc->calib.gain_raw = raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700412
413 rc = qpnp_iadc_configure(OFFSET_CALIBRATION_SHORT_CADC_LEADS,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700414 &raw_data);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700415 if (rc < 0) {
416 pr_err("qpnp adc result read failed with %d\n", rc);
417 goto fail;
418 }
419
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700420 iadc->adc->calib.offset_raw = raw_data;
421 if (rc < 0) {
422 pr_err("qpnp adc offset/gain calculation failed\n");
423 goto fail;
424 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700425
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700426 rc = qpnp_convert_raw_offset_voltage();
427
428 rslt_msb = (raw_data & QPNP_RAW_CODE_16_BIT_MSB_MASK) >>
429 QPNP_BIT_SHIFT_8;
430 rslt_lsb = raw_data & QPNP_RAW_CODE_16_BIT_LSB_MASK;
431
432 rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
433 QPNP_IADC_SEC_ACCESS_DATA);
434 if (rc < 0) {
435 pr_err("qpnp iadc configure error for sec access\n");
436 goto fail;
437 }
438
439 rc = qpnp_iadc_write_reg(QPNP_IADC_MSB_OFFSET,
440 rslt_msb);
441 if (rc < 0) {
442 pr_err("qpnp iadc configure error for MSB write\n");
443 goto fail;
444 }
445
446 rc = qpnp_iadc_write_reg(QPNP_IADC_SEC_ACCESS,
447 QPNP_IADC_SEC_ACCESS_DATA);
448 if (rc < 0) {
449 pr_err("qpnp iadc configure error for sec access\n");
450 goto fail;
451 }
452
453 rc = qpnp_iadc_write_reg(QPNP_IADC_LSB_OFFSET,
454 rslt_lsb);
455 if (rc < 0) {
456 pr_err("qpnp iadc configure error for LSB write\n");
457 goto fail;
458 }
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700459fail:
460 return rc;
461}
462
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700463static void qpnp_iadc_work(struct work_struct *work)
464{
465 struct qpnp_iadc_drv *iadc = qpnp_iadc;
466 int rc = 0;
467
468 mutex_lock(&iadc->adc->adc_lock);
469
470 rc = qpnp_iadc_calibrate_for_trim();
471 if (rc)
472 pr_err("periodic IADC calibration failed\n");
473
474 mutex_unlock(&iadc->adc->adc_lock);
475
476 schedule_delayed_work(&iadc->iadc_work,
477 round_jiffies_relative(msecs_to_jiffies
478 (QPNP_IADC_CALIB_SECONDS)));
479
480 return;
481}
482
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700483static int32_t qpnp_iadc_version_check(void)
484{
485 uint8_t revision;
486 int rc;
487
488 rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &revision);
489 if (rc < 0) {
490 pr_err("qpnp adc result read failed with %d\n", rc);
491 return rc;
492 }
493
494 if (revision < QPNP_IADC_SUPPORTED_REVISION2) {
495 pr_err("IADC Version not supported\n");
496 return -EINVAL;
497 }
498
499 return 0;
500}
501
502int32_t qpnp_iadc_is_ready(void)
503{
504 struct qpnp_iadc_drv *iadc = qpnp_iadc;
505
506 if (!iadc || !iadc->iadc_initialized)
507 return -EPROBE_DEFER;
508 else
509 return 0;
510}
511EXPORT_SYMBOL(qpnp_iadc_is_ready);
512
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700513int32_t qpnp_iadc_get_rsense(int32_t *rsense)
514{
515 uint8_t rslt_rsense;
516 int32_t rc, sign_bit = 0;
517
518 rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
519 if (rc < 0) {
520 pr_err("qpnp adc rsense read failed with %d\n", rc);
521 return rc;
522 }
523
524 if (rslt_rsense & QPNP_RSENSE_MSB_SIGN_CHECK)
525 sign_bit = 1;
526
527 rslt_rsense &= ~QPNP_RSENSE_MSB_SIGN_CHECK;
528
529 if (sign_bit)
530 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR -
531 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
532 else
533 *rsense = QPNP_IADC_INTERNAL_RSENSE_N_OHMS_FACTOR +
534 (rslt_rsense * QPNP_IADC_RSENSE_LSB_N_OHMS_PER_BIT);
535
536 return rc;
537}
538
539int32_t qpnp_check_pmic_temp(void)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700540{
541 struct qpnp_iadc_drv *iadc = qpnp_iadc;
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700542 struct qpnp_vadc_result result_pmic_therm;
543 int rc;
544
545 rc = qpnp_vadc_read(DIE_TEMP, &result_pmic_therm);
546 if (rc < 0)
547 return rc;
548
549 if (((uint64_t) (result_pmic_therm.physical -
550 iadc->die_temp_calib_offset))
551 > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
552 mutex_lock(&iadc->adc->adc_lock);
553
554 rc = qpnp_iadc_calibrate_for_trim();
555 if (rc)
556 pr_err("periodic IADC calibration failed\n");
557
558 mutex_unlock(&iadc->adc->adc_lock);
559 }
560
561 return 0;
562}
563
564int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
565 struct qpnp_iadc_result *result)
566{
567 struct qpnp_iadc_drv *iadc = qpnp_iadc;
568 int32_t rc, rsense_n_ohms, sign = 0, num;
569 int64_t result_current;
570 uint16_t raw_data;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700571
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700572 if (!iadc || !iadc->iadc_initialized)
573 return -EPROBE_DEFER;
574
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700575 rc = qpnp_check_pmic_temp();
576 if (rc) {
577 pr_err("Error checking pmic therm temp\n");
578 return rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700579 }
580
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700581 mutex_lock(&iadc->adc->adc_lock);
582
583 rc = qpnp_iadc_configure(channel, &raw_data);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700584 if (rc < 0) {
585 pr_err("qpnp adc result read failed with %d\n", rc);
586 goto fail;
587 }
588
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700589 rc = qpnp_iadc_get_rsense(&rsense_n_ohms);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700590
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700591 num = raw_data - iadc->adc->calib.offset_raw;
592 if (num < 0) {
593 sign = 1;
594 num = -num;
595 }
596
597 result->result_uv = (num * QPNP_ADC_GAIN_NV)/
598 (iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
599 result_current = result->result_uv;
600 result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
601 do_div(result_current, rsense_n_ohms);
602
603 if (sign) {
604 result->result_uv = -result->result_uv;
605 result_current = -result_current;
606 }
607
608 result->result_ua = (int32_t) result_current;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700609fail:
610 mutex_unlock(&iadc->adc->adc_lock);
611
612 return rc;
613}
614EXPORT_SYMBOL(qpnp_iadc_read);
615
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700616int32_t qpnp_iadc_get_gain_and_offset(struct qpnp_iadc_calib *result)
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700617{
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700618 struct qpnp_iadc_drv *iadc = qpnp_iadc;
619 int rc;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700620
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700621 if (!iadc || !iadc->iadc_initialized)
622 return -EPROBE_DEFER;
623
624 rc = qpnp_check_pmic_temp();
625 if (rc) {
626 pr_err("Error checking pmic therm temp\n");
627 return rc;
628 }
629
630 mutex_lock(&iadc->adc->adc_lock);
631 result->gain_raw = iadc->adc->calib.gain_raw;
632 result->ideal_gain_nv = QPNP_ADC_GAIN_NV;
633 result->gain_uv = iadc->adc->calib.gain_uv;
634 result->offset_raw = iadc->adc->calib.offset_raw;
635 result->ideal_offset_uv =
636 QPNP_OFFSET_CALIBRATION_SHORT_CADC_LEADS_IDEAL;
637 result->offset_uv = iadc->adc->calib.offset_uv;
638 mutex_unlock(&iadc->adc->adc_lock);
639
640 return 0;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700641}
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700642EXPORT_SYMBOL(qpnp_iadc_get_gain_and_offset);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700643
644static ssize_t qpnp_iadc_show(struct device *dev,
645 struct device_attribute *devattr, char *buf)
646{
647 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700648 struct qpnp_iadc_result result;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700649 int rc = -1;
650
651 rc = qpnp_iadc_read(attr->index, &result);
652
653 if (rc)
654 return 0;
655
656 return snprintf(buf, QPNP_ADC_HWMON_NAME_LENGTH,
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700657 "Result:%d\n", result.result_ua);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700658}
659
660static struct sensor_device_attribute qpnp_adc_attr =
661 SENSOR_ATTR(NULL, S_IRUGO, qpnp_iadc_show, NULL, 0);
662
663static int32_t qpnp_iadc_init_hwmon(struct spmi_device *spmi)
664{
665 struct qpnp_iadc_drv *iadc = qpnp_iadc;
666 struct device_node *child;
667 struct device_node *node = spmi->dev.of_node;
668 int rc = 0, i = 0, channel;
669
670 for_each_child_of_node(node, child) {
671 channel = iadc->adc->adc_channels[i].channel_num;
672 qpnp_adc_attr.index = iadc->adc->adc_channels[i].channel_num;
673 qpnp_adc_attr.dev_attr.attr.name =
674 iadc->adc->adc_channels[i].name;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700675 memcpy(&iadc->sens_attr[i], &qpnp_adc_attr,
676 sizeof(qpnp_adc_attr));
Stephen Boyd8a5c4e42012-10-30 11:07:22 -0700677 sysfs_attr_init(&iadc->sens_attr[i].dev_attr.attr);
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700678 rc = device_create_file(&spmi->dev,
679 &iadc->sens_attr[i].dev_attr);
680 if (rc) {
681 dev_err(&spmi->dev,
682 "device_create_file failed for dev %s\n",
683 iadc->adc->adc_channels[i].name);
684 goto hwmon_err_sens;
685 }
686 i++;
687 }
688
689 return 0;
690hwmon_err_sens:
691 pr_err("Init HWMON failed for qpnp_iadc with %d\n", rc);
692 return rc;
693}
694
695static int __devinit qpnp_iadc_probe(struct spmi_device *spmi)
696{
697 struct qpnp_iadc_drv *iadc;
698 struct qpnp_adc_drv *adc_qpnp;
699 struct device_node *node = spmi->dev.of_node;
700 struct device_node *child;
701 int rc, count_adc_channel_list = 0;
702
703 if (!node)
704 return -EINVAL;
705
706 if (qpnp_iadc) {
707 pr_err("IADC already in use\n");
708 return -EBUSY;
709 }
710
711 for_each_child_of_node(node, child)
712 count_adc_channel_list++;
713
714 if (!count_adc_channel_list) {
715 pr_err("No channel listing\n");
716 return -EINVAL;
717 }
718
719 iadc = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_iadc_drv) +
720 (sizeof(struct sensor_device_attribute) *
721 count_adc_channel_list), GFP_KERNEL);
722 if (!iadc) {
723 dev_err(&spmi->dev, "Unable to allocate memory\n");
724 return -ENOMEM;
725 }
726
727 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
728 GFP_KERNEL);
729 if (!adc_qpnp) {
730 dev_err(&spmi->dev, "Unable to allocate memory\n");
731 return -ENOMEM;
732 }
733
734 iadc->adc = adc_qpnp;
735
736 rc = qpnp_adc_get_devicetree_data(spmi, iadc->adc);
737 if (rc) {
738 dev_err(&spmi->dev, "failed to read device tree\n");
739 return rc;
740 }
741
742 rc = of_property_read_u32(node, "qcom,rsense",
743 &iadc->rsense);
744 if (rc) {
745 pr_err("Invalid rsens reference property\n");
746 return -EINVAL;
747 }
748
749 rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq,
750 qpnp_iadc_isr,
751 IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
752 if (rc) {
753 dev_err(&spmi->dev, "failed to request adc irq\n");
754 return rc;
755 } else
756 enable_irq_wake(iadc->adc->adc_irq);
757
758 iadc->iadc_init_calib = false;
759 dev_set_drvdata(&spmi->dev, iadc);
760 qpnp_iadc = iadc;
761
762 rc = qpnp_iadc_init_hwmon(spmi);
763 if (rc) {
764 dev_err(&spmi->dev, "failed to initialize qpnp hwmon adc\n");
765 return rc;
766 }
767 iadc->iadc_hwmon = hwmon_device_register(&iadc->adc->spmi->dev);
768
769 rc = qpnp_iadc_configure_interrupt();
770 if (rc) {
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700771 dev_err(&spmi->dev, "failed to configure interrupt\n");
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700772 return rc;
773 }
774
Siddartha Mohanadoss5e2988d2012-09-24 17:03:56 -0700775 rc = qpnp_iadc_version_check();
776 if (rc) {
777 dev_err(&spmi->dev, "IADC version not supported\n");
778 return rc;
779 }
780
781 rc = qpnp_iadc_calibrate_for_trim();
782 if (rc) {
783 dev_err(&spmi->dev, "failed to calibrate for USR trim\n");
784 return rc;
785 }
786 iadc->iadc_init_calib = true;
787 INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
788 schedule_delayed_work(&iadc->iadc_work,
789 round_jiffies_relative(msecs_to_jiffies
790 (QPNP_IADC_CALIB_SECONDS)));
791 iadc->iadc_initialized = true;
792
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700793 return 0;
794}
795
796static int __devexit qpnp_iadc_remove(struct spmi_device *spmi)
797{
798 struct qpnp_iadc_drv *iadc = dev_get_drvdata(&spmi->dev);
799 struct device_node *node = spmi->dev.of_node;
800 struct device_node *child;
801 int i = 0;
802
803 for_each_child_of_node(node, child) {
804 device_remove_file(&spmi->dev,
805 &iadc->sens_attr[i].dev_attr);
806 i++;
807 }
808 dev_set_drvdata(&spmi->dev, NULL);
809
810 return 0;
811}
812
813static const struct of_device_id qpnp_iadc_match_table[] = {
814 { .compatible = "qcom,qpnp-iadc",
815 },
816 {}
817};
818
819static struct spmi_driver qpnp_iadc_driver = {
820 .driver = {
821 .name = "qcom,qpnp-iadc",
822 .of_match_table = qpnp_iadc_match_table,
823 },
824 .probe = qpnp_iadc_probe,
825 .remove = qpnp_iadc_remove,
826};
827
828static int __init qpnp_iadc_init(void)
829{
830 return spmi_driver_register(&qpnp_iadc_driver);
831}
832module_init(qpnp_iadc_init);
833
834static void __exit qpnp_iadc_exit(void)
835{
836 spmi_driver_unregister(&qpnp_iadc_driver);
837}
838module_exit(qpnp_iadc_exit);
839
840MODULE_DESCRIPTION("QPNP PMIC current ADC driver");
841MODULE_LICENSE("GPL v2");