MINI2440Linux驱动01-mini2440_adc

来源:互联网 发布:软件实施工程师要求 编辑:程序博客网 时间:2024/06/14 17:26
mini2440_adc.c
#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 <linux/delay.h>#include <linux/clk.h>#include <linux/wait.h>#include <linux/sched.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <mach/regs-clock.h>#include <plat/regs-timer.h>#include <plat/regs-adc.h>#include <mach/regs-gpio.h>#include <linux/cdev.h>#include <linux/miscdevice.h>//自己定义的头文件,因原生内核并没有包含#include "s3c24xx-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 "adc"  //定义ADC 转换设备名称,将出现在/dev/adcstatic void __iomem *base_addr;//定义ADC 设备结构typedef struct {   wait_queue_head_t wait;   int channel;   int prescale;}ADC_DEV;DECLARE_MUTEX(ADC_LOCK);  //;声明全局信号量,以便和触摸屏驱动程序共享A/D 转换器static int OwnADC = 0;    //;ADC 驱动是否拥有A/D 转换器资源的状态变量static ADC_DEV adcdev;static volatile int ev_adc = 0;static int adc_data;static struct clk *adc_clock;/*定义ADC 相关的寄存器*/#define ADCCON  (*(volatile unsigned long *)(base_addr + S3C2410_ADCCON))  //ADC control#define ADCTSC  (*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC))  //ADC touch screen control#define ADCDLY  (*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY))  //ADC start or Interval Delay#define ADCDAT0 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0)) //ADC conversion data 0#define ADCDAT1 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1)) //ADC conversion data 1#define ADCUPDN (*(volatile unsigned long *)(base_addr + 0x14))            //Stylus Up/Down interrupt status#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)//;定义“开启AD 输入”宏,因为比较简单,故没有做成函数#define START_ADC_AIN(ch, prescale) \do{ \  ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \  ADCCON |= ADC_START; \  }while(0)//;ADC 中断处理函数static irqreturn_t adcdone_int_handler(int irq, void *dev_id){ //;如果ADC 驱动拥有“A/D 转换器”资源,则从ADC 寄存器读取转换结果 if (OwnADC)   {    adc_data = ADCDAT0 & 0x3ff;    ev_adc = 1;    wake_up_interruptible(&adcdev.wait);   }  return IRQ_HANDLED;}//;ADC 读函数,一般对应于用户层/应用层的设备读函数(read)static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){  char str[20];  int value;  size_t len;//;判断“A/D 转换器”资源是否可用  if (down_trylock(&ADC_LOCK) == 0)   {     OwnADC = 1;          //标记“A/D 转换器”资源状态为可用     START_ADC_AIN(adcdev.channel, adcdev.prescale); //开始转换     wait_event_interruptible(adcdev.wait, ev_adc);  //通过终端的方式等待转换结果     ev_adc = 0;     DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);           value = adc_data;   //;把转换结果赋予value,以便传递到用户层/应用层          OwnADC = 0;         //;释放“A/D 转换器”资源     up(&ADC_LOCK);    }   else   {     value = -1;         //;没有“A/D 转换器”资源,赋值为“-1”    }  len = sprintf(str, "%d\n", value);   if (count >= len)    {    int r = copy_to_user(buffer, str, len);//;把转换结果传递到用户层/应用层    return r ? r : len;   }   else    {    return -EINVAL;   }}//;打开ADC 设备的函数,一般对应于用户态程序的openstatic int s3c2410_adc_open(struct inode *inode, struct file *filp){  init_waitqueue_head(&(adcdev.wait));   //;初始化中断队列  adcdev.channel=0;        //;缺省通道为“0”  adcdev.prescale=0xff;  DPRINTK( "adc opened\n");  return 0;}static int s3c2410_adc_release(struct inode *inode, struct file *filp){  DPRINTK( "adc closed\n");  return 0;}static struct file_operations dev_fops = {      owner: THIS_MODULE,open: s3c2410_adc_open,      read:s3c2410_adc_read,      release: s3c2410_adc_release,};static struct miscdevice misc = {      .minor = MISC_DYNAMIC_MINOR,      .name = DEVICE_NAME,      .fops = &dev_fops,};static int __init dev_init(void){  int ret;  base_addr=ioremap(S3C2410_PA_ADC,0x20);  if (base_addr == NULL)   {     printk(KERN_ERR "Failed to remap register block\n");     return -ENOMEM;    }  adc_clock = clk_get(NULL, "adc");  if (!adc_clock)     {     printk(KERN_ERR "failed to get adc clock source\n");     return -ENOENT;    }  clk_enable(adc_clock);   /* normal ADC */  ADCTSC = 0;   //;注册中断  ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);   if (ret)    {     iounmap(base_addr);     return ret;    }  ret = misc_register(&misc);//;注册设备  printk (DEVICE_NAME"\tinitialized\n");  return ret;}static void __exit dev_exit(void){//;释放中断   free_irq(IRQ_ADC, &adcdev);   iounmap(base_addr);   if (adc_clock)    {     clk_disable(adc_clock);     clk_put(adc_clock);     adc_clock = NULL;    }   misc_deregister(&misc);}EXPORT_SYMBOL(ADC_LOCK);  //导出信号量“ADC_LOCK”,以便触摸屏驱动使用module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("MyARM Inc.");

  

 s3c24xx-adc.h
#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_ */

 

1、
 #include <asm/io.h>
 void *ioremap(unsigned long phys_addr, unsigned long size);
 void iounmap(void * addr);
ioremap:是把一个物理内存地址点映射为一个内核指针,被映射数据的长度由size参数设定。
iounmap:把ioremap函数返回的那个指针传递到iounmap函数可以解除映射关系。

2、
struct clk *clk_get(struct device *dev, const char *id)
   struct clk不是linux标准的结构体,各CPU厂商定义的struct clk结构不一样,但应该都有一个int id的成员变量。
   clk_get不但会将const char *id与clk的name匹配,还会根据struct device *dev的不同将idno与clk的id成员变量匹配。

3、
int request_irq(unsigned int irq,
                irqreturn_t (*handler)(int, void *, struct pt_regs *),
                unsigned long flags,
                const char *dev_name,
                void *dev_id);
void free_irq(unsigned int irq, void *dev_id);
     从 request_irq 返回给请求函数的返回值或者是 0 指示成功, 或者是一个负的
错误码, 如同平常. 函数返回 -EBUSY 来指示另一个驱动已经使用请求的中断线
是不寻常的.调用 request_irq 的正确位置是当设备第一次打开时, 在硬件被指示来产生中
断前. 函数的参数如下:
unsigned int irq:请求的中断号
irqreturn_t (*handler):安装的处理函数指针
unsigned long flags:如你会希望的, 一个与中断管理相关的选项的位掩码(SA_INTERRUPT:当置位了, 这表示一个"快速"中断处理.
SA_SHIRQ:这个位表示中断可以在设备间共享.SA_SAMPLE_RANDOM:这个位表示产生的中断能够有贡献给 /dev/random 和 /dev/urandom 使
用的加密池)
const char *dev_name:这个传递给 request_irq 的字串用在 /proc/interrupts 来显示中断的拥有者
void *dev_id:用作共享中断线的指针

void free_irq(unsigned int irq, void *dev_id);
   调用 free_irq 的位置是设备最后一次被关闭时, 在硬件被告知不要再中
断处理器之后

 



 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 车险出保单车号填错怎么办 货车拦板变形了怎么办 行车监控看不清楚车号怎么办? 1.5米的鱼缸要怎么办 被锤子砸到手了怎么办 家里地下污水管道堵塞怎么办 家里pvc灯罩变黄怎么办 欧普吸顶灯灯罩坏了怎么办 硬盘用久了变慢怎么办 地税申报工资人员弄错怎么办 买保险保单丢了怎么办 买保险的银行卡丢了怎么办 没学过JAVA入职怎么办 磨砂皮擦了鞋油怎么办 磨破皮伤口有沙子怎么办 工行信用卡被风险锁定了怎么办 超重被超限站查住以后怎么办 银行卡输入密码次数超限怎么办 信用卡密码错误次数超限怎么办 农行密码错误次数超限怎么办 剪力墙偏心受拉怎么办 韵达快递寄丢了怎么办 重要快递送丢了怎么办 快递员送货丢了怎么办 买的快递丢失了怎么办 申通把件弄丢了怎么办 淘宝快递送丢了怎么办 我的快递丢了怎么办 顺丰快递丢件怎么办 韵达快递不发货怎么办 发物流丢了怎么办啊 圆通快递寄丢了怎么办 中通快递弄丢了怎么办 中通快递寄丢了怎么办 中通快递丢了怎么办 物流没保价坏了怎么办 顺丰保值快递丢了怎么办 顺丰保价件丢失怎么办 公司购买货物对方没有发票怎么办 加工货物对方不取怎么办 物流发货发错了怎么办