blob: bdcaa4d9cd56b5af41712904d9c249afd8ae2bc2 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -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#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/mutex.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/err.h>
19#include <linux/msm_adc.h>
Anirudh Ghayalc2019332011-11-12 06:29:10 +053020#include <linux/mfd/pm8xxx/core.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021#include <linux/mfd/pmic8058.h>
22#include <linux/interrupt.h>
23#include <linux/slab.h>
24#include <linux/ratelimit.h>
25#include <linux/delay.h>
Siddartha Mohanadoss71128482011-10-05 15:16:10 -070026#include <linux/wakelock.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027
28#include <mach/mpp.h>
29#include <mach/msm_xo.h>
30
31#define ADC_DRIVER_NAME "pm8058-xoadc"
32
33#define MAX_QUEUE_LENGTH 0X15
34#define MAX_CHANNEL_PROPERTIES_QUEUE 0X7
35#define MAX_QUEUE_SLOT 0x1
36
37/* User Processor */
38#define ADC_ARB_USRP_CNTRL 0x197
39 #define ADC_ARB_USRP_CNTRL_EN_ARB BIT(0)
40 #define ADC_ARB_USRP_CNTRL_RSV1 BIT(1)
41 #define ADC_ARB_USRP_CNTRL_RSV2 BIT(2)
42 #define ADC_ARB_USRP_CNTRL_RSV3 BIT(3)
43 #define ADC_ARB_USRP_CNTRL_RSV4 BIT(4)
44 #define ADC_ARB_USRP_CNTRL_RSV5 BIT(5)
45 #define ADC_ARB_USRP_CNTRL_EOC BIT(6)
46 #define ADC_ARB_USRP_CNTRL_REQ BIT(7)
47
48#define ADC_ARB_USRP_AMUX_CNTRL 0x198
49#define ADC_ARB_USRP_ANA_PARAM 0x199
50#define ADC_ARB_USRP_DIG_PARAM 0x19A
51#define ADC_ARB_USRP_RSV 0x19B
52
53#define ADC_ARB_USRP_DATA0 0x19D
54#define ADC_ARB_USRP_DATA1 0x19C
55
56struct pmic8058_adc {
Anirudh Ghayalc2019332011-11-12 06:29:10 +053057 struct device *dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058 struct xoadc_platform_data *pdata;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059 struct adc_properties *adc_prop;
60 struct xoadc_conv_state conv[2];
61 int xoadc_queue_count;
62 int adc_irq;
63 struct linear_graph *adc_graph;
64 struct xoadc_conv_state *conv_slot_request;
65 struct xoadc_conv_state *conv_queue_list;
66 struct adc_conv_slot conv_queue_elements[MAX_QUEUE_LENGTH];
67 int xoadc_num;
68 struct msm_xo_voter *adc_voter;
Siddartha Mohanadoss71128482011-10-05 15:16:10 -070069 struct wake_lock adc_wakelock;
70 /* flag to warn/bug if wakelocks are taken after suspend_noirq */
71 int msm_suspend_check;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072};
73
74static struct pmic8058_adc *pmic_adc[XOADC_PMIC_0 + 1];
75
76static bool xoadc_initialized, xoadc_calib_first_adc;
77
78DEFINE_RATELIMIT_STATE(pm8058_xoadc_msg_ratelimit,
79 DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
80
81static inline int pm8058_xoadc_can_print(void)
82{
83 return __ratelimit(&pm8058_xoadc_msg_ratelimit);
84}
85
86int32_t pm8058_xoadc_registered(void)
87{
88 return xoadc_initialized;
89}
90EXPORT_SYMBOL(pm8058_xoadc_registered);
91
92void pm8058_xoadc_restore_slot(uint32_t adc_instance,
93 struct adc_conv_slot *slot)
94{
95 struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
96 struct xoadc_conv_state *slot_state = adc_pmic->conv_slot_request;
97
98 mutex_lock(&slot_state->list_lock);
99 list_add(&slot->list, &slot_state->slots);
100 mutex_unlock(&slot_state->list_lock);
101}
102EXPORT_SYMBOL(pm8058_xoadc_restore_slot);
103
104void pm8058_xoadc_slot_request(uint32_t adc_instance,
105 struct adc_conv_slot **slot)
106{
107 struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
108 struct xoadc_conv_state *slot_state = adc_pmic->conv_slot_request;
109
110 mutex_lock(&slot_state->list_lock);
111
112 if (!list_empty(&slot_state->slots)) {
113 *slot = list_first_entry(&slot_state->slots,
114 struct adc_conv_slot, list);
115 list_del(&(*slot)->list);
116 } else
117 *slot = NULL;
118
119 mutex_unlock(&slot_state->list_lock);
120}
121EXPORT_SYMBOL(pm8058_xoadc_slot_request);
122
123static int32_t pm8058_xoadc_arb_cntrl(uint32_t arb_cntrl,
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700124 uint32_t adc_instance, uint32_t channel)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125{
126 struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
127 int i, rc;
128 u8 data_arb_cntrl;
129
130 data_arb_cntrl = ADC_ARB_USRP_CNTRL_EOC |
131 ADC_ARB_USRP_CNTRL_RSV5 |
132 ADC_ARB_USRP_CNTRL_RSV4;
133
134 if (arb_cntrl) {
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700135 if (adc_pmic->msm_suspend_check)
136 pr_err("XOADC request being made after suspend irq "
137 "with channel id:%d\n", channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 data_arb_cntrl |= ADC_ARB_USRP_CNTRL_EN_ARB;
139 msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_ON);
140 adc_pmic->pdata->xoadc_mpp_config();
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700141 wake_lock(&adc_pmic->adc_wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 }
143
144 /* Write twice to the CNTRL register for the arbiter settings
145 to take into effect */
146 for (i = 0; i < 2; i++) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530147 rc = pm8xxx_writeb(adc_pmic->dev->parent, ADC_ARB_USRP_CNTRL,
148 data_arb_cntrl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 if (rc < 0) {
150 pr_debug("%s: PM8058 write failed\n", __func__);
151 return rc;
152 }
153 }
154
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700155 if (!arb_cntrl) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156 msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_OFF);
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700157 wake_unlock(&adc_pmic->adc_wakelock);
158 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159
160 return 0;
161}
162
163static int32_t pm8058_xoadc_configure(uint32_t adc_instance,
164 struct adc_conv_slot *slot)
165{
166
167 struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530168 u8 data_arb_cntrl = 0, data_amux_chan = 0, data_arb_rsv = 0;
169 u8 data_dig_param = 0, data_ana_param2 = 0, data_ana_param = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700170 int rc;
171
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700172 rc = pm8058_xoadc_arb_cntrl(1, adc_instance, slot->chan_path);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173 if (rc < 0) {
174 pr_debug("%s: Configuring ADC Arbiter"
175 "enable failed\n", __func__);
176 return rc;
177 }
178
179 switch (slot->chan_path) {
180
181 case CHAN_PATH_TYPE1:
182 data_amux_chan = CHANNEL_VCOIN << 4;
183 data_arb_rsv = 0x20;
184 slot->chan_properties.gain_numerator = 1;
185 slot->chan_properties.gain_denominator = 2;
186 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
187 break;
188
189 case CHAN_PATH_TYPE2:
190 data_amux_chan = CHANNEL_VBAT << 4;
191 data_arb_rsv = 0x20;
192 slot->chan_properties.gain_numerator = 1;
193 slot->chan_properties.gain_denominator = 3;
194 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
195 break;
196
197 case CHAN_PATH_TYPE3:
198 data_amux_chan = CHANNEL_VCHG << 4;
199 data_arb_rsv = 0x20;
200 slot->chan_properties.gain_numerator = 1;
201 slot->chan_properties.gain_denominator = 10;
202 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
203 break;
204
205 case CHAN_PATH_TYPE4:
206 data_amux_chan = CHANNEL_CHG_MONITOR << 4;
207 data_arb_rsv = 0x20;
208 slot->chan_properties.gain_numerator = 1;
209 slot->chan_properties.gain_denominator = 1;
210 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
211 break;
212
213 case CHAN_PATH_TYPE5:
214 data_amux_chan = CHANNEL_VPH_PWR << 4;
215 data_arb_rsv = 0x20;
216 slot->chan_properties.gain_numerator = 1;
217 slot->chan_properties.gain_denominator = 3;
218 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
219 break;
220
221 case CHAN_PATH_TYPE6:
222 data_amux_chan = CHANNEL_MPP5 << 4;
223 data_arb_rsv = 0x20;
224 slot->chan_properties.gain_numerator = 1;
225 slot->chan_properties.gain_denominator = 1;
Siddartha Mohanadoss8d8df132011-10-21 10:55:26 -0700226 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227 break;
228
229 case CHAN_PATH_TYPE7:
230 data_amux_chan = CHANNEL_MPP6 << 4;
231 data_arb_rsv = 0x20;
232 slot->chan_properties.gain_numerator = 1;
233 slot->chan_properties.gain_denominator = 1;
234 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
235 break;
236
237 case CHAN_PATH_TYPE8:
238 data_amux_chan = CHANNEL_MPP7 << 4;
239 data_arb_rsv = 0x20;
240 slot->chan_properties.gain_numerator = 1;
241 slot->chan_properties.gain_denominator = 2;
242 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
243 break;
244
245 case CHAN_PATH_TYPE9:
246 data_amux_chan = CHANNEL_MPP8 << 4;
247 data_arb_rsv = 0x20;
248 slot->chan_properties.gain_numerator = 1;
249 slot->chan_properties.gain_denominator = 2;
250 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
251 break;
252
253 case CHAN_PATH_TYPE10:
254 data_amux_chan = CHANNEL_MPP9 << 4;
255 data_arb_rsv = 0x20;
256 slot->chan_properties.gain_numerator = 1;
257 slot->chan_properties.gain_denominator = 3;
258 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
259 break;
260
261 case CHAN_PATH_TYPE11:
262 data_amux_chan = CHANNEL_USB_VBUS << 4;
263 data_arb_rsv = 0x20;
264 slot->chan_properties.gain_numerator = 1;
265 slot->chan_properties.gain_denominator = 3;
266 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
267 break;
268
269 case CHAN_PATH_TYPE12:
270 data_amux_chan = CHANNEL_DIE_TEMP << 4;
271 data_arb_rsv = 0x20;
272 slot->chan_properties.gain_numerator = 1;
273 slot->chan_properties.gain_denominator = 1;
274 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
275 break;
276
277 case CHAN_PATH_TYPE13:
278 data_amux_chan = CHANNEL_125V << 4;
279 data_arb_rsv = 0x20;
280 slot->chan_properties.gain_numerator = 1;
281 slot->chan_properties.gain_denominator = 1;
282 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
283 break;
284
285 case CHAN_PATH_TYPE14:
286 data_amux_chan = CHANNEL_INTERNAL_2 << 4;
287 data_arb_rsv = 0x20;
288 slot->chan_properties.gain_numerator = 1;
289 slot->chan_properties.gain_denominator = 1;
290 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
291 break;
292
293 case CHAN_PATH_TYPE_NONE:
294 data_amux_chan = CHANNEL_MUXOFF << 4;
295 data_arb_rsv = 0x10;
296 slot->chan_properties.gain_numerator = 1;
297 slot->chan_properties.gain_denominator = 1;
298 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[1];
299 break;
300
301 case CHAN_PATH_TYPE15:
302 data_amux_chan = CHANNEL_INTERNAL << 4;
303 data_arb_rsv = 0x20;
304 slot->chan_properties.gain_numerator = 1;
305 slot->chan_properties.gain_denominator = 1;
306 slot->chan_properties.adc_graph = &adc_pmic->adc_graph[0];
307 break;
308 }
309
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530310 rc = pm8xxx_writeb(adc_pmic->dev->parent,
311 ADC_ARB_USRP_AMUX_CNTRL, data_amux_chan);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312 if (rc < 0) {
313 pr_debug("%s: PM8058 write failed\n", __func__);
314 return rc;
315 }
316
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530317 rc = pm8xxx_writeb(adc_pmic->dev->parent,
318 ADC_ARB_USRP_RSV, data_arb_rsv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 if (rc < 0) {
320 pr_debug("%s: PM8058 write failed\n", __func__);
321 return rc;
322 }
323
324 /* Set default clock rate to 2.4 MHz XO ADC clock digital */
325 switch (slot->chan_adc_config) {
326
327 case ADC_CONFIG_TYPE1:
328 data_ana_param = 0xFE;
329 data_dig_param = 0x23;
330 data_ana_param2 = 0xFF;
331 /* AMUX register data to start the ADC conversion */
332 data_arb_cntrl = 0xF1;
333 break;
334
335 case ADC_CONFIG_TYPE2:
336 data_ana_param = 0xFE;
337 data_dig_param = 0x03;
338 data_ana_param2 = 0xFF;
339 /* AMUX register data to start the ADC conversion */
340 data_arb_cntrl = 0xF1;
341 break;
342 }
343
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530344 rc = pm8xxx_writeb(adc_pmic->dev->parent,
345 ADC_ARB_USRP_ANA_PARAM, data_ana_param);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 if (rc < 0) {
347 pr_debug("%s: PM8058 write failed\n", __func__);
348 return rc;
349 }
350
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530351 rc = pm8xxx_writeb(adc_pmic->dev->parent,
352 ADC_ARB_USRP_DIG_PARAM, data_dig_param);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 if (rc < 0) {
354 pr_debug("%s: PM8058 write failed\n", __func__);
355 return rc;
356 }
357
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530358 rc = pm8xxx_writeb(adc_pmic->dev->parent,
359 ADC_ARB_USRP_ANA_PARAM, data_ana_param2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360 if (rc < 0) {
361 pr_debug("%s: PM8058 write failed\n", __func__);
362 return rc;
363 }
364
365 enable_irq(adc_pmic->adc_irq);
366
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530367 rc = pm8xxx_writeb(adc_pmic->dev->parent,
368 ADC_ARB_USRP_CNTRL, data_arb_cntrl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369 if (rc < 0) {
370 pr_debug("%s: PM8058 write failed\n", __func__);
371 return rc;
372 }
373
374 return 0;
375}
376
377int32_t pm8058_xoadc_select_chan_and_start_conv(uint32_t adc_instance,
378 struct adc_conv_slot *slot)
379{
380 struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
381 struct xoadc_conv_state *slot_state = adc_pmic->conv_queue_list;
382
383 if (!xoadc_initialized)
384 return -ENODEV;
385
386 mutex_lock(&slot_state->list_lock);
387 list_add_tail(&slot->list, &slot_state->slots);
388 if (adc_pmic->xoadc_queue_count == 0) {
389 if (adc_pmic->pdata->xoadc_vreg_set != NULL)
390 adc_pmic->pdata->xoadc_vreg_set(1);
391 pm8058_xoadc_configure(adc_instance, slot);
392 }
393 adc_pmic->xoadc_queue_count++;
394 mutex_unlock(&slot_state->list_lock);
395
396 return 0;
397}
398EXPORT_SYMBOL(pm8058_xoadc_select_chan_and_start_conv);
399
400static int32_t pm8058_xoadc_dequeue_slot_request(uint32_t adc_instance,
401 struct adc_conv_slot **slot)
402{
403 struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
404 struct xoadc_conv_state *slot_state = adc_pmic->conv_queue_list;
405 int rc = 0;
406
407 mutex_lock(&slot_state->list_lock);
408 if (adc_pmic->xoadc_queue_count > 0 &&
409 !list_empty(&slot_state->slots)) {
410 *slot = list_first_entry(&slot_state->slots,
411 struct adc_conv_slot, list);
412 list_del(&(*slot)->list);
413 } else
414 rc = -EINVAL;
415 mutex_unlock(&slot_state->list_lock);
416
417 if (rc < 0) {
418 if (pm8058_xoadc_can_print())
419 pr_err("Pmic 8058 xoadc spurious interrupt detected\n");
420 return rc;
421 }
422
423 return 0;
424}
425
426int32_t pm8058_xoadc_read_adc_code(uint32_t adc_instance, int32_t *data)
427{
428 struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
429 struct xoadc_conv_state *slot_state = adc_pmic->conv_queue_list;
430 uint8_t rslt_lsb, rslt_msb;
431 struct adc_conv_slot *slot;
432 int32_t rc, max_ideal_adc_code = 1 << adc_pmic->adc_prop->bitresolution;
433
434 if (!xoadc_initialized)
435 return -ENODEV;
436
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530437 rc = pm8xxx_readb(adc_pmic->dev->parent, ADC_ARB_USRP_DATA0,
438 &rslt_lsb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439 if (rc < 0) {
440 pr_debug("%s: PM8058 read failed\n", __func__);
441 return rc;
442 }
443
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530444 rc = pm8xxx_readb(adc_pmic->dev->parent, ADC_ARB_USRP_DATA1,
445 &rslt_msb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700446 if (rc < 0) {
447 pr_debug("%s: PM8058 read failed\n", __func__);
448 return rc;
449 }
450
451 *data = (rslt_msb << 8) | rslt_lsb;
452
453 /* Use the midpoint to determine underflow or overflow */
454 if (*data > max_ideal_adc_code + (max_ideal_adc_code >> 1))
455 *data |= ((1 << (8 * sizeof(*data) -
456 adc_pmic->adc_prop->bitresolution)) - 1) <<
457 adc_pmic->adc_prop->bitresolution;
458 /* Return if this is a calibration run since there
459 * is no need to check requests in the waiting queue */
460 if (xoadc_calib_first_adc)
461 return 0;
462
463 mutex_lock(&slot_state->list_lock);
464 adc_pmic->xoadc_queue_count--;
465 if (adc_pmic->xoadc_queue_count > 0) {
466 slot = list_first_entry(&slot_state->slots,
467 struct adc_conv_slot, list);
468 pm8058_xoadc_configure(adc_instance, slot);
469 }
470 mutex_unlock(&slot_state->list_lock);
471
472 mutex_lock(&slot_state->list_lock);
473 /* Default value for switching off the arbiter after reading
474 the ADC value. Bit 0 set to 0. */
475 if (adc_pmic->xoadc_queue_count == 0) {
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700476 rc = pm8058_xoadc_arb_cntrl(0, adc_instance, CHANNEL_MUXOFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 if (rc < 0) {
478 pr_debug("%s: Configuring ADC Arbiter disable"
479 "failed\n", __func__);
480 return rc;
481 }
482 if (adc_pmic->pdata->xoadc_vreg_set != NULL)
483 adc_pmic->pdata->xoadc_vreg_set(0);
484 }
485 mutex_unlock(&slot_state->list_lock);
486
487 return 0;
488}
489EXPORT_SYMBOL(pm8058_xoadc_read_adc_code);
490
491static irqreturn_t pm8058_xoadc(int irq, void *dev_id)
492{
493 struct pmic8058_adc *xoadc_8058 = dev_id;
494 struct adc_conv_slot *slot = NULL;
495 int rc;
496
497 disable_irq_nosync(xoadc_8058->adc_irq);
498
499 if (xoadc_calib_first_adc)
500 return IRQ_HANDLED;
501
502 rc = pm8058_xoadc_dequeue_slot_request(xoadc_8058->xoadc_num, &slot);
503
504 if (rc < 0)
505 return IRQ_NONE;
506
507 if (rc == 0)
508 msm_adc_conv_cb(slot, 0, NULL, 0);
509
510 return IRQ_HANDLED;
511}
512
513struct adc_properties *pm8058_xoadc_get_properties(uint32_t dev_instance)
514{
515 struct pmic8058_adc *xoadc_8058 = pmic_adc[dev_instance];
516
517 return xoadc_8058->adc_prop;
518}
519EXPORT_SYMBOL(pm8058_xoadc_get_properties);
520
521int32_t pm8058_xoadc_calib_device(uint32_t adc_instance)
522{
523 struct pmic8058_adc *adc_pmic = pmic_adc[adc_instance];
524 struct adc_conv_slot *slot;
525 int rc, offset_xoadc, slope_xoadc, calib_read_1, calib_read_2;
526
527 if (adc_pmic->pdata->xoadc_vreg_set != NULL)
528 adc_pmic->pdata->xoadc_vreg_set(1);
529
530 pm8058_xoadc_slot_request(adc_instance, &slot);
531 if (slot) {
532 slot->chan_path = CHAN_PATH_TYPE13;
533 slot->chan_adc_config = ADC_CONFIG_TYPE2;
534 slot->chan_adc_calib = ADC_CONFIG_TYPE2;
535 xoadc_calib_first_adc = true;
536 rc = pm8058_xoadc_configure(adc_instance, slot);
537 if (rc) {
538 pr_err("pm8058_xoadc configure failed\n");
539 goto fail;
540 }
541 } else {
542 rc = -EINVAL;
543 goto fail;
544 }
545
546 msleep(3);
547
548 rc = pm8058_xoadc_read_adc_code(adc_instance, &calib_read_1);
549 if (rc) {
550 pr_err("pm8058_xoadc read adc failed\n");
551 xoadc_calib_first_adc = false;
552 goto fail;
553 }
554 xoadc_calib_first_adc = false;
555
556 pm8058_xoadc_slot_request(adc_instance, &slot);
557 if (slot) {
558 slot->chan_path = CHAN_PATH_TYPE15;
559 slot->chan_adc_config = ADC_CONFIG_TYPE2;
560 slot->chan_adc_calib = ADC_CONFIG_TYPE2;
561 xoadc_calib_first_adc = true;
562 rc = pm8058_xoadc_configure(adc_instance, slot);
563 if (rc) {
564 pr_err("pm8058_xoadc configure failed\n");
565 goto fail;
566 }
567 } else {
568 rc = -EINVAL;
569 goto fail;
570 }
571
572 msleep(3);
573
574 rc = pm8058_xoadc_read_adc_code(adc_instance, &calib_read_2);
575 if (rc) {
576 pr_err("pm8058_xoadc read adc failed\n");
577 xoadc_calib_first_adc = false;
578 goto fail;
579 }
580 xoadc_calib_first_adc = false;
581
582 pm8058_xoadc_restore_slot(adc_instance, slot);
583
584 slope_xoadc = (((calib_read_1 - calib_read_2) << 10)/
585 CHANNEL_ADC_625_MV);
586 offset_xoadc = calib_read_2 -
587 ((slope_xoadc * CHANNEL_ADC_625_MV) >> 10);
588
589 printk(KERN_INFO"pmic8058_xoadc:The offset for AMUX calibration"
590 "was %d\n", offset_xoadc);
591
592 adc_pmic->adc_graph[0].offset = offset_xoadc;
593 adc_pmic->adc_graph[0].dy = (calib_read_1 - calib_read_2);
594 adc_pmic->adc_graph[0].dx = CHANNEL_ADC_625_MV;
595
596 /* Retain ideal calibration settings for therm readings */
597 adc_pmic->adc_graph[1].offset = 0 ;
598 adc_pmic->adc_graph[1].dy = (1 << 15) - 1;
599 adc_pmic->adc_graph[1].dx = 2200;
600
601 if (adc_pmic->pdata->xoadc_vreg_set != NULL)
602 adc_pmic->pdata->xoadc_vreg_set(0);
603
604 return 0;
605fail:
606 if (adc_pmic->pdata->xoadc_vreg_set != NULL)
607 adc_pmic->pdata->xoadc_vreg_set(0);
608
609 return rc;
610}
611EXPORT_SYMBOL(pm8058_xoadc_calib_device);
612
613int32_t pm8058_xoadc_calibrate(uint32_t dev_instance,
614 struct adc_conv_slot *slot, int *calib_status)
615{
616 *calib_status = CALIB_NOT_REQUIRED;
617
618 return 0;
619}
620EXPORT_SYMBOL(pm8058_xoadc_calibrate);
621
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700622#ifdef CONFIG_PM
623static int pm8058_xoadc_suspend_noirq(struct device *dev)
624{
625 struct platform_device *pdev = to_platform_device(dev);
626 struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
627
628 adc_pmic->msm_suspend_check = 1;
629
630 return 0;
631}
632
633static int pm8058_xoadc_resume_noirq(struct device *dev)
634{
635 struct platform_device *pdev = to_platform_device(dev);
636 struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
637
638 adc_pmic->msm_suspend_check = 0;
639
640 return 0;
641}
642
643static const struct dev_pm_ops pm8058_xoadc_dev_pm_ops = {
644 .suspend_noirq = pm8058_xoadc_suspend_noirq,
645 .resume_noirq = pm8058_xoadc_resume_noirq,
646};
647
648#define PM8058_XOADC_DEV_PM_OPS (&pm8058_xoadc_dev_pm_ops)
649#else
650#define PM8058_XOADC_DEV_PM_OPS NULL
651#endif
652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700653static int __devinit pm8058_xoadc_probe(struct platform_device *pdev)
654{
655 struct xoadc_platform_data *pdata = pdev->dev.platform_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656 struct pmic8058_adc *adc_pmic;
657 int i, rc = 0;
658
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 if (!pdata) {
660 dev_err(&pdev->dev, "no platform data?\n");
661 return -EINVAL;
662 }
663
Stephen Boydde2e4662012-02-22 00:35:58 -0800664 adc_pmic = devm_kzalloc(&pdev->dev, sizeof(*adc_pmic), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 if (!adc_pmic) {
666 dev_err(&pdev->dev, "Unable to allocate memory\n");
667 return -ENOMEM;
668 }
669
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530670 adc_pmic->dev = &pdev->dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 adc_pmic->adc_prop = pdata->xoadc_prop;
672 adc_pmic->xoadc_num = pdata->xoadc_num;
673 adc_pmic->xoadc_queue_count = 0;
674
675 platform_set_drvdata(pdev, adc_pmic);
676
677 if (adc_pmic->xoadc_num > XOADC_PMIC_0) {
678 dev_err(&pdev->dev, "ADC device not supported\n");
Stephen Boydde2e4662012-02-22 00:35:58 -0800679 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700680 }
681
682 adc_pmic->pdata = pdata;
Stephen Boydde2e4662012-02-22 00:35:58 -0800683 adc_pmic->adc_graph = devm_kzalloc(&pdev->dev,
684 sizeof(struct linear_graph) * MAX_CHANNEL_PROPERTIES_QUEUE,
685 GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686 if (!adc_pmic->adc_graph) {
687 dev_err(&pdev->dev, "Unable to allocate memory\n");
Stephen Boydde2e4662012-02-22 00:35:58 -0800688 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689 }
690
691 /* Will be replaced by individual channel calibration */
692 for (i = 0; i < MAX_CHANNEL_PROPERTIES_QUEUE; i++) {
693 adc_pmic->adc_graph[i].offset = 0 ;
694 adc_pmic->adc_graph[i].dy = (1 << 15) - 1;
695 adc_pmic->adc_graph[i].dx = 2200;
696 }
697
698 if (pdata->xoadc_mpp_config != NULL)
699 pdata->xoadc_mpp_config();
700
701 adc_pmic->conv_slot_request = &adc_pmic->conv[0];
702 adc_pmic->conv_slot_request->context =
703 &adc_pmic->conv_queue_elements[0];
704
705 mutex_init(&adc_pmic->conv_slot_request->list_lock);
706 INIT_LIST_HEAD(&adc_pmic->conv_slot_request->slots);
707
708 /* tie each slot and initwork them */
709 for (i = 0; i < MAX_QUEUE_LENGTH; i++) {
710 list_add(&adc_pmic->conv_slot_request->context[i].list,
711 &adc_pmic->conv_slot_request->slots);
712 INIT_WORK(&adc_pmic->conv_slot_request->context[i].work,
713 msm_adc_wq_work);
714 init_completion(&adc_pmic->conv_slot_request->context[i].comp);
715 adc_pmic->conv_slot_request->context[i].idx = i;
716 }
717
718 adc_pmic->conv_queue_list = &adc_pmic->conv[1];
719
720 mutex_init(&adc_pmic->conv_queue_list->list_lock);
721 INIT_LIST_HEAD(&adc_pmic->conv_queue_list->slots);
722
723 adc_pmic->adc_irq = platform_get_irq(pdev, 0);
Stephen Boydde2e4662012-02-22 00:35:58 -0800724 if (adc_pmic->adc_irq < 0)
725 return -ENXIO;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700726
727 rc = request_threaded_irq(adc_pmic->adc_irq,
728 NULL, pm8058_xoadc,
729 IRQF_TRIGGER_RISING, "pm8058_adc_interrupt", adc_pmic);
730 if (rc) {
731 dev_err(&pdev->dev, "failed to request adc irq\n");
Stephen Boydde2e4662012-02-22 00:35:58 -0800732 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733 }
734
735 disable_irq(adc_pmic->adc_irq);
736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700737 if (adc_pmic->adc_voter == NULL) {
738 adc_pmic->adc_voter = msm_xo_get(MSM_XO_TCXO_D1,
739 "pmic8058_xoadc");
740 if (IS_ERR(adc_pmic->adc_voter)) {
741 dev_err(&pdev->dev, "Failed to get XO vote\n");
Stephen Boydde2e4662012-02-22 00:35:58 -0800742 return PTR_ERR(adc_pmic->adc_voter);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 }
744 }
745
Stephen Boydde2e4662012-02-22 00:35:58 -0800746 device_init_wakeup(&pdev->dev, pdata->xoadc_wakeup);
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700747 wake_lock_init(&adc_pmic->adc_wakelock, WAKE_LOCK_SUSPEND,
748 "pmic8058_xoadc_wakelock");
749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 pmic_adc[adc_pmic->xoadc_num] = adc_pmic;
751
752 if (pdata->xoadc_vreg_setup != NULL)
753 pdata->xoadc_vreg_setup();
754
755 xoadc_initialized = true;
756 xoadc_calib_first_adc = false;
757
758 return 0;
Stephen Boydde2e4662012-02-22 00:35:58 -0800759}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700760
Stephen Boydde2e4662012-02-22 00:35:58 -0800761static int __devexit pm8058_xoadc_teardown(struct platform_device *pdev)
762{
763 struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764
Stephen Boydde2e4662012-02-22 00:35:58 -0800765 if (adc_pmic->pdata->xoadc_vreg_shutdown != NULL)
766 adc_pmic->pdata->xoadc_vreg_shutdown();
767
768 wake_lock_destroy(&adc_pmic->adc_wakelock);
769 msm_xo_put(adc_pmic->adc_voter);
770 device_init_wakeup(&pdev->dev, 0);
771 xoadc_initialized = false;
772
773 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700774}
775
776static struct platform_driver pm8058_xoadc_driver = {
777 .probe = pm8058_xoadc_probe,
778 .remove = __devexit_p(pm8058_xoadc_teardown),
779 .driver = {
780 .name = "pm8058-xoadc",
781 .owner = THIS_MODULE,
Siddartha Mohanadoss71128482011-10-05 15:16:10 -0700782 .pm = PM8058_XOADC_DEV_PM_OPS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783 },
784};
785
786static int __init pm8058_xoadc_init(void)
787{
788 return platform_driver_register(&pm8058_xoadc_driver);
789}
790module_init(pm8058_xoadc_init);
791
792static void __exit pm8058_xoadc_exit(void)
793{
794 platform_driver_unregister(&pm8058_xoadc_driver);
795}
796module_exit(pm8058_xoadc_exit);
797
798MODULE_ALIAS("platform:pmic8058_xoadc");
799MODULE_DESCRIPTION("PMIC8058 XOADC driver");
800MODULE_LICENSE("GPL v2");