blob: 39bfc3ada7c3c0e092e7751592e74efeee5bee46 [file] [log] [blame]
Stephen Boyd3c9bd8f2012-02-21 23:49:06 -08001/* Copyright (c) 2010-2012, Code Aurora Forum. 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/platform_device.h>
17#include <linux/err.h>
18#include <linux/hwmon.h>
19#include <linux/hwmon-sysfs.h>
20#include <linux/miscdevice.h>
21#include <linux/fs.h>
22#include <linux/sched.h>
23#include <linux/wait.h>
24#include <linux/uaccess.h>
25#include <linux/msm_adc.h>
26#include <linux/pmic8058-xoadc.h>
27#include <linux/slab.h>
28#include <linux/semaphore.h>
29
30#include <mach/dal.h>
31
32#define MSM_ADC_DRIVER_NAME "msm_adc"
33#define MSM_ADC_MAX_FNAME 15
34
35#define MSM_ADC_DALRPC_DEVICEID 0x02000067
36#define MSM_ADC_DALRPC_PORT_NAME "DAL00"
37#define MSM_ADC_DALRPC_CPU SMD_APPS_MODEM
38
39#define MSM_ADC_DALRPC_CMD_REQ_CONV 9
40#define MSM_ADC_DALRPC_CMD_INPUT_PROP 11
41
42#define MSM_ADC_DALRC_CONV_TIMEOUT (5 * HZ) /* 5 seconds */
43
44enum dal_error {
45 DAL_ERROR_INVALID_DEVICE_IDX = 1,
46 DAL_ERROR_INVALID_CHANNEL_IDX,
47 DAL_ERROR_NULL_POINTER,
48 DAL_ERROR_DEVICE_QUEUE_FULL,
49 DAL_ERROR_INVALID_PROPERTY_LENGTH,
50 DAL_ERROR_REMOTE_EVENT_POOL_FULL
51};
52
53enum dal_result_status {
54 DAL_RESULT_STATUS_INVALID,
55 DAL_RESULT_STATUS_VALID
56};
57
58struct dal_conv_state {
59 struct dal_conv_slot context[MSM_ADC_DEV_MAX_INFLIGHT];
60 struct list_head slots;
61 struct mutex list_lock;
62 struct semaphore slot_count;
63};
64
65struct adc_dev {
66 char *name;
67 uint32_t nchans;
68 struct dal_conv_state conv;
69 struct dal_translation transl;
70 struct sensor_device_attribute *sens_attr;
71 char **fnames;
72};
73
74struct msm_adc_drv {
75 /* Common to both XOADC and EPM */
76 struct platform_device *pdev;
77 struct device *hwmon;
78 struct miscdevice misc;
79 /* XOADC variables */
80 struct sensor_device_attribute *sens_attr;
81 struct workqueue_struct *wq;
82 atomic_t online;
83 atomic_t total_outst;
84 wait_queue_head_t total_outst_wait;
85
86 /* EPM variables */
87 void *dev_h;
88 struct adc_dev *devs[MSM_ADC_MAX_NUM_DEVS];
89 struct mutex prop_lock;
90 atomic_t rpc_online;
91 atomic_t rpc_total_outst;
92 wait_queue_head_t rpc_total_outst_wait;
93};
94
95static bool epm_init;
96static bool epm_fluid_enabled;
97
98/* Needed to support file_op interfaces */
99static struct msm_adc_drv *msm_adc_drv;
100
Vijayakumar Muthuvel Manickam2d2a2c52011-10-20 13:41:39 -0700101static bool conv_first_request;
102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103static ssize_t msm_adc_show_curr(struct device *dev,
104 struct device_attribute *devattr, char *buf);
105
106static int msm_rpc_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
107 uint32_t chan, struct adc_chan_result *result);
108
109static int msm_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
110 uint32_t chan, struct adc_chan_result *result);
111
112static int msm_adc_open(struct inode *inode, struct file *file)
113{
114 struct msm_client_data *client;
115 struct msm_adc_drv *msm_adc = msm_adc_drv;
116 struct platform_device *pdev = msm_adc->pdev;
117
118 client = kzalloc(sizeof(struct msm_client_data), GFP_KERNEL);
119 if (!client) {
120 dev_err(&pdev->dev, "Unable to allocate memory\n");
121 return -ENOMEM;
122 }
123
124 if (!try_module_get(THIS_MODULE)) {
125 kfree(client);
126 return -EACCES;
127 }
128
129 mutex_init(&client->lock);
130 INIT_LIST_HEAD(&client->complete_list);
131 init_waitqueue_head(&client->data_wait);
132 init_waitqueue_head(&client->outst_wait);
133
134 client->online = 1;
135
136 file->private_data = client;
137
138 return nonseekable_open(inode, file);
139}
140
141static inline void msm_adc_restore_slot(struct dal_conv_state *conv_s,
142 struct dal_conv_slot *slot)
143{
144 mutex_lock(&conv_s->list_lock);
145 list_add(&slot->list, &conv_s->slots);
146 mutex_unlock(&conv_s->list_lock);
147
148 up(&conv_s->slot_count);
149}
150
151static int no_pending_client_requests(struct msm_client_data *client)
152{
153 mutex_lock(&client->lock);
154
155 if (client->num_outstanding == 0) {
156 mutex_unlock(&client->lock);
157 return 1;
158 }
159
160 mutex_unlock(&client->lock);
161
162 return 0;
163}
164
165static int data_avail(struct msm_client_data *client, uint32_t *pending)
166{
167 uint32_t completed;
168
169 mutex_lock(&client->lock);
170 completed = client->num_complete;
171 mutex_unlock(&client->lock);
172
173 if (completed > 0) {
174 if (pending != NULL)
175 *pending = completed;
176 return 1;
177 }
178
179 return 0;
180}
181
182static int msm_adc_release(struct inode *inode, struct file *file)
183{
184 struct msm_client_data *client = file->private_data;
185 struct adc_conv_slot *slot, *tmp;
186 int rc;
187 struct msm_adc_platform_data *pdata =
188 msm_adc_drv->pdev->dev.platform_data;
189 struct msm_adc_channels *channel = pdata->channel;
190
191 module_put(THIS_MODULE);
192
193 mutex_lock(&client->lock);
194
195 /* prevent any further requests while we teardown the client */
196 client->online = 0;
197
198 mutex_unlock(&client->lock);
199
200 /*
201 * We may still have outstanding transactions in flight from this
202 * client that have not completed. Make sure they're completed
203 * before removing the client.
204 */
205 rc = wait_event_interruptible(client->outst_wait,
206 no_pending_client_requests(client));
207 if (rc) {
208 pr_err("%s: wait_event_interruptible failed rc = %d\n",
209 __func__, rc);
210 return rc;
211 }
212
213 /*
214 * All transactions have completed. Add slot resources back to the
215 * appropriate devices.
216 */
217 list_for_each_entry_safe(slot, tmp, &client->complete_list, list) {
218 slot->client = NULL;
219 list_del(&slot->list);
220 channel[slot->conv.result.chan].adc_access_fn->adc_restore_slot(
221 channel[slot->conv.result.chan].adc_dev_instance, slot);
222 }
223
224 kfree(client);
225
226 return 0;
227}
228
229static int msm_adc_translate_dal_to_hwmon(struct msm_adc_drv *msm_adc,
230 uint32_t chan,
231 struct adc_dev_spec *dest)
232{
233 struct dal_translation *transl;
234 struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
235 int i;
236
237 for (i = 0; i < pdata->num_adc; i++) {
238 transl = &msm_adc->devs[i]->transl;
239 if (chan >= transl->hwmon_start &&
240 chan <= transl->hwmon_end) {
241 dest->dal.dev_idx = transl->dal_dev_idx;
242 dest->hwmon_dev_idx = transl->hwmon_dev_idx;
243 dest->dal.chan_idx = chan - transl->hwmon_start;
244 return 0;
245 }
246 }
247 return -EINVAL;
248}
249
250static int msm_adc_translate_hwmon_to_dal(struct msm_adc_drv *msm_adc,
251 struct adc_dev_spec *source,
252 uint32_t *chan)
253{
254 struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
255 struct dal_translation *transl;
256 int i;
257
258 for (i = 0; i < pdata->num_adc; i++) {
259 transl = &msm_adc->devs[i]->transl;
260 if (source->dal.dev_idx != transl->dal_dev_idx)
261 continue;
262 *chan = transl->hwmon_start + source->dal.chan_idx;
263 return 0;
264 }
265 return -EINVAL;
266}
267
268static int msm_adc_getinputproperties(struct msm_adc_drv *msm_adc,
269 const char *lookup_name,
270 struct adc_dev_spec *result)
271{
272 struct device *dev = &msm_adc->pdev->dev;
273 int rc;
274
275 mutex_lock(&msm_adc->prop_lock);
276
277 rc = dalrpc_fcn_8(MSM_ADC_DALRPC_CMD_INPUT_PROP, msm_adc->dev_h,
278 lookup_name, strlen(lookup_name) + 1,
279 &result->dal, sizeof(struct dal_dev_spec));
280 if (rc) {
281 dev_err(dev, "DAL getprop request failed: rc = %d\n", rc);
282 mutex_unlock(&msm_adc->prop_lock);
283 return -EIO;
284 }
285
286 mutex_unlock(&msm_adc->prop_lock);
287 return rc;
288}
289
290static int msm_adc_lookup(struct msm_adc_drv *msm_adc,
291 struct msm_adc_lookup *lookup)
292{
293 struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
294 struct adc_dev_spec target;
295 int rc = 0, i = 0;
296 uint32_t len = 0;
297
298 len = strnlen(lookup->name, MSM_ADC_MAX_CHAN_STR);
299 while (i < pdata->num_chan_supported) {
300 if (strncmp(lookup->name, pdata->channel[i].name, len))
301 i++;
302 else
303 break;
304 }
305
306 if (pdata->num_chan_supported > 0 && i < pdata->num_chan_supported) {
307 lookup->chan_idx = i;
308 } else if (msm_adc->dev_h) {
309 rc = msm_adc_getinputproperties(msm_adc, lookup->name, &target);
310 if (rc) {
311 pr_err("%s: Lookup failed for %s\n", __func__,
312 lookup->name);
313 return rc;
314 }
315 rc = msm_adc_translate_hwmon_to_dal(msm_adc, &target,
316 &lookup->chan_idx);
317 if (rc)
318 pr_err("%s: Translation failed for %s\n", __func__,
319 lookup->name);
320 } else {
321 pr_err("%s: Lookup failed for %s\n", __func__, lookup->name);
322 rc = -EINVAL;
323 }
324 return rc;
325}
326
327static int msm_adc_aio_conversion(struct msm_adc_drv *msm_adc,
328 struct adc_chan_result *request,
329 struct msm_client_data *client)
330{
331 struct msm_adc_platform_data *pdata =
332 msm_adc_drv->pdev->dev.platform_data;
333 struct msm_adc_channels *channel = &pdata->channel[request->chan];
334 struct adc_conv_slot *slot;
335
336 /* we could block here, but only for a bounded time */
337 channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
338 &slot);
339
340 if (slot) {
341 atomic_inc(&msm_adc->total_outst);
342 mutex_lock(&client->lock);
343 client->num_outstanding++;
344 mutex_unlock(&client->lock);
345
346 /* indicates non blocking request to callback handler */
347 slot->blocking = 0;
348 slot->compk = NULL;/*For kernel space usage; n/a for usr space*/
349 slot->conv.result.chan = client->adc_chan = request->chan;
350 slot->client = client;
351 slot->adc_request = START_OF_CONV;
352 slot->chan_path = channel->chan_path_type;
353 slot->chan_adc_config = channel->adc_config_type;
354 slot->chan_adc_calib = channel->adc_calib_type;
355 queue_work(msm_adc->wq, &slot->work);
356 return 0;
357 }
358 return -EBUSY;
359}
360
361static int msm_adc_fluid_hw_deinit(struct msm_adc_drv *msm_adc)
362{
363 struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
364
365 if (!epm_init)
366 return -EINVAL;
367
368 if (pdata->gpio_config == APROC_CONFIG &&
369 epm_fluid_enabled && pdata->adc_fluid_disable != NULL) {
370 pdata->adc_fluid_disable();
371 epm_fluid_enabled = false;
372 }
373
374 return 0;
375}
376
377static int msm_adc_fluid_hw_init(struct msm_adc_drv *msm_adc)
378{
379 struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
380
381 if (!epm_init)
382 return -EINVAL;
383
384 if (!pdata->adc_fluid_enable)
385 return -ENODEV;
386
387 printk(KERN_DEBUG "msm_adc_fluid_hw_init: Calling adc_fluid_enable.\n");
388
389 if (pdata->gpio_config == APROC_CONFIG && !epm_fluid_enabled) {
390 pdata->adc_fluid_enable();
391 epm_fluid_enabled = true;
392 }
393
394 /* return success for now but check for errors from hw init configuration */
395 return 0;
396}
397
398static int msm_adc_poll_complete(struct msm_adc_drv *msm_adc,
399 struct msm_client_data *client, uint32_t *pending)
400{
401 int rc;
402
403 /*
404 * Don't proceed if there there's nothing queued on this client.
405 * We could deadlock otherwise in a single threaded scenario.
406 */
407 if (no_pending_client_requests(client) && !data_avail(client, pending))
408 return -EDEADLK;
409
410 rc = wait_event_interruptible(client->data_wait,
411 data_avail(client, pending));
412 if (rc)
413 return rc;
414
415 return 0;
416}
417
418static int msm_adc_read_result(struct msm_adc_drv *msm_adc,
419 struct msm_client_data *client,
420 struct adc_chan_result *result)
421{
422 struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
423 struct msm_adc_channels *channel = pdata->channel;
424 struct adc_conv_slot *slot;
425 int rc = 0;
426
427 mutex_lock(&client->lock);
428
429 slot = list_first_entry(&client->complete_list,
430 struct adc_conv_slot, list);
431 if (!slot) {
432 mutex_unlock(&client->lock);
433 return -ENOMSG;
434 }
435
436 slot->client = NULL;
437 list_del(&slot->list);
438
439 client->num_complete--;
440
441 mutex_unlock(&client->lock);
442
443 *result = slot->conv.result;
444
445 /* restore this slot to reserve */
446 channel[slot->conv.result.chan].adc_access_fn->adc_restore_slot(
447 channel[slot->conv.result.chan].adc_dev_instance, slot);
448
449 return rc;
450}
451
452static long msm_adc_ioctl(struct file *file, unsigned int cmd,
453 unsigned long arg)
454{
455 struct msm_client_data *client = file->private_data;
456 struct msm_adc_drv *msm_adc = msm_adc_drv;
457 struct platform_device *pdev = msm_adc->pdev;
458 struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
459 uint32_t block_res = 0;
460
461 int rc;
462
463 switch (cmd) {
464 case MSM_ADC_REQUEST:
465 {
466 struct adc_chan_result conv;
467
468 if (copy_from_user(&conv, (void __user *)arg,
469 sizeof(struct adc_chan_result)))
470 return -EFAULT;
471
472 if (conv.chan < pdata->num_chan_supported) {
473 rc = msm_adc_blocking_conversion(msm_adc,
474 conv.chan, &conv);
475 } else {
476 if (!msm_adc->dev_h)
477 return -EAGAIN;
478
479 rc = msm_rpc_adc_blocking_conversion(msm_adc,
480 conv.chan, &conv);
481 }
482 if (rc) {
483 dev_dbg(&pdev->dev, "BLK conversion failed\n");
484 return rc;
485 }
486
487 if (copy_to_user((void __user *)arg, &conv,
488 sizeof(struct adc_chan_result)))
489 return -EFAULT;
490 break;
491 }
492 case MSM_ADC_AIO_REQUEST_BLOCK_RES:
493 block_res = 1;
494 case MSM_ADC_AIO_REQUEST:
495 {
496 struct adc_chan_result conv;
497
498 if (copy_from_user(&conv, (void __user *)arg,
499 sizeof(struct adc_chan_result)))
500 return -EFAULT;
501
502 if (conv.chan >= pdata->num_chan_supported)
503 return -EINVAL;
504
505 rc = msm_adc_aio_conversion(msm_adc, &conv, client);
506 if (rc) {
507 dev_dbg(&pdev->dev, "AIO conversion failed\n");
508 return rc;
509 }
510 if (copy_to_user((void __user *)arg, &conv,
511 sizeof(struct adc_chan_result)))
512 return -EFAULT;
513 break;
514 }
515 case MSM_ADC_AIO_POLL:
516 {
517 uint32_t completed;
518
519 rc = msm_adc_poll_complete(msm_adc, client, &completed);
520 if (rc) {
521 dev_dbg(&pdev->dev, "poll request failed\n");
522 return rc;
523 }
524
525 if (copy_to_user((void __user *)arg, &completed,
526 sizeof(uint32_t)))
527 return -EFAULT;
528
529 break;
530 }
531 case MSM_ADC_AIO_READ:
532 {
533 struct adc_chan_result result;
534
535 rc = msm_adc_read_result(msm_adc, client, &result);
536 if (rc) {
537 dev_dbg(&pdev->dev, "read result failed\n");
538 return rc;
539 }
540
541 if (copy_to_user((void __user *)arg, &result,
542 sizeof(struct adc_chan_result)))
543 return -EFAULT;
544 break;
545 }
546 case MSM_ADC_LOOKUP:
547 {
548 struct msm_adc_lookup lookup;
549
550 if (copy_from_user(&lookup, (void __user *)arg,
551 sizeof(struct msm_adc_lookup)))
552 return -EFAULT;
553
554 rc = msm_adc_lookup(msm_adc, &lookup);
555 if (rc) {
556 dev_dbg(&pdev->dev, "No such channel: %s\n",
557 lookup.name);
558 return rc;
559 }
560
561 if (copy_to_user((void __user *)arg, &lookup,
562 sizeof(struct msm_adc_lookup)))
563 return -EFAULT;
564 break;
565 }
566 case MSM_ADC_FLUID_INIT:
567 {
568 uint32_t result;
569
570 result = msm_adc_fluid_hw_init(msm_adc);
571
572 if (copy_to_user((void __user *)arg, &result,
573 sizeof(uint32_t))) {
574 printk(KERN_ERR "MSM_ADC_FLUID_INIT: "
575 "copy_to_user returned an error.\n");
576 return -EFAULT;
577 }
578 printk(KERN_DEBUG "MSM_ADC_FLUID_INIT: Success.\n");
579 break;
580 }
581 case MSM_ADC_FLUID_DEINIT:
582 {
583 uint32_t result;
584
585 result = msm_adc_fluid_hw_deinit(msm_adc);
586
587 if (copy_to_user((void __user *)arg, &result,
588 sizeof(uint32_t)))
589 return -EFAULT;
590 break;
591 }
592 default:
593 return -EINVAL;
594 }
595
596 return 0;
597}
598
599const struct file_operations msm_adc_fops = {
600 .open = msm_adc_open,
601 .release = msm_adc_release,
602 .unlocked_ioctl = msm_adc_ioctl,
603};
604
605static ssize_t msm_adc_show_curr(struct device *dev,
606 struct device_attribute *devattr, char *buf)
607{
608 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
609 struct msm_adc_drv *msm_adc = dev_get_drvdata(dev);
610 struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
611 struct adc_chan_result result;
612 int rc;
613
614#ifdef CONFIG_PMIC8058_XOADC
615 rc = pm8058_xoadc_registered();
616 if (rc <= 0)
617 return -ENODEV;
618#endif
619 if (attr->index < pdata->num_chan_supported) {
620 rc = msm_adc_blocking_conversion(msm_adc,
621 attr->index, &result);
622 } else {
623 if (pdata->gpio_config == APROC_CONFIG && !epm_fluid_enabled
624 && pdata->adc_fluid_enable != NULL) {
625 printk(KERN_DEBUG "This is to read ADC value for "
626 "Fluid EPM and init. Do it only once.\n");
627 pdata->adc_fluid_enable();
628 epm_fluid_enabled = true;
629 }
630 rc = msm_rpc_adc_blocking_conversion(msm_adc,
631 attr->index, &result);
632 }
633 if (rc)
634 return 0;
635
636 return sprintf(buf, "Result: %lld Raw: %d\n", result.physical,
637 result.adc_code);
638}
639
640static int msm_rpc_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
641 uint32_t hwmon_chan, struct adc_chan_result *result)
642{
643 struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
644 struct dal_conv_request params;
645 struct device *dev = &msm_adc->pdev->dev;
646 struct adc_dev *adc_dev;
647 struct dal_conv_state *conv_s;
648 struct dal_conv_slot *slot;
649 struct adc_dev_spec dest;
650 int timeout, rc = 0;
651
652 if (pdata->gpio_config == APROC_CONFIG &&
653 pdata->adc_gpio_enable != NULL)
654 pdata->adc_gpio_enable(hwmon_chan-pdata->num_chan_supported);
655
656 rc = msm_adc_translate_dal_to_hwmon(msm_adc, hwmon_chan, &dest);
657 if (rc) {
658 dev_err(dev, "%s: translation from chan %u failed\n",
659 __func__, hwmon_chan);
660 if (pdata->gpio_config == APROC_CONFIG &&
661 pdata->adc_gpio_disable != NULL)
662 pdata->adc_gpio_disable(hwmon_chan
663 -pdata->num_chan_supported);
664 return -EINVAL;
665 }
666
667 adc_dev = msm_adc->devs[dest.hwmon_dev_idx];
668 conv_s = &adc_dev->conv;
669
670 down(&conv_s->slot_count);
671
672 mutex_lock(&conv_s->list_lock);
673
674 slot = list_first_entry(&conv_s->slots, struct dal_conv_slot, list);
675 list_del(&slot->list);
676 BUG_ON(!slot);
677
678 mutex_unlock(&conv_s->list_lock);
679
680 /* indicates blocking request to callback handler */
681 slot->blocking = 1;
682
683 params.target.dev_idx = dest.dal.dev_idx;
684 params.target.chan_idx = dest.dal.chan_idx;
685 params.cb_h = slot->cb_h;
686
687 rc = dalrpc_fcn_8(MSM_ADC_DALRPC_CMD_REQ_CONV, msm_adc->dev_h,
688 &params, sizeof(params), NULL, 0);
689 if (rc) {
690 dev_err(dev, "%s: Conversion for device = %u channel = %u"
691 " failed\n", __func__, params.target.dev_idx,
692 params.target.chan_idx);
693
694 rc = -EIO;
695 goto blk_conv_err;
696 }
697
698 timeout = wait_for_completion_interruptible_timeout(&slot->comp,
699 MSM_ADC_DALRC_CONV_TIMEOUT);
700 if (timeout == 0) {
701 dev_err(dev, "read for device = %u channel = %u timed out\n",
702 params.target.dev_idx, params.target.chan_idx);
703 rc = -ETIMEDOUT;
704 goto blk_conv_err;
705 } else if (timeout < 0) {
706 rc = -EINTR;
707 goto blk_conv_err;
708 }
709
710 result->physical = (int64_t)slot->result.physical;
711
712 if (slot->result.status == DAL_RESULT_STATUS_INVALID)
713 rc = -ENODATA;
714
715blk_conv_err:
716 if (pdata->gpio_config == APROC_CONFIG &&
717 pdata->adc_gpio_disable != NULL)
718 pdata->adc_gpio_disable(hwmon_chan-pdata->num_chan_supported);
719 msm_adc_restore_slot(conv_s, slot);
720
721 return rc;
722}
723
724static int msm_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
725 uint32_t hwmon_chan, struct adc_chan_result *result)
726{
727 struct adc_conv_slot *slot;
728 struct msm_adc_platform_data *pdata =
729 msm_adc_drv->pdev->dev.platform_data;
730 struct msm_adc_channels *channel = &pdata->channel[hwmon_chan];
Vijayakumar Muthuvel Manickam2d2a2c52011-10-20 13:41:39 -0700731 int ret = 0;
732
733 if (conv_first_request) {
734 ret = pm8058_xoadc_calib_device(channel->adc_dev_instance);
735 if (ret) {
736 pr_err("pmic8058 xoadc calibration failed, retry\n");
737 return ret;
738 }
739 conv_first_request = false;
740 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741
742 channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
743 &slot);
744 if (slot) {
745 slot->conv.result.chan = hwmon_chan;
746 /* indicates blocking request to callback handler */
747 slot->blocking = 1;
748 slot->adc_request = START_OF_CONV;
749 slot->chan_path = channel->chan_path_type;
750 slot->chan_adc_config = channel->adc_config_type;
751 slot->chan_adc_calib = channel->adc_calib_type;
752 queue_work(msm_adc_drv->wq, &slot->work);
753
754 wait_for_completion_interruptible(&slot->comp);
755 *result = slot->conv.result;
756 channel->adc_access_fn->adc_restore_slot(
757 channel->adc_dev_instance, slot);
758 return 0;
759 }
760 return -EBUSY;
761}
762
763int32_t adc_channel_open(uint32_t channel, void **h)
764{
765 struct msm_client_data *client;
766 struct msm_adc_drv *msm_adc = msm_adc_drv;
767 struct msm_adc_platform_data *pdata;
768 struct platform_device *pdev;
769 int i = 0;
770
771 if (!msm_adc_drv)
772 return -EFAULT;
773
774#ifdef CONFIG_PMIC8058_XOADC
775 if (pm8058_xoadc_registered() <= 0)
776 return -ENODEV;
777#endif
778 pdata = msm_adc->pdev->dev.platform_data;
779 pdev = msm_adc->pdev;
780
781 while (i < pdata->num_chan_supported) {
782 if (channel == pdata->channel[i].channel_name)
783 break;
784 else
785 i++;
786 }
787
788 if (i == pdata->num_chan_supported)
789 return -EBADF; /* unknown channel */
790
791 client = kzalloc(sizeof(struct msm_client_data), GFP_KERNEL);
792 if (!client) {
793 dev_err(&pdev->dev, "Unable to allocate memory\n");
794 return -ENOMEM;
795 }
796
797 if (!try_module_get(THIS_MODULE)) {
798 kfree(client);
799 return -EACCES;
800 }
801
802 mutex_init(&client->lock);
803 INIT_LIST_HEAD(&client->complete_list);
804 init_waitqueue_head(&client->data_wait);
805 init_waitqueue_head(&client->outst_wait);
806
807 client->online = 1;
808 client->adc_chan = i;
809 *h = (void *)client;
810 return 0;
811}
812
813int32_t adc_channel_close(void *h)
814{
815 struct msm_client_data *client = (struct msm_client_data *)h;
816
817 kfree(client);
818 return 0;
819}
820
821int32_t adc_channel_request_conv(void *h, struct completion *conv_complete_evt)
822{
823 struct msm_client_data *client = (struct msm_client_data *)h;
824 struct msm_adc_platform_data *pdata =
825 msm_adc_drv->pdev->dev.platform_data;
826 struct msm_adc_channels *channel = &pdata->channel[client->adc_chan];
827 struct adc_conv_slot *slot;
Vijayakumar Muthuvel Manickam2d2a2c52011-10-20 13:41:39 -0700828 int ret;
829
830 if (conv_first_request) {
831 ret = pm8058_xoadc_calib_device(channel->adc_dev_instance);
832 if (ret) {
833 pr_err("pmic8058 xoadc calibration failed, retry\n");
834 return ret;
835 }
836 conv_first_request = false;
837 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700838
839 channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
840 &slot);
841
842 if (slot) {
843 atomic_inc(&msm_adc_drv->total_outst);
844 mutex_lock(&client->lock);
845 client->num_outstanding++;
846 mutex_unlock(&client->lock);
847
848 slot->conv.result.chan = client->adc_chan;
849 slot->blocking = 0;
850 slot->compk = conv_complete_evt;
851 slot->client = client;
852 slot->adc_request = START_OF_CONV;
853 slot->chan_path = channel->chan_path_type;
854 slot->chan_adc_config = channel->adc_config_type;
855 slot->chan_adc_calib = channel->adc_calib_type;
856 queue_work(msm_adc_drv->wq, &slot->work);
857 return 0;
858 }
859 return -EBUSY;
860}
861
862int32_t adc_channel_read_result(void *h, struct adc_chan_result *chan_result)
863{
864 struct msm_client_data *client = (struct msm_client_data *)h;
865 struct msm_adc_platform_data *pdata =
866 msm_adc_drv->pdev->dev.platform_data;
867 struct msm_adc_channels *channel = pdata->channel;
868 struct adc_conv_slot *slot;
869 int rc = 0;
870
871 mutex_lock(&client->lock);
872
873 slot = list_first_entry(&client->complete_list,
874 struct adc_conv_slot, list);
875 if (!slot) {
876 mutex_unlock(&client->lock);
877 return -ENOMSG;
878 }
879
880 slot->client = NULL;
881 list_del(&slot->list);
882
883 client->num_complete--;
884
885 mutex_unlock(&client->lock);
886
887 *chan_result = slot->conv.result;
888
889 /* restore this slot to reserve */
890 channel[slot->conv.result.chan].adc_access_fn->adc_restore_slot(
891 channel[slot->conv.result.chan].adc_dev_instance, slot);
892
893 return rc;
894}
895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896static void msm_rpc_adc_conv_cb(void *context, u32 param,
897 void *evt_buf, u32 len)
898{
899 struct dal_adc_result *result = evt_buf;
900 struct dal_conv_slot *slot = context;
901 struct msm_adc_drv *msm_adc = msm_adc_drv;
902
903 memcpy(&slot->result, result, sizeof(slot->result));
904
905 /* for blocking requests, signal complete */
906 if (slot->blocking)
907 complete(&slot->comp);
908
909 /* for non-blocking requests, add slot to the client completed list */
910 else {
911 struct msm_client_data *client = slot->client;
912
913 mutex_lock(&client->lock);
914
915 list_add(&slot->list, &client->complete_list);
916 client->num_complete++;
917 client->num_outstanding--;
918
919 /*
920 * if the client release has been invoked and this is call
921 * corresponds to the last request, then signal release
922 * to complete.
923 */
924 if (slot->client->online == 0 && client->num_outstanding == 0)
925 wake_up_interruptible_all(&client->outst_wait);
926
927 mutex_unlock(&client->lock);
928
929 wake_up_interruptible_all(&client->data_wait);
930
931 atomic_dec(&msm_adc->total_outst);
932
933 /* verify driver remove has not been invoked */
934 if (atomic_read(&msm_adc->online) == 0 &&
935 atomic_read(&msm_adc->total_outst) == 0)
936 wake_up_interruptible_all(&msm_adc->total_outst_wait);
937 }
938}
939
940void msm_adc_conv_cb(void *context, u32 param,
941 void *evt_buf, u32 len)
942{
943 struct adc_conv_slot *slot = context;
944 struct msm_adc_drv *msm_adc = msm_adc_drv;
945
946 switch (slot->adc_request) {
947 case START_OF_CONV:
948 slot->adc_request = END_OF_CONV;
949 break;
950 case START_OF_CALIBRATION:
951 slot->adc_request = END_OF_CALIBRATION;
952 break;
953 case END_OF_CALIBRATION:
954 case END_OF_CONV:
955 break;
956 }
957 queue_work(msm_adc->wq, &slot->work);
958}
959
960static void msm_adc_teardown_device_conv(struct platform_device *pdev,
961 struct adc_dev *adc_dev)
962{
963 struct dal_conv_state *conv_s = &adc_dev->conv;
964 struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
965 struct dal_conv_slot *slot;
966 int i;
967
968 for (i = 0; i < MSM_ADC_DEV_MAX_INFLIGHT; i++) {
969 slot = &conv_s->context[i];
970 if (slot->cb_h) {
971 dalrpc_dealloc_cb(msm_adc->dev_h, slot->cb_h);
972 slot->cb_h = NULL;
973 }
974 }
975}
976
977static void msm_rpc_adc_teardown_device(struct platform_device *pdev,
978 struct adc_dev *adc_dev)
979{
980 struct dal_translation *transl = &adc_dev->transl;
981 int i, num_chans = transl->hwmon_end - transl->hwmon_start + 1;
982
983 if (adc_dev->sens_attr)
984 for (i = 0; i < num_chans; i++)
985 device_remove_file(&pdev->dev,
986 &adc_dev->sens_attr[i].dev_attr);
987
988 msm_adc_teardown_device_conv(pdev, adc_dev);
989
990 kfree(adc_dev->fnames);
991 kfree(adc_dev->sens_attr);
992 kfree(adc_dev);
993}
994
995static void msm_rpc_adc_teardown_devices(struct platform_device *pdev)
996{
997 struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
998 struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
999 int i, rc = 0;
1000
1001 for (i = 0; i < pdata->num_adc; i++) {
1002 if (msm_adc->devs[i]) {
1003 msm_rpc_adc_teardown_device(pdev, msm_adc->devs[i]);
1004 msm_adc->devs[i] = NULL;
1005 } else
1006 break;
1007 }
1008
1009 if (msm_adc->dev_h) {
1010 rc = daldevice_detach(msm_adc->dev_h);
1011 if (rc)
1012 dev_err(&pdev->dev, "Cannot detach from dal device\n");
1013 msm_adc->dev_h = NULL;
1014 }
1015
1016}
1017
1018static void msm_adc_teardown_device(struct platform_device *pdev,
1019 struct msm_adc_drv *msm_adc)
1020{
1021 struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
1022 int i, num_chans = pdata->num_chan_supported;
1023
1024 if (pdata->num_chan_supported > 0) {
1025 if (msm_adc->sens_attr)
1026 for (i = 0; i < num_chans; i++)
1027 device_remove_file(&pdev->dev,
1028 &msm_adc->sens_attr[i].dev_attr);
1029 kfree(msm_adc->sens_attr);
1030 }
1031}
1032
1033static void msm_adc_teardown(struct platform_device *pdev)
1034{
1035 struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
1036
1037 if (!msm_adc)
1038 return;
1039
1040 misc_deregister(&msm_adc->misc);
1041
1042 if (msm_adc->hwmon)
1043 hwmon_device_unregister(msm_adc->hwmon);
1044
1045 msm_rpc_adc_teardown_devices(pdev);
1046 msm_adc_teardown_device(pdev, msm_adc);
1047
1048 kfree(msm_adc);
1049 platform_set_drvdata(pdev, NULL);
1050}
1051
1052static int __devinit msm_adc_device_conv_init(struct msm_adc_drv *msm_adc,
1053 struct adc_dev *adc_dev)
1054{
1055 struct platform_device *pdev = msm_adc->pdev;
1056 struct dal_conv_state *conv_s = &adc_dev->conv;
1057 struct dal_conv_slot *slot = conv_s->context;
1058 int rc, i;
1059
1060 sema_init(&conv_s->slot_count, MSM_ADC_DEV_MAX_INFLIGHT);
1061 mutex_init(&conv_s->list_lock);
1062 INIT_LIST_HEAD(&conv_s->slots);
1063
1064 for (i = 0; i < MSM_ADC_DEV_MAX_INFLIGHT; i++) {
1065 list_add(&slot->list, &conv_s->slots);
1066 slot->cb_h = dalrpc_alloc_cb(msm_adc->dev_h,
1067 msm_rpc_adc_conv_cb, slot);
1068 if (!slot->cb_h) {
1069 dev_err(&pdev->dev, "Unable to allocate DAL callback"
1070 " for slot %d\n", i);
1071 rc = -ENOMEM;
1072 goto dal_err_cb;
1073 }
1074 init_completion(&slot->comp);
1075 slot->idx = i;
1076 slot++;
1077 }
1078
1079 return 0;
1080
1081dal_err_cb:
1082 msm_adc_teardown_device_conv(pdev, adc_dev);
1083
1084 return rc;
1085}
1086
1087static struct sensor_device_attribute msm_rpc_adc_curr_in_attr =
1088 SENSOR_ATTR(NULL, S_IRUGO, msm_adc_show_curr, NULL, 0);
1089
1090static int __devinit msm_rpc_adc_device_init_hwmon(struct platform_device *pdev,
1091 struct adc_dev *adc_dev)
1092{
1093 struct dal_translation *transl = &adc_dev->transl;
1094 int i, rc, num_chans = transl->hwmon_end - transl->hwmon_start + 1;
1095 const char prefix[] = "curr", postfix[] = "_input";
1096 char tmpbuf[5];
1097
1098 adc_dev->fnames = kzalloc(num_chans * MSM_ADC_MAX_FNAME +
1099 num_chans * sizeof(char *), GFP_KERNEL);
1100 if (!adc_dev->fnames) {
1101 dev_err(&pdev->dev, "Unable to allocate memory\n");
1102 return -ENOMEM;
1103 }
1104
1105 adc_dev->sens_attr = kzalloc(num_chans *
1106 sizeof(struct sensor_device_attribute), GFP_KERNEL);
1107 if (!adc_dev->sens_attr) {
1108 dev_err(&pdev->dev, "Unable to allocate memory\n");
1109 rc = -ENOMEM;
1110 goto hwmon_err_fnames;
1111 }
1112
1113 for (i = 0; i < num_chans; i++) {
1114 adc_dev->fnames[i] = (char *)adc_dev->fnames +
1115 i * MSM_ADC_MAX_FNAME + num_chans * sizeof(char *);
1116 strcpy(adc_dev->fnames[i], prefix);
1117 sprintf(tmpbuf, "%d", transl->hwmon_start + i);
1118 strcat(adc_dev->fnames[i], tmpbuf);
1119 strcat(adc_dev->fnames[i], postfix);
1120
1121 msm_rpc_adc_curr_in_attr.index = transl->hwmon_start + i;
1122 msm_rpc_adc_curr_in_attr.dev_attr.attr.name =
1123 adc_dev->fnames[i];
1124 memcpy(&adc_dev->sens_attr[i], &msm_rpc_adc_curr_in_attr,
1125 sizeof(msm_rpc_adc_curr_in_attr));
1126
1127 rc = device_create_file(&pdev->dev,
1128 &adc_dev->sens_attr[i].dev_attr);
1129 if (rc) {
1130 dev_err(&pdev->dev, "device_create_file failed for "
1131 "dal dev %u chan %d\n",
1132 adc_dev->transl.dal_dev_idx, i);
1133 goto hwmon_err_sens;
1134 }
1135 }
1136
1137 return 0;
1138
1139hwmon_err_sens:
1140 kfree(adc_dev->sens_attr);
1141hwmon_err_fnames:
1142 kfree(adc_dev->fnames);
1143
1144 return rc;
1145}
1146
1147static int __devinit msm_rpc_adc_device_init(struct platform_device *pdev)
1148{
1149 struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
1150 struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
1151 struct adc_dev *adc_dev;
1152 struct adc_dev_spec target;
1153 int i, rc;
1154 int hwmon_cntr = pdata->num_chan_supported;
1155
1156 for (i = 0; i < pdata->num_adc; i++) {
1157 adc_dev = kzalloc(sizeof(struct adc_dev), GFP_KERNEL);
1158 if (!adc_dev) {
1159 dev_err(&pdev->dev, "Unable to allocate memory\n");
1160 rc = -ENOMEM;
1161 goto dev_init_err;
1162 }
1163
1164 msm_adc->devs[i] = adc_dev;
1165 adc_dev->name = pdata->dev_names[i];
1166
1167 rc = msm_adc_device_conv_init(msm_adc, adc_dev);
1168 if (rc) {
1169 dev_err(&pdev->dev, "DAL device[%s] failed conv init\n",
1170 adc_dev->name);
1171 goto dev_init_err;
1172 }
1173
1174 /* DAL device lookup */
1175 rc = msm_adc_getinputproperties(msm_adc, adc_dev->name,
1176 &target);
1177 if (rc) {
1178 dev_err(&pdev->dev, "No such DAL device[%s]\n",
1179 adc_dev->name);
1180 goto dev_init_err;
1181 }
1182
1183 adc_dev->transl.dal_dev_idx = target.dal.dev_idx;
1184 adc_dev->transl.hwmon_dev_idx = i;
1185 adc_dev->nchans = target.dal.chan_idx;
1186 adc_dev->transl.hwmon_start = hwmon_cntr;
1187 adc_dev->transl.hwmon_end = hwmon_cntr + adc_dev->nchans - 1;
1188 hwmon_cntr += adc_dev->nchans;
1189
1190 rc = msm_rpc_adc_device_init_hwmon(pdev, adc_dev);
1191 if (rc)
1192 goto dev_init_err;
1193 }
1194
1195 return 0;
1196
1197dev_init_err:
1198 msm_rpc_adc_teardown_devices(pdev);
1199 return rc;
1200}
1201
1202static int __devinit msm_rpc_adc_init(struct platform_device *pdev1)
1203{
1204 struct msm_adc_drv *msm_adc = msm_adc_drv;
1205 struct platform_device *pdev = msm_adc->pdev;
1206 struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
1207 int rc = 0;
1208
1209 dev_dbg(&pdev->dev, "msm_rpc_adc_init called\n");
1210
1211 if (!pdata) {
1212 dev_err(&pdev->dev, "no platform data?\n");
1213 return -EINVAL;
1214 }
1215
1216 mutex_init(&msm_adc->prop_lock);
1217
1218 rc = daldevice_attach(MSM_ADC_DALRPC_DEVICEID,
1219 MSM_ADC_DALRPC_PORT_NAME,
1220 MSM_ADC_DALRPC_CPU,
1221 &msm_adc->dev_h);
1222 if (rc) {
1223 dev_err(&pdev->dev, "Cannot attach to dal device\n");
1224 return rc;
1225 }
1226
1227 dev_dbg(&pdev->dev, "Attach to dal device Succeeded\n");
1228
1229 rc = msm_rpc_adc_device_init(pdev);
1230 if (rc) {
1231 dev_err(&pdev->dev, "msm_adc_dev_init failed\n");
1232 goto err_cleanup;
1233 }
1234
1235 init_waitqueue_head(&msm_adc->rpc_total_outst_wait);
1236 atomic_set(&msm_adc->rpc_online, 1);
1237 atomic_set(&msm_adc->rpc_total_outst, 0);
1238 epm_init = true;
1239 pr_info("msm_adc successfully registered\n");
1240
1241 return 0;
1242
1243err_cleanup:
1244 msm_rpc_adc_teardown_devices(pdev);
1245
1246 return rc;
1247}
1248
1249/*
1250 * Process the deferred job
1251 */
1252void msm_adc_wq_work(struct work_struct *work)
1253{
1254 struct adc_properties *adc_properties;
1255 struct adc_conv_slot *slot = container_of(work,
1256 struct adc_conv_slot, work);
1257 uint32_t idx = slot->conv.result.chan;
1258 struct msm_adc_platform_data *pdata =
1259 msm_adc_drv->pdev->dev.platform_data;
1260 struct msm_adc_channels *channel = &pdata->channel[idx];
1261 int32_t adc_code;
1262
1263 switch (slot->adc_request) {
1264 case START_OF_CONV:
1265 channel->adc_access_fn->adc_select_chan_and_start_conv(
1266 channel->adc_dev_instance, slot);
1267 break;
1268 case END_OF_CONV:
1269 adc_properties = channel->adc_access_fn->adc_get_properties(
1270 channel->adc_dev_instance);
1271 if (channel->adc_access_fn->adc_read_adc_code)
1272 channel->adc_access_fn->adc_read_adc_code(
1273 channel->adc_dev_instance, &adc_code);
1274 if (channel->chan_processor)
1275 channel->chan_processor(adc_code, adc_properties,
1276 &slot->chan_properties, &slot->conv.result);
1277 /* Intentionally a fall thru here. Calibraton does not need
1278 to perform channel processing, etc. However, both
1279 end of conversion and end of calibration requires the below
1280 fall thru code to be executed. */
1281 case END_OF_CALIBRATION:
1282 /* for blocking requests, signal complete */
1283 if (slot->blocking)
1284 complete(&slot->comp);
1285 else {
1286 struct msm_client_data *client = slot->client;
1287
1288 mutex_lock(&client->lock);
1289
1290 if (slot->adc_request == END_OF_CONV) {
1291 list_add(&slot->list, &client->complete_list);
1292 client->num_complete++;
1293 }
1294 client->num_outstanding--;
1295
1296 /*
1297 * if the client release has been invoked and this is call
1298 * corresponds to the last request, then signal release
1299 * to complete.
1300 */
1301 if (slot->client->online == 0 &&
1302 client->num_outstanding == 0)
1303 wake_up_interruptible_all(&client->outst_wait);
1304
1305 mutex_unlock(&client->lock);
1306
1307 wake_up_interruptible_all(&client->data_wait);
1308
1309 atomic_dec(&msm_adc_drv->total_outst);
1310
1311 /* verify driver remove has not been invoked */
1312 if (atomic_read(&msm_adc_drv->online) == 0 &&
1313 atomic_read(&msm_adc_drv->total_outst) == 0)
1314 wake_up_interruptible_all(
1315 &msm_adc_drv->total_outst_wait);
1316
1317 if (slot->compk) /* Kernel space request */
1318 complete(slot->compk);
1319 if (slot->adc_request == END_OF_CALIBRATION)
1320 channel->adc_access_fn->adc_restore_slot(
1321 channel->adc_dev_instance, slot);
1322 }
1323 break;
1324 case START_OF_CALIBRATION: /* code here to please code reviewers
1325 to satisfy silly compiler warnings */
1326 break;
1327 }
1328}
1329
1330static struct sensor_device_attribute msm_adc_curr_in_attr =
1331 SENSOR_ATTR(NULL, S_IRUGO, msm_adc_show_curr, NULL, 0);
1332
1333static int __devinit msm_adc_init_hwmon(struct platform_device *pdev,
1334 struct msm_adc_drv *msm_adc)
1335{
1336 struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
1337 struct msm_adc_channels *channel = pdata->channel;
1338 int i, rc, num_chans = pdata->num_chan_supported;
1339
1340 if (!channel)
1341 return -EINVAL;
1342
1343 msm_adc->sens_attr = kzalloc(num_chans *
1344 sizeof(struct sensor_device_attribute), GFP_KERNEL);
1345 if (!msm_adc->sens_attr) {
1346 dev_err(&pdev->dev, "Unable to allocate memory\n");
1347 rc = -ENOMEM;
1348 goto hwmon_err_sens;
1349 }
1350
1351 for (i = 0; i < num_chans; i++) {
1352 msm_adc_curr_in_attr.index = i;
1353 msm_adc_curr_in_attr.dev_attr.attr.name = channel[i].name;
1354 memcpy(&msm_adc->sens_attr[i], &msm_adc_curr_in_attr,
1355 sizeof(msm_adc_curr_in_attr));
1356
1357 rc = device_create_file(&pdev->dev,
1358 &msm_adc->sens_attr[i].dev_attr);
1359 if (rc) {
1360 dev_err(&pdev->dev, "device_create_file failed for "
1361 "dal dev %s\n",
1362 channel[i].name);
1363 goto hwmon_err_sens;
1364 }
1365 }
1366
1367 return 0;
1368
1369hwmon_err_sens:
1370 kfree(msm_adc->sens_attr);
1371
1372 return rc;
1373}
1374
1375static struct platform_driver msm_adc_rpcrouter_remote_driver = {
1376 .probe = msm_rpc_adc_init,
1377 .driver = {
1378 .name = MSM_ADC_DALRPC_PORT_NAME,
1379 .owner = THIS_MODULE,
1380 },
1381};
1382
Stephen Boyd3c9bd8f2012-02-21 23:49:06 -08001383static int __devinit msm_adc_probe(struct platform_device *pdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384{
1385 struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
1386 struct msm_adc_drv *msm_adc;
1387 int rc = 0;
1388
1389 if (!pdata) {
1390 dev_err(&pdev->dev, "no platform data?\n");
1391 return -EINVAL;
1392 }
1393
1394 msm_adc = kzalloc(sizeof(struct msm_adc_drv), GFP_KERNEL);
1395 if (!msm_adc) {
1396 dev_err(&pdev->dev, "Unable to allocate memory\n");
1397 return -ENOMEM;
1398 }
1399
1400 platform_set_drvdata(pdev, msm_adc);
1401 msm_adc_drv = msm_adc;
1402 msm_adc->pdev = pdev;
1403
1404 if (pdata->target_hw == MSM_8x60 || pdata->target_hw == FSM_9xxx) {
1405 rc = msm_adc_init_hwmon(pdev, msm_adc);
1406 if (rc) {
1407 dev_err(&pdev->dev, "msm_adc_dev_init failed\n");
1408 goto err_cleanup;
1409 }
1410 }
1411
1412 msm_adc->hwmon = hwmon_device_register(&pdev->dev);
1413 if (IS_ERR(msm_adc->hwmon)) {
1414 dev_err(&pdev->dev, "hwmon_device_register failed\n");
1415 rc = PTR_ERR(msm_adc->hwmon);
1416 goto err_cleanup;
1417 }
1418
1419 msm_adc->misc.name = MSM_ADC_DRIVER_NAME;
1420 msm_adc->misc.minor = MISC_DYNAMIC_MINOR;
1421 msm_adc->misc.fops = &msm_adc_fops;
1422
1423 if (misc_register(&msm_adc->misc)) {
1424 dev_err(&pdev->dev, "Unable to register misc device!\n");
1425 goto err_cleanup;
1426 }
1427
1428 init_waitqueue_head(&msm_adc->total_outst_wait);
1429 atomic_set(&msm_adc->online, 1);
1430 atomic_set(&msm_adc->total_outst, 0);
1431
1432 msm_adc->wq = create_singlethread_workqueue("msm_adc");
1433 if (!msm_adc->wq)
1434 goto err_cleanup;
1435
1436 if (pdata->num_adc > 0) {
1437 if (pdata->target_hw == MSM_8x60)
1438 platform_driver_register(
1439 &msm_adc_rpcrouter_remote_driver);
1440 else
1441 msm_rpc_adc_init(pdev);
1442 }
Vijayakumar Muthuvel Manickam2d2a2c52011-10-20 13:41:39 -07001443 conv_first_request = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444
1445 pr_info("msm_adc successfully registered\n");
1446
1447 return 0;
1448
1449err_cleanup:
1450 msm_adc_teardown(pdev);
1451
1452 return rc;
1453}
1454
1455static int __devexit msm_adc_remove(struct platform_device *pdev)
1456{
1457 int rc;
1458
1459 struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
1460
1461 atomic_set(&msm_adc->online, 0);
1462
1463 atomic_set(&msm_adc->rpc_online, 0);
1464
1465 misc_deregister(&msm_adc->misc);
1466
1467 hwmon_device_unregister(msm_adc->hwmon);
1468 msm_adc->hwmon = NULL;
1469
1470 /*
1471 * We may still have outstanding transactions in flight that have not
1472 * completed. Make sure they're completed before tearing down.
1473 */
1474 rc = wait_event_interruptible(msm_adc->total_outst_wait,
1475 atomic_read(&msm_adc->total_outst) == 0);
1476 if (rc) {
1477 pr_err("%s: wait_event_interruptible failed rc = %d\n",
1478 __func__, rc);
1479 return rc;
1480 }
1481
1482 rc = wait_event_interruptible(msm_adc->rpc_total_outst_wait,
1483 atomic_read(&msm_adc->rpc_total_outst) == 0);
1484 if (rc) {
1485 pr_err("%s: wait_event_interruptible failed rc = %d\n",
1486 __func__, rc);
1487 return rc;
1488 }
1489
1490 msm_adc_teardown(pdev);
1491
1492 pr_info("msm_adc unregistered\n");
1493
1494 return 0;
1495}
1496
1497static struct platform_driver msm_adc_driver = {
1498 .probe = msm_adc_probe,
1499 .remove = __devexit_p(msm_adc_remove),
1500 .driver = {
1501 .name = MSM_ADC_DRIVER_NAME,
1502 .owner = THIS_MODULE,
1503 },
1504};
1505
1506static int __init msm_adc_init(void)
1507{
1508 return platform_driver_register(&msm_adc_driver);
1509}
1510module_init(msm_adc_init);
1511
1512static void __exit msm_adc_exit(void)
1513{
1514 platform_driver_unregister(&msm_adc_driver);
1515}
1516module_exit(msm_adc_exit);
1517
1518MODULE_DESCRIPTION("MSM ADC Driver");
1519MODULE_ALIAS("platform:msm_adc");
1520MODULE_LICENSE("GPL v2");
1521MODULE_VERSION("0.1");