ARM-Linux驱动--ADC驱动(中断方式)

 

硬件平台:FL2440

内核版本:2.6.28

主机平台:Ubuntu 11.04

内核版本:2.6.39

这个驱动写了好久,因为原来的Linux内核编译的时候将触摸屏驱动编译进内核了,而触摸屏驱动里的ADC中断在注册的时候类型选择的是

 

IRQF_SAMPLE_RANDOM,不是共享类型,所以,自己写的ADC驱动在每次open的时候,总提示ADC中断注册失败。

 

解决方案:

重新配置内核,选择触摸屏驱动以模块的形式编译,而不是直接编译进内核,这样Linux在启动的时候不会自动加载触摸屏驱动,当然,IRQ_ADC中断号不会被占用。这样可以测试自己写的ADC驱动了。

以下是驱动源代码:

  1. #include <linux/kernel.h>   
  2. #include <linux/module.h>   
  3. #include <linux/fs.h>   
  4. #include <linux/device.h> /*创建设备节点*/   
  5. #include <linux/clk.h>   
  6. #include <linux/wait.h> /*定义DECLARE_WAIT_QUEUE_HEAD*/   
  7. #include <linux/irqreturn.h> /*定义了irqreturn_t等*/   
  8. #include <linux/interrupt.h> /*request_irq disable_irq enable_irq*/   
  9. #include <asm/io.h>   
  10. #include <asm/uaccess.h>   
  11. #include <asm/irq.h>  /*其中包含了#include "mach/irqs.h" */   
  12. #include <plat/regs-adc.h>   
  13. #include <mach/regs-clock.h>   
  14. #define ADC_MAJOR 102   
  15. #define ADC_NAME "my_adc"   
  16. #define SUCCESS 0   
  17. static int adc_open(struct inode *,struct file *);  
  18. static int adc_release(struct inode *,struct file *);  
  19. static int __init adc_init(void);  
  20. static int __exit adc_exit(void);  
  21. static ssize_t adc_read(struct file *,char *,size_t,loff_t *);  
  22. volatile unsigned long adc_con;  
  23. unsigned long adc_dat0;  
  24. int flag;//等待任务完成标志   
  25. unsigned long buf;//存放转换完成的数据   
  26. //声明等待队列   
  27. DECLARE_WAIT_QUEUE_HEAD(adc_wait);  
  28. struct clk *adc_clk;   
  29. static irqreturn_t adc_interrupt(int irq,void * dev_id)//中断处理程序   
  30. {  
  31.     if(flag==0)  
  32.     {  
  33.         buf=(readw(adc_dat0) & 0x3ff );//读取转换完成的数据   
  34.         flag=1;  
  35.         wake_up_interruptible(&adc_wait);//唤醒等待其上的进程   
  36.         printk("Read value is %ld/n",buf);  
  37.     }  
  38.     return IRQ_HANDLED;  
  39. }  
  40. struct file_operations  adc_ops =  
  41. {  
  42.     .owner  =   THIS_MODULE,  
  43.     .read       =   adc_read,  
  44.     .open   =   adc_open,  
  45.     .release    =   adc_release,  
  46. };  
  47. static int __init adc_init(void)  
  48. {  
  49.     int ret;  
  50.     adc_clk = clk_get(NULL,"adc");//获取时钟   
  51.     clk_enable(adc_clk);//使能时钟   
  52.       
  53.     ret=register_chrdev(ADC_MAJOR,ADC_NAME,&adc_ops); //注册设备   
  54.     if(ret<0)  
  55.     {  
  56.         printk("register device fail/n");  
  57.         return ret;  
  58.     }  
  59.     adc_con=(unsigned long)ioremap(0x58000000,4);  
  60.     adc_dat0=(volatile unsigned long)ioremap(0x58000000+S3C2410_ADCDAT0,4);  
  61.     if( !(adc_con & adc_dat0) )  
  62.     {  
  63.         printk("Failed to ioremap/n");  
  64.         goto handle;  
  65.     }  
  66.     printk("Initialized.../n");  
  67.     return SUCCESS;  
  68. handle:  
  69.     unregister_chrdev(ADC_MAJOR,ADC_NAME);  
  70.     return -1;  
  71. }  
  72. static int adc_open(struct inode * inode,struct file * file) //打开设备函数   
  73. {  
  74.     //注册中断   
  75.     int ret;  
  76.     //disable_irq(IRQ_ADC);   
  77.     //enable_irq(IRQ_ADC);   
  78.     ret=request_irq(IRQ_ADC,adc_interrupt,IRQF_SHARED,ADC_NAME,1);//注册中断 IRQ_ADC在 mach/irqs.h中定义   
  79.     if(ret<0)  
  80.     {  
  81.         printk("IRQ %d can not request/n",IRQ_ADC);  
  82.         return ret;  
  83.     }  
  84.     return SUCCESS;  
  85. }  
  86. static int adc_release(struct inode * inode,struct file * file) //关闭设备函数   
  87. {  
  88.     free_irq(IRQ_ADC,1);//释放中断   
  89.     return SUCCESS;  
  90. }  
  91. static ssize_t adc_read(struct file *file,  
  92.                             char * buffer,  
  93.                             size_t length,  
  94.                             loff_t * offset)//设备读取函数   
  95. {  
  96.       
  97.     writew((1<<14)|(0x31<<6),adc_con);       //设置ADCCON   
  98.     writew((readw(adc_con) | 0x1),adc_con);  //启动AD转换   
  99.     wait_event_interruptible(adc_wait,flag);  
  100.     flag=0;  
  101. }  
  102. static int __exit adc_exit(void//驱动卸载函数   
  103. {  
  104.     iounmap(adc_con);  
  105.     iounmap(adc_dat0);  
  106.     unregister_chrdev(ADC_MAJOR,ADC_NAME);  
  107.     clk_disable(adc_clk);  
  108.     clk_put(adc_clk);  
  109.     printk("The adc is unintialized/n");  
  110.     return SUCCESS;  
  111. }  
  112. module_init(adc_init);           
  113. module_exit(adc_exit);  
  114. MODULE_LICENSE("GPL");  

Makefile文件:

  1. obj-m := adc.o  
  2. KERNELDIR ?= /arm/linux-2.6.28.7-2440  
  3. PWD := $(shell pwd)  
  4. default:  
  5.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
  6. clean:  
  7.     rm -f *.o *.ko *.order *.symvers read  
  8. read:  
  9.     arm-linux-gcc -o read read_adc.c  

以下是测试代码:

  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <sys/time.h>   
  4. #define ADC_DEVICE  "/dev/my_adc"   
  5. int main()  
  6. {  
  7.     int ret;  
  8.     unsigned int data;  
  9.     ret=open(ADC_DEVICE,0);  
  10.     if(ret<0)  
  11.     {  
  12.         printf("Open adc fail/n");  
  13.         return ret;  
  14.     }  
  15.     for(;;)  
  16.     {  
  17.         //printf("cnt=%d/n",cnt);   
  18.         read(ret,&data,sizeof(data));  
  19.         //printf("The value is %d/n",data);   
  20.     }  
  21.     close(ret);  
  22.     return 0;  
  23. }  

首先新建设备:

mknod /dev/my_adc c 102 32

然后插入驱动 insmod adc.ko

运行测试程序./read

结果如下:

可以看出,调节ad转换器上的旋钮,看到AD转换值的变化,说明驱动工作正常。

 

阅读更多
个人分类: linux驱动
想对作者说点什么? 我来说一句

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

关闭
关闭
关闭