samsung ADC 通用驱动

来源:互联网 发布:大数据hadoop指令 编辑:程序博客网 时间:2024/05/16 11:42

         ADC是嵌入式产品常用的设备,它的驱动并不是很难,但是如果有多个这类设备的话,就得考虑ADC中断共享的问题了,这样反而是驱动变得较复杂,且不易控制。在2.6.29内核后在arch/arm/plat-samsung目录下加入了adc.c这个代码,这是一个通用adc驱动代码。这个代码用来初始化adc设备并构建了一个客户请求列表,用来接受客户请求转换数据。

下面这个结构体用来描述adc设备

struct adc_device {       struct platform_device    *pdev;       struct platform_device    *owner;        struct clk           *clk;       struct s3c_adc_client      *cur;       struct s3c_adc_client      *ts_pend;       void __iomem           *regs;       spinlock_t                   lock;       unsigned int               prescale;       int              irq;};

  下面这个结构体用来描述一个客户端:   

structs3c_adc_client {         structplatform_device    *pdev;                       structlist_head        pend;                        //用来构建客户请求列表         wait_queue_head_t         *wait;                //等待队列头,用来睡眠         unsignedint              nr_samples;         int                       result;         unsignedchar           is_ts;                         //是否是触摸屏         unsignedchar           channel;                            //通道          void  (*select_cb)(struct s3c_adc_client *c,unsigned selected);         void  (*convert_cb)(struct s3c_adc_client *c,                                  unsigned val1, unsigned val2,                                  unsigned *samples_left); //转换回调函数};
下面就是结构图

 我们需要在我们的驱动中构建这个结构体,并且向adc通用驱动中注册这个结构体。注册函数为:

structs3c_adc_client *s3c_adc_register(struct platform_device *pdev,               void(*select)(struct s3c_adc_client *client,                             unsigned int selected),               void(*conv)(struct s3c_adc_client *client,                             unsigned d0, unsigned d1,                             unsigned *samples_left),                             unsignedint is_ts)
然后我们就可以读取相应通道的数据了:

ints3c_adc_read(struct s3c_adc_client *client, unsigned int ch);

现在我们开始写我们的驱动:

1、  构建我们的设备结构体

在arch/arm/mach-s3c2410/mach-smdk2410.c中添加如下内容structplatform_device s3c_device_adc_convert = {.name                         ="adc_convert",.id                                 =-1,.dev.parent                =&s3c_device_adc.dev,};

2、  注册我们的设备

修改arch/arm/mach-s3c2410/mach-smdk2410.c,在结构体数组smdk2410_devices中添加我们的设备:

staticstruct platform_device *smdk2410_devices[] __initdata = {……&s3c_device_adc,                               //添加内容&s3c_device_adc_convert,     //添加内容……};

 修改后重新编译内核

3、  构建我们的驱动

#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <linux/platform_device.h>#include <plat/adc.h>#include <plat/regs-adc.h>MODULE_LICENSE ("GPL");int adc_major = 250;int adc_minor = 0;int number_of_devices = 1;struct s3c_adc_client *client;struct cdev cdev;dev_t devno = 0;static ssize_t adc_convert_read(struct file *file, char __user *buff, size_t count, loff_t *offset) {unsigned data;unsigned ch;data = 10;ch = 0;data = s3c_adc_read(client, ch);printk("data0 = %d\n", data);if(copy_to_user(buff, (char *)&data, sizeof(data)))return -EFAULT;return 0;}static int adc_convert_open(struct inode *inode, struct file *file){return 0;}static int adc_convert_release(struct inode *inode, struct file *file){return 0;}static struct file_operations adc_convert_fops = {.owner = THIS_MODULE,.read= adc_convert_read,.open = adc_convert_open,.release= adc_convert_release,};static int __devinit adc_convert_probe( struct platform_device *pdev ){struct device *dev = &pdev->dev;int ret = -EINVAL;printk("function = %s\n", __func__);devno = MKDEV(adc_major, adc_minor);ret = register_chrdev_region(devno, number_of_devices, "adc_convert");if( ret ){dev_err(dev, "failed to register device number\n");goto err_register_chrdev_region;}cdev_init(&cdev, &adc_convert_fops);cdev.owner = THIS_MODULE;ret = cdev_add(&cdev, devno, number_of_devices);if( ret ){dev_err(dev, "failed to add device\n");goto err_cdev_add;}client = s3c_adc_register (pdev, NULL, NULL, 0);if(IS_ERR( client )){dev_err(dev, "failed to register adc client\n");goto err_s3c_adc_register;}return 0;err_s3c_adc_register:cdev_del( &cdev );err_cdev_add:unregister_chrdev_region(devno, number_of_devices);err_register_chrdev_region:return ret; }static int __devexit adc_convert_remove(struct platform_device *pdev){s3c_adc_release(client);cdev_del( &cdev );unregister_chrdev_region(devno, number_of_devices);return 0;}static struct platform_driver adc_convert_driver = {.driver = {.name = "adc_convert",.owner = THIS_MODULE,},.probe= adc_convert_probe,.remove = __devexit_p(adc_convert_remove)};static int __init adc_convert_init (void){return platform_driver_register( &adc_convert_driver );}static void __exit adc_convert_exit (void) {platform_driver_unregister( &adc_convert_driver );}module_init (adc_convert_init);module_exit (adc_convert_exit);


4、  编译驱动,并加载到内核里,使用下面代码测试,即可读到相应通道的数据

#include <stdio.h>#include <sys/types.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>int main (void) {int fd;int data;fd = open ("/dev/adc",O_RDWR);if (fd < 0) {perror("open");  exit(0);}while(1){read (fd, (char *)&data, sizeof(data));printf("Voltage = %.2f\n", 3.3/1024*data);sleep(1);}close (fd);printf ("/dev/adc closed :)\n");return 0;}


原创粉丝点击