OK6410之ADC驱动程序 字符设备驱动

本文详细介绍了如何为OK6410平台编写ADC(模拟数字转换器)驱动程序,该驱动作为字符设备进行操作。内容涉及驱动结构、模块化、文件操作函数以及Makefile配置等关键部分,旨在帮助读者理解Linux内核中的字符设备驱动开发。
摘要由CSDN通过智能技术生成

驱动程序:
/*
 * A adc driver as an example of char device drivers
 *
 * The initial developer of the original code is Barry Song
 * <author@linuxdriver.cn>. All Rights Reserved.
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/device.h> /* device_create()*/

#include <asm/io.h>   
#include <asm/irq.h>   
#include <asm/uaccess.h>   
#include <mach/map.h>   

#include <plat/regs-adc.h>  
#include <mach/map.h>  
   

static void __iomem *base_addr;


/*s3c6410之ADC 寄存器控制地址*/

#define __ADCREG(name)  (*(volatile unsigned long *)(base_addr + name))  
#define ADCCON          __ADCREG(S3C_ADCCON)    // ADC control  
#define ADCTSC          __ADCREG(S3C_ADCTSC)    // ADC touch screen control  
#define ADCDLY          __ADCREG(S3C_ADCDLY)    // ADC start or Interval Delay  
#define ADCDAT0         __ADCREG(S3C_ADCDAT0)   // ADC conversion data 0  
#define ADCDAT1         __ADCREG(S3C_ADCDAT1)   // ADC conversion data 1  
#define ADCUPDN         __ADCREG(S3C_ADCUPDN)   // Stylus Up/Down interrupt status  


/*ADC寄存器相应位配置*/
#define PRESCALE_DIS        (0 << 14)     
#define PRESCALE_EN         (1 << 14)   
#define PRSCVL(x)           ((x) << 6)   
#define ADC_INPUT(x)        ((x) << 3)   
#define ADC_START           (1 << 0)   
#define ADC_ENDCVT          (1 << 15)  

#define ADC_SIZE    0x1000    /*全局内存最大4K字节*/
#define MEM_CLEAR 0x1  /*清0全局内存*/
#define ADC_MAJOR 250    /*预设的adc的主设备号*/

static int adc_major = ADC_MAJOR;
/*adc设备结构体*/
struct adc_dev {
    struct cdev cdev; /*cdev结构体*/
    unsigned char mem[ADC_SIZE]; /*全局内存*/
};

struct adc_dev *adc_devp; /*设备结构体指针*/

/*s3c6410之ADC控制寄存器初始化*/
static int adc_init(void)  
{  
   unsigned int preScaler = 0XFF;  
    ADCCON = (1<<14)|(preScaler<<6)|(0<<3)|(0<<2);  
    ADCCON |= ADC_START;   
   return 0;  
}  

/*文件打开函数*/
int adc_open(struct inode *inode, struct file *filp)
{
    /*ADC初始化*/
       adc_init();  
    printk("<0>adc_drv_open and adc_init()\n");
       
    return 0;
}
/*文件释放函数*/
int adc_release(struct inode *inode, struct file *filp)
{
    return 0;
}

/*读函数*/

static ssize_t adc_read(struct file *filp, char __user *buf, size_t size,
    loff_t *ppos)
{
    unsigned long p =  *ppos;
    unsigned int count = size;
    int ret = 0;
    int count=0;
    
     ADCCON |= ADC_START;   
     while(ADCCON & 0x01);//check if Enable_start is low   
     while(!(ADCCON &0x8000));/*检查转换是否结束*/  
      ret = ADCDAT0 & 0x3ff;
     count=copy_to_user(buff,(char *)&ret,sizeof(ret));

     return sizeof(ret);
}

/*文件操作结构体*/
static const struct file_operations adc_fops = {
    .owner = THIS_MODULE,
    .read = adc_read,
    .open = adc_open,
    .release = adc_release,
};

/*初始化并注册cdev*/
static void adc_setup_cdev(struct adc_dev *dev, int index)
{
    int err, devno = MKDEV(adc_major, index);

    cdev_init(&dev->cdev, &adc_fops);
    dev->cdev.owner = THIS_MODULE;
    err = cdev_add(&dev->cdev, devno, 1);
    if (err)
        printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}

struct class *myclass;


/*设备驱动模块加载函数*/
int adc_dev_init(void)
{
    int result;
    dev_t devno = MKDEV(adc_major, 0);

    /* 申请设备号*/
    if (adc_major)
        result = register_chrdev_region(devno, 1, "adc");
    else { /* 动态申请设备号 */
        result = alloc_chrdev_region(&devno, 0, 1, "adc");
        adc_major = MAJOR(devno);
    }
    if (result < 0)
        return result;

    /* 动态申请设备结构体的内存*/
    adc_devp = kmalloc(sizeof(struct adc_dev), GFP_KERNEL);
    if (!adc_devp) {    /*申请失败*/
        result =  - ENOMEM;
        goto fail_malloc;
    }

    memset(adc_devp, 0, sizeof(struct adc_dev));

    adc_setup_cdev(adc_devp, 0);

      /*自动创建设备文件*/
    myclass = class_create(THIS_MODULE,"test_char"); /*在sys下创建类目录/sys/class/test_char*/
    device_create(myclass, NULL, MKDEV(adc_major,0), NULL, "adc");   

     base_addr =ioremap(0x7E00B000,0X20);//地址映射   
     if(base_addr == NULL)  
       {  
           printk("<0>failed to remap\n");  
           return -ENOMEM;  
       }  
    
    return 0;

fail_malloc:
    unregister_chrdev_region(devno, 1);
    return result;
}

/*模块卸载函数*/
void adc_dev_exit(void)
{
    cdev_del(&adc_devp->cdev);   /*注销cdev*/
    kfree(adc_devp);     /*释放设备结构体内存*/
    unregister_chrdev_region(MKDEV(adc_major, 0), 1); /*释放设备号*/
    class_destroy(myclass);
    device_destroy(myclass,MKDEV(adc_major,0));
     iounmap(base_addr);//取消映射  
}

MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_LICENSE("Dual BSD/GPL");

module_param(adc_major, int, S_IRUGO);

module_init(adc_dev_init);
module_exit(adc_dev_exit);




应用程序:

#include <stdio.h>   
#include <fcntl.h>   
#include <unistd.h>   
 
int main()  
{  
    int fp,adc_data,i;
    int ret;
    fp = open("/dev/adc_dev",O_RDWR);  
    if(fp<0)
        printf("open failed!\n");
    printf("open sucessed!\n");
    
   for(i=0;i<100;i++)  
   {  
       ret = read(fp,&adc_data,sizeof(adc_data));  
       printf("read sucessed!\n");
       if(ret<0)
     {
        printf("read ADC failed!\n");
        return -1;
       }
       else
              printf("Read ADC value is: %d\n",adc_data);  
       sleep(1);  
    }  
   close(fp);  
   return 0;  
 }  





Makefile:

ifneq ($(KERNELRELEASE),)

obj-m := adc.o

else

KDIR := /home/OK6410/linux2.6.28

all:
    make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=arm-linux-
clean:
    rm -f *.ko *.o *.mod.o *.mod.c *.symvers

endif







  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值