微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM-Linux驱动--RTC(实时时钟)驱动分析

ARM-Linux驱动--RTC(实时时钟)驱动分析

时间:11-20 来源:互联网 点击:

rform_device这个参数后,就需要从中提取出需要的信息。它一般会通过调用内核提供的platform_get_resource和platform_get_irq等函数来获得相关信息。如通过platform_get_resource获得设备的起始地址后,可以对其进行request_mem_region和ioremap等操作,以便应用程序对其进行操作。通过platform_get_irq得到设备的中断号以后,就可以调用request_irq函数来向系统申请中断。这些操作在设备驱动程序中一般都要完成。

[cpp]view plaincopy

  1. staticint__devinits3c_rtc_probe(structplatform_device*pdev)
  2. {
  3. structrtc_device*rtc;//定义rtc_device结构体,定义在/include/linux/rtc.h
  4. structresource*res;//定义资源结构体,定义在/include/linux/ioport.h
  5. intret;
  6. pr_debug("%s:probe=%p\n",__func__,pdev);
  7. /*findtheIRQs*/
  8. s3c_rtc_tickno=platform_get_irq(pdev,1);//在系统定义的平台设备中获取中断号
  9. if(s3c_rtc_tickno<0){//异常处理
  10. dev_err(&pdev->dev,"noirqforrtctick\n");
  11. return-ENOENT;
  12. }
  13. /*getthememoryregion*/
  14. res=platform_get_resource(pdev,IORESOURCE_MEM,0);//获取RTC平台使用的IO资源
  15. if(res==NULL){
  16. dev_err(&pdev->dev,"failedtogetmemoryregionresource\n");
  17. return-ENOENT;
  18. }
  19. //申请内存区域,res是structresource类型,见本函数后面
  20. s3c_rtc_mem=request_mem_region(res->start,
  21. res->end-res->start+1,
  22. pdev->name);
  23. if(s3c_rtc_mem==NULL){//申请内存出错
  24. dev_err(&pdev->dev,"failedtoreservememoryregion\n");
  25. ret=-ENOENT;
  26. gotoerr_nores;
  27. }
  28. //将寄存器地址映射成虚拟地址,以便访问
  29. s3c_rtc_base=ioremap(res->start,res->end-res->start+1);
  30. if(s3c_rtc_base==NULL){
  31. dev_err(&pdev->dev,"failedioremap()\n");
  32. ret=-EINVAL;
  33. gotoerr_nomap;
  34. }
  35. /*checktoseeifeverythingissetupcorrectly*/
  36. s3c_rtc_enable(pdev,1);//对RTCCON寄存器设置,详情见下面的函数实现
  37. pr_debug("s3c2410_rtc:RTCCON=%02x\n",
  38. readb(s3c_rtc_base+S3C2410_RTCCON));
  39. s3c_rtc_setfreq(&pdev->dev,1);//详情见下面的函数实现
  40. /*registerRTCandexit*/
  41. rtc=rtc_device_register("s3c",&pdev->dev,&s3c_rtcops,
  42. THIS_MODULE);//注册RTC为RTC设备,其中s3c_rtcops定义见下
  43. if(IS_ERR(rtc)){
  44. dev_err(&pdev->dev,"cannotattachrtc\n");
  45. ret=PTR_ERR(rtc);
  46. gotoerr_nortc;
  47. }
  48. rtc->max_user_freq=128;//设置RTC节拍时间计数寄存器TICNT的节拍时间计数值的用户最大相对值
  49. //将RTC类的设备数据传递给系统设备,在/include/linux/platform_device.h中

[cpp]view plaincopy

  1. //#defineplatform_set_drvdata(_dev,data)dev_set_drvdata(&(_dev)->dev,(data)),该函数在/include/linux/device.h中定义,见本函数下面

[cpp]view plaincopy

  1. platform_set_drvdata(pdev,rtc);

[cpp]view plaincopy

  1. return0;

[cpp]view plaincopy

  1. //异常处理
  2. err_nortc:
  3. s3c_rtc_enable(pdev,0);
  4. iounmap(s3c_rtc_base);
  5. err_nomap:
  6. release_resource(s3c_rtc_mem);
  7. err_nores:
  8. returnret;
  9. }

下面是/include/linux/ioport.h中struct resource结构体定义

[cpp]view plaincopy

  1. structresource{
  2. resource_size_tstart;
  3. resource_size_tend;
  4. constchar*name;
  5. unsignedlongflags;
  6. structresource*parent,*sibling,*child;
  7. };

这是dev_set_drvdata()的函数定义:

[cpp]view plaincopy

  1. staticinlinevoiddev_set_drvdata(structdevice*dev,void*data)
  2. {
  3. dev->driver_data=data;
  4. }

接下来是在s3c_rtc_probe()函数用到的两个函数s3c_rtc_enable()和s3c_rtc_setfreq()

  1. staticvoids3c_rtc_enable(structplatform_device*pdev,inten)
  2. {

  1. void__iomem*base=s3c_rtc_base;//__iomem的作用就是为了使编译器更好的优化编译
  2. unsignedinttmp;
  3. if(s3c_rtc_base==NULL)
  4. return;
  5. //en作为参数传递过来如果en==0,关闭电源前的情况
  6. if(!en){
  7. tmp=readb(base+S3C2410_RTCCON);

  1. writeb(tmp&~S3C2410_RTCCON_RTCEN,base+S3C2410_RTCCON);//设置RTCCON寄存器,屏蔽RTC使能,可以参考数据手册中寄存器的相关定义
  2. tmp=readb(base+S3C2410_TICNT);
  3. writeb(tmp&~S3C2410_TICNT_ENABLE,base+S3C2410_TICNT);//设置TICNT寄存器,屏蔽节拍时间中断使能
  4. }else{
  5. /*re-enablethedevice,andcheckitisok*/
  6. //en!=0的情况,表示系统复位,重新使能RTC驱动
  7. if((readb(base+S3C2410_RTCCON)&S3C2410_RTCCON_RTCEN)==0){//RTCCON第0位为0,将其设置为1,重新使能
  8. dev_info(&pdev->dev,"rtcdisabled,re-enabling\n");
  9. tmp=readb(base+S3C2410_RTCCON);
  10. writeb(tmp|S3C2410

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top