samsung ADC 通用驱动

 

作者:曹忠明,华清远见嵌入式培训中心讲师。

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

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

struct s3c_adc_client {
        structplatform_device        *pdev;
        structlist_head         pend;        //用来构建客户请求列表
        wait_queue_head_t        *wait;        //等待队列头,用来睡眠
        unsignedint         nr_samples;
        int                result;
        unsigned char        is_ts;        //是否是触摸屏
        unsigned char         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通用驱动中注册这个结构体。注册函数为:

struct s3c_adc_client *s3c_adc_register(structplatform_device *pdev,
                        void (*select)(struct s3c_adc_client *client,unsignedint selected),
                        void (*conv)(struct s3c_adc_client *client,unsigned d0, unsigned d1,unsigned *samples_left),
                        unsignedintis_ts)

然后我们就可以读取相应通道的数据了:

int s3c_adc_read(struct s3c_adc_client *client, unsigned intch);

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

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

在arch/arm/mach-s3c2410/mach-smdk2410.c中添加如下内容

structplatform_device s3c_device_adc_conversion = {
                .name = "adc_conversion",
                .id = -1,
                .dev.parent = &s3c_device_adc.dev,
        };

2、 注册我们的设备

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

staticstructplatform_device *smdk2410_devices[] __initdata = {
                ……
                &s3c_device_adc, //添加内容
                &s3c_device_adc_conversion, //添加内容
                ……
        };

修改后重新编译内核

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");

intadc_major = 250;
        intadc_minor = 0;
        intnumber_of_devices = 1;
        struct s3c_adc_client *client;

structcdevcdev;
        dev_tdevno = 0;

staticssize_tadc_conversion_read(struct file *file, char __user *buff, size_t count, loff_t *offset)
        {
                unsigned data;
                unsignedch;
                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;
        }

staticintadc_conversion_open(structinode *inode, struct file *file)
        {
                return 0;
        }

staticintadc_conversion_release(structinode *inode, struct file *file)
        {
                return 0;
        }

staticstructfile_operationsadc_conversion_fops = {
                .owner = THIS_MODULE,
                .read = adc_conversion_read,
                .open = adc_conversion_open,
                .release = adc_conversion_release,
        };

staticint __devinitadc_conversion_probe( structplatform_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_conversion");
                if( ret )
                {
                        dev_err(dev, "failed to register device number\n");
                        gotoerr_register_chrdev_region;
                }

        cdev_init(&cdev, &adc_conversion_fops);
                cdev.owner = THIS_MODULE;
                ret = cdev_add(&cdev, devno, number_of_devices);
                if( ret )
                {
                        dev_err(dev, "failed to add device\n");
                        gotoerr_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;
         }

staticint __devexitadc_conversion_remove(structplatform_device *pdev)
        {
                s3c_adc_release(client);
                cdev_del(&cdev );
                unregister_chrdev_region(devno, number_of_devices);
                return 0;
        }

staticstructplatform_driveradc_conversion_driver = {
                .driver = {
                        .name = "adc_conversion",
                        .owner = THIS_MODULE,
                },
                .probe = adc_conversion_probe,
                .remove = __devexit_p(adc_conversion_remove)
        };

staticint __initadc_conversion_init (void)
        {
                returnplatform_driver_register( &adc_conversion_driver );
        }

static void __exit adc_conversion_exit (void)
        {
                platform_driver_unregister(&adc_conversion_driver );
        }

module_init (adc_conversion_init);
        module_exit (adc_conversion_exit);

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

#include <stdio.h>
        #include <sys/types.h>
        #include <unistd.h>
        #include <stdlib.h>
        #include <fcntl.h>

int main (void)
        {
                intfd;
                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;
        }

展开阅读全文

没有更多推荐了,返回首页