PageRenderTime 112ms CodeModel.GetById 16ms app.highlight 84ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/hwmon/m_adc.c

https://bitbucket.org/cresqo/cm7-p500-kernel
C | 922 lines | 697 code | 168 blank | 57 comment | 86 complexity | 3aba6bbc092d018c612aff2d1daa9706 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  1/* Copyright (c) 2010-2011, 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 * You should have received a copy of the GNU General Public License
 13 * along with this program; if not, write to the Free Software
 14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 15 * 02110-1301, USA.
 16 */
 17
 18#include <linux/kernel.h>
 19#include <linux/init.h>
 20#include <linux/mutex.h>
 21#include <linux/platform_device.h>
 22#include <linux/err.h>
 23#include <linux/hwmon.h>
 24#include <linux/hwmon-sysfs.h>
 25#include <linux/miscdevice.h>
 26#include <linux/fs.h>
 27#include <linux/sched.h>
 28#include <linux/wait.h>
 29#include <linux/uaccess.h>
 30#include <linux/m_adc.h>
 31#include <linux/pmic8058-xoadc.h>
 32#include <linux/slab.h>
 33
 34#define MSM_ADC_DRIVER_NAME             "msm_adc"
 35
 36struct msm_adc_drv {
 37	void				*dev_h;
 38	struct platform_device		*pdev;
 39	struct sensor_device_attribute	*sens_attr;
 40	struct workqueue_struct		*wq;
 41	struct device			*hwmon;
 42	struct miscdevice		misc;
 43	atomic_t			online;
 44	atomic_t			total_outst;
 45	wait_queue_head_t		total_outst_wait;
 46};
 47
 48/* Needed to support file_op interfaces */
 49static struct msm_adc_drv *msm_adc_drv;
 50
 51static int conv_first_request;
 52
 53static ssize_t msm_adc_show_curr(struct device *dev,
 54				struct device_attribute *devattr, char *buf);
 55
 56static int msm_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
 57				uint32_t chan, struct adc_chan_result *result);
 58
 59static int msm_adc_open(struct inode *inode, struct file *file)
 60{
 61	struct msm_client_data *client;
 62	struct msm_adc_drv *msm_adc = msm_adc_drv;
 63	struct platform_device *pdev = msm_adc->pdev;
 64
 65	client = kzalloc(sizeof(struct msm_client_data), GFP_KERNEL);
 66	if (!client) {
 67		dev_err(&pdev->dev, "Unable to allocate memory\n");
 68		return -ENOMEM;
 69	}
 70
 71	if (!try_module_get(THIS_MODULE)) {
 72		kfree(client);
 73		return -EACCES;
 74	}
 75
 76	mutex_init(&client->lock);
 77	INIT_LIST_HEAD(&client->complete_list);
 78	init_waitqueue_head(&client->data_wait);
 79	init_waitqueue_head(&client->outst_wait);
 80
 81	client->online = 1;
 82
 83	file->private_data = client;
 84
 85	return nonseekable_open(inode, file);
 86}
 87
 88static int no_pending_client_requests(struct msm_client_data *client)
 89{
 90	mutex_lock(&client->lock);
 91
 92	if (client->num_outstanding == 0) {
 93		mutex_unlock(&client->lock);
 94		return 1;
 95	}
 96
 97	mutex_unlock(&client->lock);
 98
 99	return 0;
100}
101
102static int data_avail(struct msm_client_data *client, uint32_t *pending)
103{
104	uint32_t completed;
105
106	mutex_lock(&client->lock);
107	completed = client->num_complete;
108	mutex_unlock(&client->lock);
109
110	if (completed > 0) {
111		if (pending != NULL)
112			*pending = completed;
113		return 1;
114	}
115
116	return 0;
117}
118
119static int msm_adc_release(struct inode *inode, struct file *file)
120{
121	struct msm_client_data *client = file->private_data;
122	struct adc_conv_slot *slot, *tmp;
123	int rc;
124	struct msm_adc_platform_data *pdata =
125					msm_adc_drv->pdev->dev.platform_data;
126	struct msm_adc_channels *channel = pdata->channel;
127
128	module_put(THIS_MODULE);
129
130	mutex_lock(&client->lock);
131
132	/* prevent any further requests while we teardown the client */
133	client->online = 0;
134
135	mutex_unlock(&client->lock);
136
137	/*
138	 * We may still have outstanding transactions in flight from this
139	 * client that have not completed. Make sure they're completed
140	 * before removing the client.
141	 */
142	rc = wait_event_interruptible(client->outst_wait,
143				      no_pending_client_requests(client));
144	if (rc) {
145		pr_err("%s: wait_event_interruptible failed rc = %d\n",
146								__func__, rc);
147		return rc;
148	}
149
150	/*
151	 * All transactions have completed. Add slot resources back to the
152	 * appropriate devices.
153	 */
154	list_for_each_entry_safe(slot, tmp, &client->complete_list, list) {
155		slot->client = NULL;
156		list_del(&slot->list);
157		channel[slot->conv.result.chan].adc_access_fn->adc_restore_slot(
158		channel[slot->conv.result.chan].adc_dev_instance, slot);
159	}
160
161	kfree(client);
162
163	return 0;
164}
165
166static int msm_adc_lookup(struct msm_adc_drv *msm_adc,
167			  struct msm_adc_lookup *lookup)
168{
169	struct platform_device *pdev = msm_adc->pdev;
170	struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
171	int rc = 0, i = 0;
172
173	do {
174		if (strcmp(lookup->name, pdata->channel[i].name))
175			i++;
176		else
177			break;
178	} while (i < pdata->num_chan_supported);
179
180	if (i == pdata->num_chan_supported)
181		rc = -EINVAL;
182
183	if (rc) {
184		dev_err(&pdev->dev, "Lookup failed for %s\n", lookup->name);
185		return rc;
186	}
187
188	lookup->chan_idx = i;
189	return rc;
190}
191
192static int msm_adc_aio_conversion(struct msm_adc_drv *msm_adc,
193				  struct adc_chan_result *request,
194				  struct msm_client_data *client)
195{
196	struct msm_adc_platform_data *pdata =
197					msm_adc_drv->pdev->dev.platform_data;
198	struct msm_adc_channels *channel = &pdata->channel[request->chan];
199	struct adc_conv_slot *slot;
200
201	/* we could block here, but only for a bounded time */
202	channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
203									&slot);
204
205	if (slot) {
206		atomic_inc(&msm_adc->total_outst);
207		mutex_lock(&client->lock);
208		client->num_outstanding++;
209		mutex_unlock(&client->lock);
210
211		/* indicates non blocking request to callback handler */
212		slot->blocking = 0;
213		slot->compk = NULL;/*For kernel space usage; n/a for usr space*/
214		slot->conv.result.chan = client->adc_chan = request->chan;
215		slot->client = client;
216		slot->adc_request = START_OF_CONV;
217		slot->chan_path = channel->chan_path_type;
218		slot->chan_adc_config = channel->adc_config_type;
219		slot->chan_adc_calib = channel->adc_calib_type;
220		queue_work(msm_adc->wq, &slot->work);
221		return 0;
222	}
223	return -EBUSY;
224}
225
226static int msm_adc_poll_complete(struct msm_adc_drv *msm_adc,
227			     struct msm_client_data *client, uint32_t *pending)
228{
229	int rc;
230
231	/*
232	 * Don't proceed if there there's nothing queued on this client.
233	 * We could deadlock otherwise in a single threaded scenario.
234	 */
235	if (no_pending_client_requests(client))
236		return -EDEADLK;
237
238	rc = wait_event_interruptible(client->data_wait,
239				data_avail(client, pending));
240	if (rc)
241		return rc;
242
243	return 0;
244}
245
246static int msm_adc_read_result(struct msm_adc_drv *msm_adc,
247			       struct msm_client_data *client,
248			       struct adc_chan_result *result)
249{
250	struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
251	struct msm_adc_channels *channel = pdata->channel;
252	struct adc_conv_slot *slot;
253	int rc = 0;
254
255	mutex_lock(&client->lock);
256
257	slot = list_first_entry(&client->complete_list,
258				struct adc_conv_slot, list);
259	if (!slot) {
260		mutex_unlock(&client->lock);
261		return -ENOMSG;
262	}
263
264	slot->client = NULL;
265	list_del(&slot->list);
266
267	client->num_complete--;
268
269	mutex_unlock(&client->lock);
270
271	*result = slot->conv.result;
272
273	/* restore this slot to reserve */
274	channel[slot->conv.result.chan].adc_access_fn->adc_restore_slot(
275		channel[slot->conv.result.chan].adc_dev_instance, slot);
276
277	return rc;
278}
279
280static long msm_adc_ioctl(struct file *file, unsigned int cmd,
281					     unsigned long arg)
282{
283	struct msm_client_data *client = file->private_data;
284	struct msm_adc_drv *msm_adc = msm_adc_drv;
285	struct platform_device *pdev = msm_adc->pdev;
286	int rc;
287
288	switch (cmd) {
289	case MSM_ADC_REQUEST:
290		{
291			struct adc_chan_result conv;
292
293			if (copy_from_user(&conv, (void __user *)arg,
294					sizeof(struct adc_chan_result)))
295				return -EFAULT;
296
297			rc = msm_adc_blocking_conversion(msm_adc, conv.chan,
298							&conv);
299			if (rc) {
300				dev_dbg(&pdev->dev, "BLK conversion failed\n");
301				return rc;
302			}
303
304			if (copy_to_user((void __user *)arg, &conv,
305					sizeof(struct adc_chan_result)))
306				return -EFAULT;
307			break;
308		}
309	case MSM_ADC_AIO_REQUEST:
310		{
311			struct adc_chan_result conv;
312
313			if (copy_from_user(&conv, (void __user *)arg,
314					sizeof(struct adc_chan_result)))
315				return -EFAULT;
316
317			rc = msm_adc_aio_conversion(msm_adc, &conv, client);
318			if (rc) {
319				dev_dbg(&pdev->dev, "AIO conversion failed\n");
320				return rc;
321			}
322			break;
323		}
324	case MSM_ADC_AIO_POLL:
325		{
326			uint32_t completed;
327
328			rc = msm_adc_poll_complete(msm_adc, client, &completed);
329			if (rc) {
330				dev_dbg(&pdev->dev, "poll request failed\n");
331				return rc;
332			}
333
334			if (copy_to_user((void __user *)arg, &completed,
335					sizeof(uint32_t)))
336				return -EFAULT;
337
338			break;
339		}
340	case MSM_ADC_AIO_READ:
341		{
342			struct adc_chan_result result;
343
344			rc = msm_adc_read_result(msm_adc, client, &result);
345			if (rc) {
346				dev_dbg(&pdev->dev, "read result failed\n");
347				return rc;
348			}
349
350			if (copy_to_user((void __user *)arg, &result,
351					sizeof(struct adc_chan_result)))
352				return -EFAULT;
353			break;
354		}
355	case MSM_ADC_LOOKUP:
356		{
357			struct msm_adc_lookup lookup;
358
359			if (copy_from_user(&lookup, (void __user *)arg,
360					sizeof(struct msm_adc_lookup)))
361				return -EFAULT;
362
363			rc = msm_adc_lookup(msm_adc, &lookup);
364			if (rc) {
365				dev_dbg(&pdev->dev, "No such channel: %s\n",
366						lookup.name);
367				return rc;
368			}
369
370			if (copy_to_user((void __user *)arg, &lookup,
371					sizeof(struct msm_adc_lookup)))
372				return -EFAULT;
373			break;
374		}
375	default:
376		return -EINVAL;
377	}
378
379	return 0;
380}
381
382const struct file_operations msm_adc_fops = {
383	.open = msm_adc_open,
384	.release = msm_adc_release,
385	.unlocked_ioctl = msm_adc_ioctl,
386};
387
388static ssize_t msm_adc_show_curr(struct device *dev,
389				 struct device_attribute *devattr, char *buf)
390{
391	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
392	struct msm_adc_drv *msm_adc = dev_get_drvdata(dev);
393	int rc;
394	struct adc_chan_result result;
395
396	rc = pm8058_xoadc_registered();
397	if (rc <= 0)
398		return -ENODEV;
399
400	rc = msm_adc_blocking_conversion(msm_adc, attr->index, &result);
401	if (rc)
402		return 0;
403
404	return sprintf(buf, "Result: %lld Raw: %d\n", result.physical,
405				result.adc_code);
406}
407
408static int msm_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
409			uint32_t hwmon_chan, struct adc_chan_result *result)
410{
411	struct adc_conv_slot *slot;
412	struct msm_adc_platform_data *pdata =
413					msm_adc_drv->pdev->dev.platform_data;
414	struct msm_adc_channels *channel = &pdata->channel[hwmon_chan];
415	int ret;
416
417	if (!conv_first_request) {
418		ret = pm8058_xoadc_calib_device(channel->adc_dev_instance);
419		if (ret) {
420			pr_err("pmic8058 xoadc calibration failed, retry\n");
421			return ret;
422		}
423		conv_first_request = 1;
424	}
425
426	channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
427									&slot);
428	if (slot) {
429		slot->conv.result.chan = hwmon_chan;
430		/* indicates blocking request to callback handler */
431		slot->blocking = 1;
432		slot->adc_request = START_OF_CONV;
433		slot->chan_path = channel->chan_path_type;
434		slot->chan_adc_config = channel->adc_config_type;
435		slot->chan_adc_calib = channel->adc_calib_type;
436		queue_work(msm_adc_drv->wq, &slot->work);
437
438		wait_for_completion_interruptible(&slot->comp);
439		*result = slot->conv.result;
440		channel->adc_access_fn->adc_restore_slot(
441					channel->adc_dev_instance, slot);
442		return 0;
443	}
444	return -EBUSY;
445}
446
447void msm_adc_conv_cb(void *context, u32 param,
448			    void *evt_buf, u32 len)
449{
450	struct adc_conv_slot *slot = context;
451	struct msm_adc_drv *msm_adc = msm_adc_drv;
452
453	switch (slot->adc_request) {
454	case START_OF_CONV:
455		slot->adc_request = END_OF_CONV;
456	break;
457	case START_OF_CALIBRATION:
458		slot->adc_request = END_OF_CALIBRATION;
459	break;
460	case END_OF_CALIBRATION:
461	case END_OF_CONV:
462	break;
463	}
464	queue_work(msm_adc->wq, &slot->work);
465}
466EXPORT_SYMBOL(msm_adc_conv_cb);
467
468static void msm_adc_teardown_device(struct platform_device *pdev,
469				    struct msm_adc_drv *msm_adc)
470{
471	struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
472	int i, num_chans = pdata->num_chan_supported;
473
474	if (msm_adc->sens_attr)
475		for (i = 0; i < num_chans; i++)
476			device_remove_file(&pdev->dev,
477					&msm_adc->sens_attr[i].dev_attr);
478
479	kfree(msm_adc->sens_attr);
480}
481
482static void msm_adc_teardown(struct platform_device *pdev)
483{
484	struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
485
486	if (!msm_adc)
487		return;
488
489	misc_deregister(&msm_adc->misc);
490
491	if (msm_adc->hwmon)
492		hwmon_device_unregister(msm_adc->hwmon);
493
494	msm_adc_teardown_device(pdev, msm_adc);
495
496	if (msm_adc->dev_h)
497		msm_adc->dev_h = NULL;
498
499	kfree(msm_adc);
500	platform_set_drvdata(pdev, NULL);
501}
502
503/*
504 * Process the deferred job
505 */
506void msm_adc_wq_work(struct work_struct *work)
507{
508	struct adc_properties *adc_properties;
509	struct adc_conv_slot *slot = container_of(work,
510						struct adc_conv_slot, work);
511	uint32_t idx = slot->conv.result.chan;
512	struct msm_adc_platform_data *pdata =
513					msm_adc_drv->pdev->dev.platform_data;
514	struct msm_adc_channels *channel = &pdata->channel[idx];
515	int32_t adc_code;
516
517	switch (slot->adc_request) {
518	case START_OF_CONV:
519			channel->adc_access_fn->adc_select_chan_and_start_conv(
520					channel->adc_dev_instance, slot);
521	break;
522	case END_OF_CONV:
523		adc_properties = channel->adc_access_fn->adc_get_properties(
524						channel->adc_dev_instance);
525		if (channel->adc_access_fn->adc_read_adc_code)
526			channel->adc_access_fn->adc_read_adc_code(
527					channel->adc_dev_instance, &adc_code);
528		if (channel->chan_processor)
529			channel->chan_processor(adc_code, adc_properties,
530				&slot->chan_properties, &slot->conv.result);
531		/* Intentionally a fall thru here.  Calibraton does not need
532		to perform channel processing, etc.  However, both
533		end of conversion and end of calibration requires the below
534		fall thru code to be executed. */
535	case END_OF_CALIBRATION:
536		/* for blocking requests, signal complete */
537		if (slot->blocking)
538			complete(&slot->comp);
539		else {
540			struct msm_client_data *client = slot->client;
541
542			mutex_lock(&client->lock);
543
544			if (slot->adc_request == END_OF_CONV) {
545				list_add(&slot->list, &client->complete_list);
546				client->num_complete++;
547			}
548			client->num_outstanding--;
549
550		/*
551		 * if the client release has been invoked and this is call
552		 * corresponds to the last request, then signal release
553		 * to complete.
554		 */
555			if (slot->client->online == 0 &&
556						client->num_outstanding == 0)
557				wake_up_interruptible_all(&client->outst_wait);
558
559			mutex_unlock(&client->lock);
560
561			wake_up_interruptible_all(&client->data_wait);
562
563			atomic_dec(&msm_adc_drv->total_outst);
564
565			/* verify driver remove has not been invoked */
566			if (atomic_read(&msm_adc_drv->online) == 0 &&
567				atomic_read(&msm_adc_drv->total_outst) == 0)
568				wake_up_interruptible_all(
569					&msm_adc_drv->total_outst_wait);
570
571			if (slot->compk) /* Kernel space request */
572				complete(slot->compk);
573			if (slot->adc_request == END_OF_CALIBRATION)
574				channel->adc_access_fn->adc_restore_slot(
575					channel->adc_dev_instance, slot);
576		}
577	break;
578	case START_OF_CALIBRATION: /* code here to please code reviewers
579					to satisfy silly compiler warnings */
580	break;
581	}
582}
583EXPORT_SYMBOL(msm_adc_wq_work);
584
585static struct sensor_device_attribute msm_adc_curr_in_attr =
586	SENSOR_ATTR(NULL, S_IRUGO, msm_adc_show_curr, NULL, 0);
587
588static int __devinit msm_adc_init_hwmon(struct platform_device *pdev,
589					       struct msm_adc_drv *msm_adc)
590{
591	struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
592	struct msm_adc_channels *channel = pdata->channel;
593	int i, rc, num_chans = pdata->num_chan_supported;
594
595	if (!channel)
596		return -EINVAL;
597
598	msm_adc->sens_attr = kzalloc(num_chans *
599			    sizeof(struct sensor_device_attribute), GFP_KERNEL);
600	if (!msm_adc->sens_attr) {
601		dev_err(&pdev->dev, "Unable to allocate memory\n");
602		rc = -ENOMEM;
603		goto hwmon_err_sens;
604	}
605
606	for (i = 0; i < num_chans; i++) {
607		msm_adc_curr_in_attr.index = i;
608		msm_adc_curr_in_attr.dev_attr.attr.name = channel[i].name;
609		memcpy(&msm_adc->sens_attr[i], &msm_adc_curr_in_attr,
610						sizeof(msm_adc_curr_in_attr));
611
612		rc = device_create_file(&pdev->dev,
613				&msm_adc->sens_attr[i].dev_attr);
614		if (rc) {
615			dev_err(&pdev->dev, "device_create_file failed for "
616					    "dal dev %s\n",
617					    channel[i].name);
618			goto hwmon_err_sens;
619		}
620	}
621
622	return 0;
623
624hwmon_err_sens:
625	kfree(msm_adc->sens_attr);
626
627	return rc;
628}
629
630static int __devinit msm_adc_probe(struct platform_device *pdev)
631{
632	struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
633	struct msm_adc_drv *msm_adc;
634	int rc = 0;
635
636	if (!pdata) {
637		dev_err(&pdev->dev, "no platform data?\n");
638		return -EINVAL;
639	}
640
641	msm_adc = kzalloc(sizeof(struct msm_adc_drv), GFP_KERNEL);
642	if (!msm_adc) {
643		dev_err(&pdev->dev, "Unable to allocate memory\n");
644		return -ENOMEM;
645	}
646
647	platform_set_drvdata(pdev, msm_adc);
648	msm_adc_drv = msm_adc;
649	msm_adc->pdev = pdev;
650
651	rc = msm_adc_init_hwmon(pdev, msm_adc);
652	if (rc) {
653		dev_err(&pdev->dev, "msm_adc_dev_init failed\n");
654		goto err_cleanup;
655	}
656
657	msm_adc->hwmon = hwmon_device_register(&pdev->dev);
658	if (IS_ERR(msm_adc->hwmon)) {
659		dev_err(&pdev->dev, "hwmon_device_register failed.\n");
660		rc = PTR_ERR(msm_adc->hwmon);
661		goto err_cleanup;
662	}
663
664	msm_adc->misc.name = MSM_ADC_DRIVER_NAME;
665	msm_adc->misc.minor = MISC_DYNAMIC_MINOR;
666	msm_adc->misc.fops = &msm_adc_fops;
667
668	if (misc_register(&msm_adc->misc)) {
669		dev_err(&pdev->dev, "Unable to register misc device!\n");
670		goto err_cleanup;
671	}
672
673	init_waitqueue_head(&msm_adc->total_outst_wait);
674	atomic_set(&msm_adc->online, 1);
675	atomic_set(&msm_adc->total_outst, 0);
676
677	msm_adc->wq = create_singlethread_workqueue("msm_adc");
678	if (!msm_adc->wq)
679		goto err_cleanup;
680
681	pr_info("msm_adc successfully registered\n");
682
683	return 0;
684
685err_cleanup:
686	msm_adc_teardown(pdev);
687
688	return rc;
689}
690
691static int __devexit msm_adc_remove(struct platform_device *pdev)
692{
693	int rc;
694
695	struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
696
697	atomic_set(&msm_adc->online, 0);
698
699	misc_deregister(&msm_adc->misc);
700
701	hwmon_device_unregister(msm_adc->hwmon);
702	msm_adc->hwmon = NULL;
703
704	/*
705	 * We may still have outstanding transactions in flight that have not
706	 * completed. Make sure they're completed before tearing down.
707	 */
708	rc = wait_event_interruptible(msm_adc->total_outst_wait,
709				      atomic_read(&msm_adc->total_outst) == 0);
710	if (rc) {
711		pr_err("%s: wait_event_interruptible failed rc = %d\n",
712								__func__, rc);
713		return rc;
714	}
715
716	msm_adc_teardown(pdev);
717
718	pr_info("msm_adc unregistered\n");
719
720	return 0;
721}
722
723static struct platform_driver msm_adc_driver = {
724	.probe = msm_adc_probe,
725	.remove = __devexit_p(msm_adc_remove),
726	.driver = {
727		.name = MSM_ADC_DRIVER_NAME,
728		.owner = THIS_MODULE,
729	},
730};
731
732static int __init msm_adc_init(void)
733{
734	return platform_driver_register(&msm_adc_driver);
735}
736module_init(msm_adc_init);
737
738static void __exit msm_adc_exit(void)
739{
740	platform_driver_unregister(&msm_adc_driver);
741}
742module_exit(msm_adc_exit);
743
744MODULE_DESCRIPTION("MSM ADC Driver");
745MODULE_ALIAS("platform:msm_adc");
746MODULE_LICENSE("GPL v2");
747MODULE_VERSION("0.1");
748
749
750int32_t adc_channel_open(uint32_t channel, void **h)
751{
752	struct msm_client_data *client;
753	struct msm_adc_drv *msm_adc = msm_adc_drv;
754	struct msm_adc_platform_data *pdata;
755	struct platform_device *pdev;
756	int i = 0, rc;
757
758	if (!msm_adc_drv)
759		return -EFAULT;
760
761	rc = pm8058_xoadc_registered();
762
763	if (rc <= 0)
764		return -ENODEV;
765
766	pdata = msm_adc->pdev->dev.platform_data;
767	pdev = msm_adc->pdev;
768
769	while (i < pdata->num_chan_supported) {
770		if (channel == pdata->channel[i].channel_name)
771			break;
772		else
773			i++;
774	}
775
776	if (i == pdata->num_chan_supported)
777		return -EBADF; /* unknown channel */
778
779	client = kzalloc(sizeof(struct msm_client_data), GFP_KERNEL);
780	if (!client) {
781		dev_err(&pdev->dev, "Unable to allocate memory\n");
782		return -ENOMEM;
783	}
784
785	if (!try_module_get(THIS_MODULE)) {
786		kfree(client);
787		return -EACCES;
788	}
789
790	mutex_init(&client->lock);
791	INIT_LIST_HEAD(&client->complete_list);
792	init_waitqueue_head(&client->data_wait);
793	init_waitqueue_head(&client->outst_wait);
794
795	client->online = 1;
796	client->adc_chan = i;
797	*h = (void *)client;
798	return 0;
799}
800
801int32_t adc_channel_close(void *h)
802{
803	struct msm_client_data *client = (struct msm_client_data *)h;
804
805	kfree(client);
806	return 0;
807}
808
809int32_t adc_channel_request_conv(void *h, struct completion *conv_complete_evt)
810{
811	struct msm_client_data *client = (struct msm_client_data *)h;
812	struct msm_adc_platform_data *pdata =
813					msm_adc_drv->pdev->dev.platform_data;
814	struct msm_adc_channels *channel = &pdata->channel[client->adc_chan];
815	struct adc_conv_slot *slot;
816	int ret;
817
818	if (!conv_first_request) {
819		ret = pm8058_xoadc_calib_device(channel->adc_dev_instance);
820		if (ret) {
821			pr_err("pm8058 xoadc calibration failed, retry\n");
822			return ret;
823		}
824		conv_first_request = 1;
825	}
826
827	channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
828									&slot);
829
830	if (slot) {
831		atomic_inc(&msm_adc_drv->total_outst);
832		mutex_lock(&client->lock);
833		client->num_outstanding++;
834		mutex_unlock(&client->lock);
835
836		slot->conv.result.chan = client->adc_chan;
837		slot->blocking = 0;
838		slot->compk = conv_complete_evt;
839		slot->client = client;
840		slot->adc_request = START_OF_CONV;
841		slot->chan_path = channel->chan_path_type;
842		slot->chan_adc_config = channel->adc_config_type;
843		slot->chan_adc_calib = channel->adc_calib_type;
844		queue_work(msm_adc_drv->wq, &slot->work);
845		return 0;
846	}
847	return -EBUSY;
848}
849
850int32_t adc_channel_read_result(void *h, struct adc_chan_result *chan_result)
851{
852	struct msm_client_data *client = (struct msm_client_data *)h;
853	struct msm_adc_platform_data *pdata =
854					msm_adc_drv->pdev->dev.platform_data;
855	struct msm_adc_channels *channel = pdata->channel;
856	struct adc_conv_slot *slot;
857	int rc = 0;
858
859	mutex_lock(&client->lock);
860
861	slot = list_first_entry(&client->complete_list,
862				struct adc_conv_slot, list);
863	if (!slot) {
864		mutex_unlock(&client->lock);
865		return -ENOMSG;
866	}
867
868	slot->client = NULL;
869	list_del(&slot->list);
870
871	client->num_complete--;
872
873	mutex_unlock(&client->lock);
874
875	*chan_result = slot->conv.result;
876
877	/* restore this slot to reserve */
878	channel[slot->conv.result.chan].adc_access_fn->adc_restore_slot(
879		channel[slot->conv.result.chan].adc_dev_instance, slot);
880
881	return rc;
882}
883
884int32_t adc_calib_request(void *h, struct completion *calib_complete_evt)
885{
886	struct msm_client_data *client = (struct msm_client_data *)h;
887	struct msm_adc_platform_data *pdata =
888					msm_adc_drv->pdev->dev.platform_data;
889	struct msm_adc_channels *channel = &pdata->channel[client->adc_chan];
890	struct adc_conv_slot *slot;
891	int rc, calib_status;
892
893	channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
894									&slot);
895	if (slot) {
896		slot->conv.result.chan = client->adc_chan;
897		slot->blocking = 0;
898		slot->compk = calib_complete_evt;
899		slot->adc_request = START_OF_CALIBRATION;
900		slot->chan_path = channel->chan_path_type;
901		slot->chan_adc_config = channel->adc_config_type;
902		slot->chan_adc_calib = channel->adc_calib_type;
903		rc = channel->adc_access_fn->adc_calibrate(
904			channel->adc_dev_instance, slot, &calib_status);
905
906		if (calib_status == CALIB_NOT_REQUIRED) {
907			channel->adc_access_fn->adc_restore_slot(
908					channel->adc_dev_instance, slot);
909			/* client will always wait in case when
910				calibration is not required */
911			complete(calib_complete_evt);
912		} else {
913			atomic_inc(&msm_adc_drv->total_outst);
914			mutex_lock(&client->lock);
915			client->num_outstanding++;
916			mutex_unlock(&client->lock);
917		}
918
919		return rc;
920	}
921	return -EBUSY;
922}