S3C2410的ADC驱动程序

驱动模块程序:

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/init.h>


#include <linux/sched.h>

#include <linux/delay.h>


#include <asm/uaccess.h>

#include <linux/kernel.h>   /* printk() */

#include <linux/slab.h>   /* kmalloc() */

#include <linux/fs.h>       /* everything... */

#include <linux/errno.h>    /* error codes */

#include <linux/types.h>    /* size_t */

#include <linux/mm.h>

#include <linux/kdev_t.h>

#include <linux/cdev.h>

#include <linux/delay.h>

#include <asm/io.h>

#include <asm/uaccess.h>

#include <linux/errno.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/slab.h>

#include <linux/input.h>

#include <linux/init.h>

#include <linux/serio.h>

#include <asm/irq.h>


#include <linux/irq.h>

#include "s3c2410-adc.h"


#define DEVICE_NAME    "adc"

#define ADCRAW_MINOR    0

#define ADC_INPUT(x)    ((x)<<3)

#define PRSCVL(x) ((x)<<6)


#define ADCCON    0x58000000

#define ADCDAT0    0x5800000c

#define CLKCON    0x4c00000c


static int adc_major = 258;


static volatile unsigned int *adccon;

static volatile unsigned int *adcdat0;

static volatile unsigned int *clkcon;


typedef struct {

    struct semaphore lock; //声明一个信号量

    wait_queue_head_t wait; //声明一个等待队列头

    int channel;//选择哪一路AD转换器

    int prescale;//预分频值

}ADC_DEV;


static ADC_DEV adcdev;

/*

 *中断处理函数

 */

static irqreturn_t adcdone_int_handler(int irq,void *dev_id)

{

    wake_up(&adcdev.wait);//唤醒等待队列

    return IRQ_HANDLED ;

}

/*

 *对设备进行写操作,buffer一定是用户空间的

 */

static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)

{

    int data;


    if(count!=sizeof(data)){

        printk(KERN_INFO"the size of  input data must be %d\n", sizeof(data));

        return 0;

    }


    copy_from_user(&data, buffer, count);//从用户空间拷贝数据到内核空间

    adcdev.channel=ADC_WRITE_GETCH(data);//得到哪一路AD转换器

    adcdev.prescale=ADC_WRITE_GETPRE(data);//得到预分频值


     //printk(KERN_INFO"set adc channel=%d, prescale=0x%x\n", adcdev.channel, adcdev.prescale);


    return count;

}

/*

 *对设备进行读操作,buffer一定是用户空间的

 */

static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)

{

    int ret = 0;


    if (down_interruptible(&adcdev.lock))//获得信号量

        return -ERESTARTSYS;

        writel(readl(adccon) &(~1), adccon);//对AD控制寄存器进行操作,具体参看s3c2410 datasheet


    writel( (1<<14) | (255<<6) |(1<<0)|(1<<0)| ADC_INPUT(adcdev.channel), adccon);

    sleep_on( &adcdev.wait );

    ret = readl(adcdat0);

    ret &= 0x3ff;

    //printk(KERN_INFO"AIN[%d] = 0x%04x, %d\n", adcdev.channel, ret, readl(S3C2410_ADCCON) & 0x80 ? 1:0);


    copy_to_user(buffer, (char *)&ret, sizeof(ret));//拷贝内核数据到用户空间


    up(&adcdev.lock);


    return sizeof(ret);

}

/*

 *打开设备

 */

static int s3c2410_adc_open(struct inode *inode, struct file *filp)

{    

        int ret;

       printk("in adc open");

    ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_DISABLED, DEVICE_NAME, NULL);//注册中断例程

    if (ret) {

        return ret;

    }


    init_MUTEX(&adcdev.lock);//初始化一个互斥的信号量,并设置为1

    init_waitqueue_head(&(adcdev.wait));//初始化等待队列


    adcdev.channel=0;

    adcdev.prescale=0xff;


    printk(KERN_INFO"adc opened\n");

    return 0;

}

/*

 *关闭设备

 */

static int s3c2410_adc_release(struct inode *inode, struct file *filp)

{

        free_irq(IRQ_ADC, NULL);//释放中断资源


    printk(KERN_INFO"adc closed\n");

    return 0;

}


/*

 *初始化并添加结构提struct cdev到系统之中

 */

static void adc_setup_cdev(struct cdev *dev, int minor,

        struct file_operations *fops)

{

    int err, devno = MKDEV(adc_major, minor);

    

    cdev_init(dev, fops);//初始化结构体struct cdev

    dev->owner = THIS_MODULE;

    dev->ops = fops;//给结构体里的ops成员赋初值,这里是对设备操作的具体的实现函数

    err = cdev_add (dev, devno, 1);//将结构提struct cdev添加到系统之中

    /* Fail gracefully if need be */

    if (err)

        printk (KERN_NOTICE "Error %d adding adc %d", err, minor);

}


static struct cdev AdcDevs;

/*

 *定义一个file_operations结构体,来实现对设备的具体操作的功能

 */

static struct file_operations adc_remap_ops = {

    owner:    THIS_MODULE,

    open:    s3c2410_adc_open,

    read:    s3c2410_adc_read,    

    write:    s3c2410_adc_write,

    release:    s3c2410_adc_release,

};


/*

 *初始化设备驱动模块,主要完成对字符设备结构体的初始化和添加到系统中,并得到一个设备的设备号

 */

static int  adc_init(void)

{

//    writel(0,S3C2410_ADCTSC); //XP_PST(NOP_MODE);

    int result;

    dev_t dev = MKDEV(adc_major, 0);//将主设备号和次设备号定义到一个dev_t数据类型的结构体之中


    /* Figure out our device number. */

    if (adc_major)

        result = register_chrdev_region(dev, 1, "adc");//静态注册一个设备,设备号先前指定好,并得到一个设备名,cat /proc/device来查看信息

    else {

        result = alloc_chrdev_region(&dev, 0, 1, "adc");//如果主设备号被占用,则由系统提供一个主设备号给设备驱动程序

        adc_major = MAJOR(dev);//得到主设备号

    }

    if (result < 0) {

        return result;

    }

    if (adc_major == 0)                          

        adc_major = result;//如果静态分配失败。把动态非配的设备号给设备驱动程序

    adc_setup_cdev(&AdcDevs, 0, &adc_remap_ops);//初始化和添加结构体struct cdev到系统之中


    //do ioremap

    adccon = ioremap(ADCCON, 0x4);

    adcdat0 = ioremap(ADCDAT0, 0x4);

    clkcon = ioremap(CLKCON, 0x4);


    printk(KERN_INFO"adc clock = %d\n", *clkcon & (0x1<<15));

    *clkcon |= 0x1 << 15; //open clock for adc


    printk(KERN_INFO"adc device installed, with major %d\n", adc_major);

    return 0;

}

/*

 *卸载驱动模块

 */

static void adc_cleanup(void)

{

    iounmap(adccon);

    iounmap(adcdat0);


    cdev_del(&AdcDevs);//删除结构体struct cdev

    unregister_chrdev_region(MKDEV(adc_major, 0), 1);//卸载设备驱动所占有的资源

    printk(KERN_INFO"adc device uninstalled\n");

}


module_init(adc_init);//初始化设备驱动程序的入口

module_exit(adc_cleanup);//卸载设备驱动程序的入口


MODULE_LICENSE("Dual BSD/GPL"); //模块应该指定代码所使用的许可证

/×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××/

头文件的部分:

#ifndef _S3C2410_ADC_H_
#define _S3C2410_ADC_H_

#define ADC_WRITE(ch, prescale)    ((ch)<<16|(prescale))

#define ADC_WRITE_GETCH(data)    (((data)>>16)&0x7)
#define ADC_WRITE_GETPRE(data)    ((data)&0xff)

#endif /* _S3C2410_ADC_H_ */

/×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××/


测序部分的应用程序:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <fcntl.h>
#include "s3c2410-adc.h"

#define ADC_DEV        "/dev/adc"
static int adc_fd = -1;

static int init_ADdevice(void)
{   //打开设备
        printf(ADC_DEV);
    if((adc_fd=open(ADC_DEV,O_RDWR))<0){
        perror("open");
        return -1;
    }
}

static int GetADresult(int channel)
{
    int PRESCALE=0XFF;
    int data=ADC_WRITE(channel, PRESCALE);
    write(adc_fd, &data, sizeof(data));//对设备进行读操作
    read(adc_fd, &data, sizeof(data));//对设备进行写操作
    return data;
}
int main(void)
{
    int i;
    float d;

    if(init_ADdevice()<0)
        return -1;
                                                                                


    while( 1 ){
            d=((float)GetADresult(0)*3.3)/1024.0;
            printf("%8.4f\t",d);
            printf("\n");
            sleep(1);
            printf("\r");
    }

    close(adc_fd);//关闭设备
    return 0;
}


/×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××/

Mafile:

ifeq ($(KERNELRELEASE),)


#KERNELDIR ?= /your/target/source/directory/

KERNELDIR ?= /home/linux/s3c2410-2.6.35/kernel/linux-2.6.35

PWD := $(shell pwd)


modules:

    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules


modules_install:

    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install


clean:

    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*


.PHONY: modules modules_install clean


else

    obj-m := s3c2410-adc.o

endif




阅读更多
想对作者说点什么? 我来说一句

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

关闭
关闭
关闭