免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 984 | 回复: 0
打印 上一主题 下一主题

TQ2440adc驱动1-作为简单的字符设备 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-20 09:44 |只看该作者 |倒序浏览
一、环境描述及效果展示
硬件环境:TQ2440开发板
内核版本:linux-2.6.32
文件系统:busybox-1.13.1
交叉工具:arm-2009q1,codesource出品
效果如下
 
 
二、code
    //ad.c TQ2440,
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/sched.h>
  5. #include <linux/poll.h>
  6. #include <linux/timer.h>
  7. #include <linux/irq.h>
  8. #include <linux/cdev.h>
  9. #include <linux/clk.h>
  10. #include <linux/wait.h>//waitqueue
  11. #include <linux/errno.h>
  12. #include <linux/interrupt.h>//irq
  13. #include <linux/io.h>
  14. #include <linux/types.h>
  15. #include <linux/delay.h>
  16. #include <linux/semaphore.h>//sem
  17. #include <linux/fs.h>
  18. #include <linux/platform_device.h>//
  19. #include <linux/miscdevice.h>

  20. #include <linux/device.h>
  21. #include <linux/workqueue.h>//workqueue

  22. #include <asm/uaccess.h>
  23. #include <asm/irq.h>

  24. //soc相关

  25. #include <mach/gpio.h>
  26. #include <mach/regs-clock.h>
  27. #include <mach/regs-gpio.h>
  28. #include <mach/hardware.h>
  29. #include <mach/irqs.h>//IRQ_ADC


  30. #include <plat/regs-adc.h>//这个头文件,包含了ADC


  31. #include <plat/map.h>
  32. //取消调试信息,则只需要#define _DEBUG_ 0
  33. #define _DEBUG_ 1
  34. #define DEV_NAME "usr_adc"


  35. #if _DEBUG_
  36. #define debug(format,msg...) printk(format,##msg)
  37. #else
  38. #define debug(format,msg...) (void *)(0)
  39. #endif

  40. char * iok="ok";
  41. char *ino="no";
  42. char * msg;

  43. //ADCCON
  44. static void __iomem * VIR_ADC_BASE;
  45. #define base_addr VIR_ADC_BASE
  46. //clk
  47. static struct clk *adc_clk;

  48. //这个值是全局变量,是用来存放采样值
  49. unsigned short volatile value;

  50. //这个值用来标识转换完成
  51. unsigned int volatile end_of_conv;

  52. DECLARE_WAIT_QUEUE_HEAD(wq);
  53. DECLARE_MUTEX(lock);

  54. struct
  55. {
  56. int ch;
  57. int prescale;    
  58. }adc_dev;


  59. //相关头文件plat/regs-adc.h
  60. //下面开始书写启动ADC的函数
  61. //这个函数很关键
  62. /*
  63. 15            14                13-6            5-3                 2                1             0
  64. ecflg prscen prscvl sel_mux stdbm read_start enable_start
  65. */
  66. static int start_adc(int ch,int prescale)
  67. {
  68.     //使用256分频|使用AIN2|使能ADC

  69.     unsigned int temp=0;
  70.     //0111,1111,1101,0001
  71.     temp |= S3C2410_ADCCON_PRSCEN |S3C2410_ADCCON_PRSCVL(prescale)|S3C2410_ADCCON_SELMUX(ch);
  72.     debug("in %s,writel temp=%02x--------->[ok]\n",__func__,temp);    


  73.     writel(temp,(VIR_ADC_BASE+S3C2410_ADCCON));
  74.      debug("in %s,writel temp=%02x--------->[ok]\n",__func__,temp);


  75.     temp |= S3C2410_ADCCON_ENABLE_START;
  76.     writel(temp,(VIR_ADC_BASE+S3C2410_ADCCON));
  77.      debug("in %s,writel temp=%02x--------->[ok]\n",__func__,temp);

  78.     return 0;
  79. }

  80. //irq proc
  81. //ADC中断处理程序
  82. static irqreturn_t irq_proc(int irq, void *dev_id)
  83. {
  84.     value=readl(VIR_ADC_BASE +S3C2410_ADCDAT0)&0x3ff;
  85.     end_of_conv=1;
  86.     
  87.     
  88.     debug("in %s,readl,value=%d\n",__func__,value);    
  89.     wake_up_interruptible(&wq);
  90.     
  91.     
  92.     debug("in %s,readl,avale=%d\n",__func__,value);    
  93.     return IRQ_RETVAL(IRQ_HANDLED);
  94. }


  95. //打开设备
  96. static int dev_open(struct inode *nodep,struct file *filep)
  97. {
  98.     
  99.     int ret=0;
  100.     if(down_trylock(&lock))
  101.         {
  102.             ret= -EBUSY;
  103.             goto out;    
  104.         }
  105.     
  106.     
  107.     //value初始化为0或者初始化为0xff
  108.     //end_of_conv结束标志初始化为0
  109.     //初始化AD通道为2.分频0xff
  110.     value=0x0000;
  111.     end_of_conv=0;
  112.     adc_dev.ch=2;
  113.     adc_dev.prescale=0xff;
  114.     
  115.     //进行 ioremap
  116.     
  117.     VIR_ADC_BASE =ioremap(S3C2410_PA_ADC,0x20);
  118.     msg=(VIR_ADC_BASE==NULL ? iok : ino);
  119.     debug("in %s,ioremap VIR_ADC_BASE=%p--------->[%s]\n",__func__,VIR_ADC_BASE,msg);
  120.     if(VIR_ADC_BASE==NULL)
  121.         {
  122.             ret =-ENOMEM;    
  123.             goto out;
  124.         }
  125.         
  126.         
  127.     //writel(0,base_addr+S3C2410_ADCTSC);
  128.     ret=request_irq(IRQ_ADC,irq_proc,IRQF_SHARED,DEV_NAME,&adc_dev);
  129.     msg=(ret==0 ? iok : ino);
  130.     debug("in %s,request_irq--------->[%s]\n",__func__,msg);
  131.     if (ret)
  132.         goto out;
  133.         
  134.         
  135.             
  136.     //获得时钟源plat-s3c/clock.c
  137.     adc_clk = clk_get(NULL,"adc");
  138.     msg=(adc_clk==NULL ? iok : ino);
  139.     debug("in %s,clk_get--------->[%s]\n",__func__,msg);
  140.     if(adc_clk==NULL)
  141.         {
  142.             
  143.             ret =-ENOENT;    
  144.             goto out;
  145.         };
  146.      clk_enable(adc_clk);    
  147.         
  148.         
  149. out:        
  150.     return ret;
  151. }


  152. //read
  153. static int dev_read(struct file* filep,char * buf, ssize_t count,loff_t *ops)
  154. {
  155.     int ret=0;;
  156.                 
  157.             /*
  158.             注意这个结构
  159.             if(end_of_conv==0){}
  160.             else{}
  161.             为什么会有这个结构?
  162.             
  163.          考虑应用程序的结构
  164.             int fd=open();
  165.          ...............
  166.          do{
  167.                   ...
  168.                   i=read();
  169.                  ...
  170.                   }while(i>0);
  171.          close(fd);
  172.             
  173.              ...............
  174.             
  175.             //如果数据转换完成,
  176.             //则啥也不做直接进入下一步
  177.             
  178.             }
  179.      put_user(value,buf);
  180.      不能用这个,那样返回的数据是不正确的
  181.      */
  182.     
  183.     if(end_of_conv==0)
  184.         {
  185.         start_adc(adc_dev.ch,adc_dev.prescale);
  186.             //非阻塞读
  187.          if(filep->f_flags & O_NONBLOCK)
  188.                  {
  189.                      ret=-EAGAIN;
  190.                      debug("in %s,filep->f_flags & O_NONBLOCK------>[return]\n",__func__);
  191.                      goto out;    
  192.                  }
  193.              else//阻塞读
  194.                  {
  195.                  debug("in %s,wait_event end_of_conv=1------------->[start]\n",__func__);
  196.                  //等待事件end_of_conv==1,或者等待2s,
  197.                  wait_event_interruptible_timeout(wq,end_of_conv==1,200);
  198.                  debug("in %s,finish wait_event end_of_conv=1------------->[finish]\n",__func__);
  199.                  }
  200.             
  201.         }
  202.         else
  203.             {}

  204.         copy_to_user(buf,(char *)&value,sizeof(value));
  205.         end_of_conv=0;
  206.         value=0;
  207.     out:    
  208.         return ret;
  209.         
  210.         
  211. }



  212. //dev_release
  213. static int dev_release(struct inode *nodep,struct file *filep)
  214. {
  215.     free_irq(IRQ_ADC,&adc_dev);    
  216.     
  217.     //释放ioremap
  218.     VIR_ADC_BASE==NULL? 0 : iounmap(VIR_ADC_BASE);
  219.     
  220.     
  221.     //释放adc_clk
  222.     if(adc_clk!=NULL)
  223.         {
  224.             clk_disable(adc_clk);
  225.             clk_put(adc_clk);
  226.             adc_clk=NULL;    
  227.         }
  228.     up(&lock);    
  229.         return 0;
  230. }
  231. static int dev_write(struct file* filep,char * buf, ssize_t count,loff_t *ops)
  232. {
  233.     debug("\nsorry,this dev can't be write\n");
  234.     return 0;
  235. }



  236. //字符设备关键结构体
  237. struct file_operations file_ops=
  238. {
  239. .owner    =THIS_MODULE,
  240. .open     = dev_open,
  241. .read        =dev_read,
  242. .write    =dev_write,
  243. .release =dev_release,
  244. };



  245. //我们将这个注册为混杂设备
  246. struct miscdevice adc_fops=
  247. {
  248. .minor =MISC_DYNAMIC_MINOR,
  249. .name =DEV_NAME,
  250. .fops= &file_ops,    

  251. };

  252. //dev_init

  253. static __init int dev_init(void)
  254. {

  255.     int ret;
  256.     ret=misc_register(&adc_fops);
  257.        msg=(ret==0?iok : ino);
  258.        debug("in %s,misc_register--------->[%s]\n",__func__,msg);
  259.        return ret;

  260. }



  261. //dev_exit

  262. static __exit int dev_exit(void)
  263. {

  264.     int ret;
  265.     ret=misc_deregister(&adc_fops);
  266.        msg=(ret==0?iok : ino);
  267.        debug("in %s,misc_deregister--------->[%s]\n",__func__,msg);
  268.        return ret;

  269. }


  270. MODULE_AUTHOR("keytounix");
  271. MODULE_LICENSE("GPL");
  272. MODULE_DESCRIPTION("driver adc for TQ2440");
  273. module_init(dev_init);
  274. module_exit(dev_exit);
三、 Makefile
 
  1. TARGET=ad
  2. #这个对应ad.c
  3. #ad.c是上面那个驱动文件
  4. #生成目标文件ad.ko

  5. #-W是显示警告信息
  6. #-w不显示警告信息
  7. CC=arm-linux-gcc -w

  8. #ad.ko
  9. obj-m :=$(TARGET).o

  10. #这个是内核路径
  11. KERNELDIR :=/home/kernel/linux-2.6.32

  12. default:
  13.     make -C $(KERNELDIR) M=$(shell pwd) modules

  14. clean:
  15.     rm -rf module* *.symvers $(TARGET).o $(TARGET).mod.c $(TARGET).mod.o $(TARGET).ko $(TARGET).tmp_versions
四 、测试应用程序read
    //read.c
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <fcntl.h>

  5. int main(int argc, char *argv[])
  6. {
  7.     int fd;
  8.     if(argc==1)
  9.     {
  10.      //./test 设备名 是否阻塞读取 是否循环读取
  11.     printf("./test /dev/usr_adc 1 1\n");
  12.     printf("./test dev_name BLOCK LOOP\n");
  13.     return 0;
  14.     }
  15.     //以阻塞方式打开设备文件,非阻塞时flags=O_NONBLOCK
  16.     if(argc==3 && argv[2][0]=='0')
  17.     fd = open(argv[1], O_NONBLOCK|O_RDWR);
  18.     else
  19.         fd = open(argv[1], 0|O_RDWR);
  20.      
  21.     if(fd < 0)
  22.     {
  23.         printf("Open %s Device Faild!\n",argv[1]);
  24.         exit(1);
  25.     }
  26.     else
  27.         {
  28.         printf("open %s ok\n",argv[1])    ;
  29.         }

  30.     
  31.     
  32.         int ret;
  33.         int data;
  34.         
  35.     do
  36.     {
  37.     ret = read(fd, &data, sizeof(data));

  38.        printf("Read %s value is: %d\n", argv[1],data);
  39.        }while(argc==4 && argv[3][0]=='1');

  40.     close(fd);

  41.     return 0;
  42. }
  43. //arm-linux-gcc -march=armv4t read.c -o read
  44. //使用方法 #./read /dev/usr_adc 1 0
 
 
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP