adc驱动

一、函数解析

1、读取选定通道的ADC的值

static inline int exynos_adc_read_ch(void) {
	int ret;
    /*上锁*/
	ret = mutex_lock_interruptible(&adcdev.lock);
	if (ret < 0)
		return ret;
    /*读取指定通道的值*/
	ret = s3c_adc_read(adcdev.client, adcdev.channel);
    /*解锁*/
	mutex_unlock(&adcdev.lock);

	return ret;
}

2、选择ADC通道

static inline void exynos_adc_set_channel(int channel) {
    /*如果通道在0-4之间,就出错*/
	if (channel < 0 || channel > 3)
		return;

	adcdev.channel = channel;
}

3、读取ADC的值

static ssize_t exynos_adc_read(struct file *filp, char *buffer,
		size_t count, loff_t *ppos)
{
	char str[20];
	int value;
	size_t len;
    /*读取通道上的值*/
	value = exynos_adc_read_ch();

	len = sprintf(str, "%d\n", value);
	if (count >= len) {
		int r = copy_to_user(buffer, str, len);
		return r ? r : len;
	} else {
		return -EINVAL;
	}
}

4、ioctl函数

static long exynos_adc_ioctl(struct file *file,
		unsigned int cmd, unsigned long arg)
{
#define ADC_SET_CHANNEL		0xc000fa01
#define ADC_SET_ADCTSC		0xc000fa02

	switch (cmd) {
		case ADC_SET_CHANNEL:
            /*设置ADC的转换通道*/
			exynos_adc_set_channel(arg);
			break;
		case ADC_SET_ADCTSC:
			/* do nothing */
			break;
		default:
			return -EINVAL;
	}

	return 0;
}

5、打开设备

static int exynos_adc_open(struct inode *inode, struct file *filp)
{
    /*设置ADC的转换通道0*/
	exynos_adc_set_channel(0);

	DPRINTK("adc opened\n");
	return 0;
}

6、释放ADC设备

/*关闭ADC设备*/
static int exynos_adc_release(struct inode *inode, struct file *filp)
{
	DPRINTK("adc closed\n");
	return 0;
}

7、匹配函数

static int __devinit exynos_adc_probe(struct platform_device *dev)
{
	int ret;
    /*初始化一个锁*/   
	mutex_init(&adcdev.lock);

	/* 注册一个ADC设备驱动 */
	adcdev.client = s3c_adc_register(dev, NULL, NULL, 0);
	if (IS_ERR(adcdev.client)) {
		printk("tiny4412_adc: cannot register adc\n");
		ret = PTR_ERR(adcdev.client);
		goto err_mem;
	}
    /*注册杂项设备*/
	ret = misc_register(&misc);

	printk(DEVICE_NAME"\tinitialized\n");

err_mem:
	return ret;
}

8、设备移除函数

static int __devexit exynos_adc_remove(struct platform_device *dev)
{
    /*注销杂项设备*/
	misc_deregister(&misc);
    /*释放ADC设备*/
	s3c_adc_release(adcdev.client);

	return 0;
}

9、入口函数

static int __init exynos_adc_init(void)
{
    /*注册平台总线*/
	return platform_driver_register(&exynos_adc_driver);
}

10、出口函数

static void __exit exynos_adc_exit(void)
{
    /*注销设备驱动*/
	platform_driver_unregister(&exynos_adc_driver);
}

二、驱动程序

/*
 * linux/drivers/char/tiny4412_adc.c
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>

#include <plat/adc.h>

#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define DPRINTK(x...) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}
#else
#define DPRINTK(x...) (void)(0)
#endif

#define DEVICE_NAME	"tiny4412-adc"

typedef struct {
	struct mutex lock;
	struct s3c_adc_client *client;
	int channel;
} ADC_DEV;

static ADC_DEV adcdev;

static inline int exynos_adc_read_ch(void) {
	int ret;

	ret = mutex_lock_interruptible(&adcdev.lock);
	if (ret < 0)
		return ret;

	ret = s3c_adc_read(adcdev.client, adcdev.channel);
	mutex_unlock(&adcdev.lock);

	return ret;
}

static inline void exynos_adc_set_channel(int channel) {
	if (channel < 0 || channel > 3)
		return;

	adcdev.channel = channel;
}

static ssize_t exynos_adc_read(struct file *filp, char *buffer,
		size_t count, loff_t *ppos)
{
	char str[20];
	int value;
	size_t len;

	value = exynos_adc_read_ch();

	len = sprintf(str, "%d\n", value);
	if (count >= len) {
		int r = copy_to_user(buffer, str, len);
		return r ? r : len;
	} else {
		return -EINVAL;
	}
}

static long exynos_adc_ioctl(struct file *file,
		unsigned int cmd, unsigned long arg)
{
#define ADC_SET_CHANNEL		0xc000fa01
#define ADC_SET_ADCTSC		0xc000fa02

	switch (cmd) {
		case ADC_SET_CHANNEL:
			exynos_adc_set_channel(arg);
			break;
		case ADC_SET_ADCTSC:
			/* do nothing */
			break;
		default:
			return -EINVAL;
	}

	return 0;
}

static int exynos_adc_open(struct inode *inode, struct file *filp)
{
	exynos_adc_set_channel(0);

	DPRINTK("adc opened\n");
	return 0;
}

static int exynos_adc_release(struct inode *inode, struct file *filp)
{
	DPRINTK("adc closed\n");
	return 0;
}

static struct file_operations adc_dev_fops = {
	owner:	THIS_MODULE,
	open:	exynos_adc_open,
	read:	exynos_adc_read,	
	unlocked_ioctl:	exynos_adc_ioctl,
	release:	exynos_adc_release,
};

static struct miscdevice misc = {
	.minor	= MISC_DYNAMIC_MINOR,
	.name	= "adc",
	.fops	= &adc_dev_fops,
};

static int __devinit exynos_adc_probe(struct platform_device *dev)
{
	int ret;

	mutex_init(&adcdev.lock);

	/* Register with the core ADC driver. */
	adcdev.client = s3c_adc_register(dev, NULL, NULL, 0);
	if (IS_ERR(adcdev.client)) {
		printk("tiny4412_adc: cannot register adc\n");
		ret = PTR_ERR(adcdev.client);
		goto err_mem;
	}

	ret = misc_register(&misc);

	printk(DEVICE_NAME"\tinitialized\n");

err_mem:
	return ret;
}

static int __devexit exynos_adc_remove(struct platform_device *dev)
{
	misc_deregister(&misc);
	s3c_adc_release(adcdev.client);

	return 0;
}

static struct platform_driver exynos_adc_driver = {
	.driver = {
		.name		= "tiny4412_adc",
		.owner		= THIS_MODULE,
	},
	.probe		= exynos_adc_probe,
	.remove		= __devexit_p(exynos_adc_remove),
};

static int __init exynos_adc_init(void)
{
	return platform_driver_register(&exynos_adc_driver);
}

static void __exit exynos_adc_exit(void)
{
	platform_driver_unregister(&exynos_adc_driver);
}

module_init(exynos_adc_init);
module_exit(exynos_adc_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARM Inc.");

猜你喜欢

转载自blog.csdn.net/danwuxie/article/details/82762174
ADC
今日推荐