您的位置 首页 芯闻

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

硬件平台:FL2440(S3C2440)内核版本:Linux2.6.28主机平台:Ubuntu11.04内核版本:Linux2.6.39交叉编译器版本:arm-linux-gcc3.4…

硬件渠道:FL2440(S3C2440)

内核版别:Linux 2.6.28

主机渠道:Ubuntu 11.04

内核版别:Linux 2.6.39

穿插编译器版别:arm-linux-gcc 3.4.1

原创著作,转载请标明出处http://blog.csdn.net/yming0221/article/details/6584285

1、实时时钟概述

实时时钟(RTC)单元能够在断电的状况下运用怯懦电池持续计时作业。RTC运用STRB/LDRB ARM操作传输二进制码十进制数的8位数据给CPU。其间的数据包含秒、分、时、日期、天、月、年的时刻信息。能够碑文报警功用。

2、实时时钟操作

下面是RTC模块的电路图

3、RTC寄存器介绍

实时时钟操控寄存器(RTCCON)-REAL TIME CLOCK CONTROL REGISTER

节拍时刻计数寄存器(TICNT)-TICK TIME COUNT REGISTER

RTC报警操控寄存器(RTCALM)-RTC ALARM CONTROL REGISTER

报警秒数寄存器(ALMSEC)-ALARM SECOND DATA REGISTER

报警分钟计数寄存器(ALMMIN)-ALARM MIN DATA REGISTER

报警小时数据寄存器(ALMHOUR)-ALARM HOUR DATA REGISTER

报警日期数据寄存器(ALMDATE)-ALARM DATE DATA REGISTER

报警月数数据寄存器(ALMMON)-ALARM MON DATA REGISTER

报警年数数据寄存器(ALMYEAR)-ALARM YEAR DATA REGISTER

BCD数据寄存器的格局和报警寄存器结构相同,仅仅对应的地址不同。

BCD秒寄存器(BCDSEC)-BCD SECOND REGISTER 地址:0x57000070(L)0x57000073(B)

BCD分寄存器(BCDMIN)-BCD MINUTE REGISTER 地址:0x57000074(L)0x57000077(B)

BCD小时寄存器(BCDHOUR)-BCD HOUR REGISTER 地址:0x57000078(L)0x5700007B(B)

BCD日期寄存器(BCDDATE)-BCD DATE REGISTER 地址:0x5700007C(L)0x5700007F(B)

BCD日寄存器(BCDDAY)-BCD DAY REGISTER 地址:0x57000080(L)0x57000083(B)

BCD月寄存器(BCDMON)-BCD MONTH REGISTER 地址:0x57000084(L)0x57000087(B)

BCD年寄存器(BCDYEAR)-BCD YEAR REGISTER 地址:0x57000088(L)0x5700008B(B)

4、驱动实例剖析

为了使驱动更简单了解,现在这个RTC驱动只完结了计时功用,没有增加相应的报警功用,也没有增加电源办理的功用,短少的功用往后完善。

下面先整体了解驱动:

首先是RTC驱动的结构体,在/include/linux/platform_device.h中,如下

[cpp]view plaincopy

  1. structplatform_driver{
  2. int(*probe)(structplatform_device*);
  3. int(*remove)(structplatform_device*);
  4. void(*shutdown)(structplatform_device*);
  5. int(*suspend)(structplatform_device*,pm_message_tstate);
  6. int(*suspend_late)(structplatform_device*,pm_message_tstate);
  7. int(*resume_early)(structplatform_device*);
  8. int(*resume)(structplatform_device*);
  9. structpm_ext_ops*pm;
  10. structdevice_driverdriver;
  11. };

驱动中界说对应的结构体

[cpp]view plaincopy

  1. staticstructplatform_drivers3c2410_rtc_driver={
  2. .probe=s3c_rtc_probe,//RTC勘探函数
  3. .remove=__devexit_p(s3c_rtc_remove),//RTC移除函数
  4. .driver={
  5. .name=”s3c2410-rtc”,
  6. .owner=THIS_MODULE,
  7. },
  8. };

下面是驱动中驱动的初始化和退出函数

[cpp]view plaincopy

  1. staticint__inits3c_rtc_init(void)
  2. {
  3. printk(banner);
  4. returnplatform_driver_register(&s3c2410_rtc_driver);
  5. }
  6. staticvoid__exits3c_rtc_exit(void)
  7. {
  8. platform_driver_unregister(&s3c2410_rtc_driver);
  9. }

platform_driver_register()和platform_driver_unregister()函数在/drivers/base/platform.c中完结的。

能够看出,platform_driver_register()函数的效果便是为platform_driver中的driver中的probe、remove等供给接口函数

[cpp]view plaincopy

  1. intplatform_driver_register(structplatform_driver*drv)
  2. {
  3. drv->driver.bus=&platform_bus_type;
  4. if(drv->probe)
  5. drv->driver.probe=platform_drv_probe;
  6. if(drv->remove)
  7. drv->driver.remove=platform_drv_remove;
  8. if(drv->shutdown)
  9. drv->driver.shutdown=platform_drv_shutdown;
  10. if(drv->suspend)
  11. drv->driver.suspend=platform_drv_suspend;
  12. if(drv->resume)
  13. drv->driver.resume=platform_drv_resume;
  14. if(drv->pm)
  15. drv->driver.pm=&drv->pm->base;
  16. returndriver_register(&drv->driver);//注册老的驱动
  17. }
[cpp]view plaincopy

  1. voidplatform_driver_unregister(structplatform_driver*drv)
  2. {
  3. driver_unregister(&drv->driver);
  4. }

接下来是RTC渠道驱动勘探函数s3c_rtc_probe,下面函数界说的时分运用了__devinit的效果是使编译器优化代码,将其放在和是的内存方位,削减内存占用和进步内核功率。

probe函数接收到plarform_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_RTCCON_RTCEN,base+S3C2410_RTCCON);
  11. }
  12. if((readb(base+S3C2410_RTCCON)&S3C2410_RTCCON_CNTSEL)){
  13. dev_info(&pdev->dev,”removingRTCCON_CNTSEL\n”);
  14. tmp=readb(base+S3C2410_RTCCON);
  15. writeb(tmp&~S3C2410_RTCCON_CNTSEL,base+S3C2410_RTCCON);//设置RTCCON第2位为0,设置BCD计数为混合BCD计数
  16. }
  17. if((readb(base+S3C2410_RTCCON)&S3C2410_RTCCON_CLKRST)){
  18. dev_info(&pdev->dev,”removingRTCCON_CLKRST\n”);
  19. tmp=readb(base+S3C2410_RTCCON);
  20. writeb(tmp&~S3C2410_RTCCON_CLKRST,base+S3C2410_RTCCON);//RTC时钟计数器复位
  21. }
  22. }
  23. }
[cpp]view plaincopy

  1. staticints3c_rtc_setfreq(structdevice*dev,intfreq)//设定节拍时刻计数值
  2. {
  3. unsignedinttmp;
  4. spin_lock_irq(&s3c_rtc_pie_lock);//获取自旋锁,对资源互斥拜访
  5. tmp=readb(s3c_rtc_base+S3C2410_TICNT)&S3C2410_TICNT_ENABLE;//节拍时刻使能有用
  6. tmp|=(128/freq)-1;
  7. writeb(tmp,s3c_rtc_base+S3C2410_TICNT);
  8. spin_unlock_irq(&s3c_rtc_pie_lock);//解锁
  9. return0;
  10. }

接下来是RTC设备类的操作。

下面是rtc_class_ops是RTC设备类在RTC驱动中心部分中界说的对RTC设备类进行操作的结构体,相似字符设备在驱动中的file_operations对字符设备进行操作的意思。该结构体被界说在rtc.h中,对RTC的操作首要有翻开、封闭、设置或获取时刻、设置或获取报警、设置节拍时刻计数值等等,该结构体内接口函数的完结都在下面

  1. staticconststructrtc_class_opss3c_rtcops={
  2. .open=s3c_rtc_open,
  3. .release=s3c_rtc_release,
  4. .read_time=s3c_rtc_gettime,
  5. .set_time=s3c_rtc_settime,
  6. .irq_set_freq=s3c_rtc_setfreq,
  7. .irq_set_state=s3c_rtc_setpie,
  8. };

RTC翻开设备函数s3c_rtc_open()

  1. staticints3c_rtc_open(structdevice*dev)
  2. {
  3. structplatform_device*pdev=to_platform_device(dev);//从渠道设备中获取RTC设备类的数据
  4. structrtc_device*rtc_dev=platform_get_drvdata(pdev);
  5. intret;
  6. ret=request_irq(s3c_rtc_tickno,s3c_rtc_tickirq,
  7. IRQF_DISABLED,”s3c2410-rtctick”,rtc_dev);//请求中止
  8. if(ret){
  9. dev_err(dev,”IRQ%derror%d\n”,s3c_rtc_tickno,ret);
  10. gototick_err;
  11. }
  12. tick_err:
  13. returnret;
  14. }

RTC TICK节拍时刻中止服务程序

  1. staticirqreturn_ts3c_rtc_tickirq(intirq,void*id)
  2. {
  3. structrtc_device*rdev=id;
  4. rtc_update_irq(rdev,1,RTC_PF|RTC_IRQF);
  5. returnIRQ_HANDLED;
  6. }

RTC封闭设备函数s3c_rtc_release()

  1. staticvoids3c_rtc_release(structdevice*dev)
  2. {
  3. structplatform_device*pdev=to_platform_device(dev);//从渠道设备中获取RTC设备类的数据
  4. structrtc_device*rtc_dev=platform_get_drvdata(pdev);
  5. /*donotclearAIEhere,itmaybeneededforwake*/
  6. s3c_rtc_setpie(dev,0);//函数界说见下面
  7. free_irq(s3c_rtc_tickno,rtc_dev);
  8. }

s3c_rtc_setpie()函数,该函数首要效果便是依据参数设置TICNT寄存器的最高位,参数为0,制止使能,参数为1,使能

  1. staticints3c_rtc_setpie(structdevice*dev,intenabled)
  2. {
  3. unsignedinttmp;
  4. pr_debug(“%s:pie=%d\n”,__func__,enabled);
  5. spin_lock_irq(&s3c_rtc_pie_lock);
  6. tmp=readb(s3c_rtc_base+S3C2410_TICNT)&~S3C2410_TICNT_ENABLE;//读取TICNT的值并将最高位清0
  7. if(enabled)
  8. tmp|=S3C2410_TICNT_ENABLE;
  9. writeb(tmp,s3c_rtc_base+S3C2410_TICNT);//写入核算后新的值
  10. spin_unlock_irq(&s3c_rtc_pie_lock);
  11. return0;
  12. }

下面两个函数是设置和读取BCD寄存器的时刻,逻辑很简单,仅仅读取和设置相应寄存器的值

  1. staticints3c_rtc_gettime(structdevice*dev,structrtc_time*rtc_tm)
  2. {
  3. unsignedinthave_retried=0;
  4. void__iomem*base=s3c_rtc_base;
  5. retry_get_time:
  6. rtc_tm->tm_min=readb(base+S3C2410_RTCMIN);
  7. rtc_tm->tm_hour=readb(base+S3C2410_RTCHOUR);
  8. rtc_tm->tm_mday=readb(base+S3C2410_RTCDATE);
  9. rtc_tm->tm_mon=readb(base+S3C2410_RTCMON);
  10. rtc_tm->tm_year=readb(base+S3C2410_RTCYEAR);
  11. rtc_tm->tm_sec=readb(base+S3C2410_RTCSEC);
  12. /*theonlywaytoworkoutwetherthesystemwasmid-update
  13. *whenwereaditistocheckthesecondcounter,andifit
  14. *iszero,thenwere-trytheentireread
  15. */
  16. if(rtc_tm->tm_sec==0&&!have_retried){
  17. have_retried=1;
  18. gotoretry_get_time;
  19. }
  20. pr_debug(“readtime%02x.%02x.%02x%02x/%02x/%02x\n”,
  21. rtc_tm->tm_year,rtc_tm->tm_mon,rtc_tm->tm_mday,
  22. rtc_tm->tm_hour,rtc_tm->tm_min,rtc_tm->tm_sec);
  23. rtc_tm->tm_sec=bcd2bin(rtc_tm->tm_sec);
  24. rtc_tm->tm_min=bcd2bin(rtc_tm->tm_min);
  25. rtc_tm->tm_hour=bcd2bin(rtc_tm->tm_hour);
  26. rtc_tm->tm_mday=bcd2bin(rtc_tm->tm_mday);
  27. rtc_tm->tm_mon=bcd2bin(rtc_tm->tm_mon);
  28. rtc_tm->tm_year=bcd2bin(rtc_tm->tm_year);
  29. rtc_tm->tm_year+=100;
  30. rtc_tm->tm_mon-=1;
  31. return0;
  32. }
  33. staticints3c_rtc_settime(structdevice*dev,structrtc_time*tm)
  34. {
  35. void__iomem*base=s3c_rtc_base;
  36. intyear=tm->tm_year-100;
  37. pr_debug(“settime%02d.%02d.%02d%02d/%02d/%02d\n”,
  38. tm->tm_year,tm->tm_mon,tm->tm_mday,
  39. tm->tm_hour,tm->tm_min,tm->tm_sec);
  40. /*wegetaroundy2kbysimplynotsupportingit*/
  41. if(year<0||year>=100){
  42. dev_err(dev,”rtconlysupports100years\n”);
  43. return-EINVAL;
  44. }
  45. writeb(bin2bcd(tm->tm_sec),base+S3C2410_RTCSEC);
  46. writeb(bin2bcd(tm->tm_min),base+S3C2410_RTCMIN);
  47. writeb(bin2bcd(tm->tm_hour),base+S3C2410_RTCHOUR);
  48. writeb(bin2bcd(tm->tm_mday),base+S3C2410_RTCDATE);
  49. writeb(bin2bcd(tm->tm_mon+1),base+S3C2410_RTCMON);
  50. writeb(bin2bcd(year),base+S3C2410_RTCYEAR);
  51. return0;
  52. }

到这儿RTC驱动的计时功用完结,报警功用还没有完结。下面是这个驱动源代码

  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #includeinterrupt.h>
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include
  15. #include
  16. staticstructresource*s3c_rtc_mem;
  17. staticvoid__iomem*s3c_rtc_base;
  18. staticints3c_rtc_tickno=NO_IRQ;
  19. staticDEFINE_SPINLOCK(s3c_rtc_pie_lock);
  20. staticirqreturn_ts3c_rtc_tickirq(intirq,void*id)
  21. {
  22. structrtc_device*rdev=id;
  23. rtc_update_irq(rdev,1,RTC_PF|RTC_IRQF);
  24. returnIRQ_HANDLED;
  25. }
  26. /*Updatecontrolregisters*/
  27. staticvoids3c_rtc_setaie(intto)
  28. {
  29. unsignedinttmp;
  30. pr_debug(“%s:aie=%d\n”,__func__,to);
  31. tmp=readb(s3c_rtc_base+S3C2410_RTCALM)&~S3C2410_RTCALM_ALMEN;
  32. if(to)
  33. tmp|=S3C2410_RTCALM_ALMEN;
  34. writeb(tmp,s3c_rtc_base+S3C2410_RTCALM);
  35. }
  36. staticints3c_rtc_setpie(structdevice*dev,intenabled)
  37. {
  38. unsignedinttmp;
  39. pr_debug(“%s:pie=%d\n”,__func__,enabled);
  40. spin_lock_irq(&s3c_rtc_pie_lock);
  41. tmp=readb(s3c_rtc_base+S3C2410_TICNT)&~S3C2410_TICNT_ENABLE;
  42. if(enabled)
  43. tmp|=S3C2410_TICNT_ENABLE;
  44. writeb(tmp,s3c_rtc_base+S3C2410_TICNT);
  45. spin_unlock_irq(&s3c_rtc_pie_lock);
  46. return0;
  47. }
  48. staticints3c_rtc_setfreq(structdevice*dev,intfreq)
  49. {
  50. unsignedinttmp;
  51. spin_lock_irq(&s3c_rtc_pie_lock);
  52. tmp=readb(s3c_rtc_base+S3C2410_TICNT)&S3C2410_TICNT_ENABLE;
  53. tmp|=(128/freq)-1;
  54. writeb(tmp,s3c_rtc_base+S3C2410_TICNT);
  55. spin_unlock_irq(&s3c_rtc_pie_lock);
  56. return0;
  57. }
  58. /*Timeread/write*/
  59. staticints3c_rtc_gettime(structdevice*dev,structrtc_time*rtc_tm)
  60. {
  61. unsignedinthave_retried=0;
  62. void__iomem*base=s3c_rtc_base;
  63. retry_get_time:
  64. rtc_tm->tm_min=readb(base+S3C2410_RTCMIN);
  65. rtc_tm->tm_hour=readb(base+S3C2410_RTCHOUR);
  66. rtc_tm->tm_mday=readb(base+S3C2410_RTCDATE);
  67. rtc_tm->tm_mon=readb(base+S3C2410_RTCMON);
  68. rtc_tm->tm_year=readb(base+S3C2410_RTCYEAR);
  69. rtc_tm->tm_sec=readb(base+S3C2410_RTCSEC);
  70. /*theonlywaytoworkoutwetherthesystemwasmid-update
  71. *whenwereaditistocheckthesecondcounter,andifit
  72. *iszero,thenwere-trytheentireread
  73. */
  74. if(rtc_tm->tm_sec==0&&!have_retried){
  75. have_retried=1;
  76. gotoretry_get_time;
  77. }
  78. pr_debug(“readtime%02x.%02x.%02x%02x/%02x/%02x\n”,
  79. rtc_tm->tm_year,rtc_tm->tm_mon,rtc_tm->tm_mday,
  80. rtc_tm->tm_hour,rtc_tm->tm_min,rtc_tm->tm_sec);
  81. rtc_tm->tm_sec=bcd2bin(rtc_tm->tm_sec);
  82. rtc_tm->tm_min=bcd2bin(rtc_tm->tm_min);
  83. rtc_tm->tm_hour=bcd2bin(rtc_tm->tm_hour);
  84. rtc_tm->tm_mday=bcd2bin(rtc_tm->tm_mday);
  85. rtc_tm->tm_mon=bcd2bin(rtc_tm->tm_mon);
  86. rtc_tm->tm_year=bcd2bin(rtc_tm->tm_year);
  87. rtc_tm->tm_year+=100;
  88. rtc_tm->tm_mon-=1;
  89. return0;
  90. }
  91. staticints3c_rtc_settime(structdevice*dev,structrtc_time*tm)
  92. {
  93. void__iomem*base=s3c_rtc_base;
  94. intyear=tm->tm_year-100;
  95. pr_debug(“settime%02d.%02d.%02d%02d/%02d/%02d\n”,
  96. tm->tm_year,tm->tm_mon,tm->tm_mday,
  97. tm->tm_hour,tm->tm_min,tm->tm_sec);
  98. /*wegetaroundy2kbysimplynotsupportingit*/
  99. if(year<0||year>=100){
  100. dev_err(dev,”rtconlysupports100years\n”);
  101. return-EINVAL;
  102. }
  103. writeb(bin2bcd(tm->tm_sec),base+S3C2410_RTCSEC);
  104. writeb(bin2bcd(tm->tm_min),base+S3C2410_RTCMIN);
  105. writeb(bin2bcd(tm->tm_hour),base+S3C2410_RTCHOUR);
  106. writeb(bin2bcd(tm->tm_mday),base+S3C2410_RTCDATE);
  107. writeb(bin2bcd(tm->tm_mon+1),base+S3C2410_RTCMON);
  108. writeb(bin2bcd(year),base+S3C2410_RTCYEAR);
  109. return0;
  110. }
  111. staticints3c_rtc_open(structdevice*dev)
  112. {
  113. structplatform_device*pdev=to_platform_device(dev);
  114. structrtc_device*rtc_dev=platform_get_drvdata(pdev);
  115. intret;
  116. ret=request_irq(s3c_rtc_tickno,s3c_rtc_tickirq,
  117. IRQF_DISABLED,”s3c2410-rtctick”,rtc_dev);
  118. if(ret){
  119. dev_err(dev,”IRQ%derror%d\n”,s3c_rtc_tickno,ret);
  120. gototick_err;
  121. }
  122. tick_err:
  123. returnret;
  124. }
  125. staticvoids3c_rtc_release(structdevice*dev)
  126. {
  127. structplatform_device*pdev=to_platform_device(dev);
  128. structrtc_device*rtc_dev=platform_get_drvdata(pdev);
  129. /*donotclearAIEhere,itmaybeneededforwake*/
  130. s3c_rtc_setpie(dev,0);
  131. free_irq(s3c_rtc_tickno,rtc_dev);
  132. }
  133. staticconststructrtc_class_opss3c_rtcops={
  134. .open=s3c_rtc_open,
  135. .release=s3c_rtc_release,
  136. .read_time=s3c_rtc_gettime,
  137. .set_time=s3c_rtc_settime,
  138. .irq_set_freq=s3c_rtc_setfreq,
  139. .irq_set_state=s3c_rtc_setpie,
  140. };
  141. staticvoids3c_rtc_enable(structplatform_device*pdev,inten)
  142. {
  143. void__iomem*base=s3c_rtc_base;
  144. unsignedinttmp;
  145. if(s3c_rtc_base==NULL)
  146. return;
  147. if(!en){
  148. tmp=readb(base+S3C2410_RTCCON);
  149. writeb(tmp&~S3C2410_RTCCON_RTCEN,base+S3C2410_RTCCON);
  150. tmp=readb(base+S3C2410_TICNT);
  151. writeb(tmp&~S3C2410_TICNT_ENABLE,base+S3C2410_TICNT);
  152. }else{
  153. /*re-enablethedevice,andcheckitisok*/
  154. if((readb(base+S3C2410_RTCCON)&S3C2410_RTCCON_RTCEN)==0){
  155. dev_info(&pdev->dev,”rtcdisabled,re-enabling\n”);
  156. tmp=readb(base+S3C2410_RTCCON);
  157. writeb(tmp|S3C2410_RTCCON_RTCEN,base+S3C2410_RTCCON);
  158. }
  159. if((readb(base+S3C2410_RTCCON)&S3C2410_RTCCON_CNTSEL)){
  160. dev_info(&pdev->dev,”removingRTCCON_CNTSEL\n”);
  161. tmp=readb(base+S3C2410_RTCCON);
  162. writeb(tmp&~S3C2410_RTCCON_CNTSEL,base+S3C2410_RTCCON);
  163. }
  164. if((readb(base+S3C2410_RTCCON)&S3C2410_RTCCON_CLKRST)){
  165. dev_info(&pdev->dev,”removingRTCCON_CLKRST\n”);
  166. tmp=readb(base+S3C2410_RTCCON);
  167. writeb(tmp&~S3C2410_RTCCON_CLKRST,base+S3C2410_RTCCON);
  168. }
  169. }
  170. }
  171. staticint__devexits3c_rtc_remove(structplatform_device*dev)
  172. {
  173. structrtc_device*rtc=platform_get_drvdata(dev);
  174. platform_set_drvdata(dev,NULL);
  175. rtc_device_unregister(rtc);
  176. s3c_rtc_setpie(&dev->dev,0);
  177. s3c_rtc_setaie(0);
  178. iounmap(s3c_rtc_base);
  179. release_resource(s3c_rtc_mem);
  180. kfree(s3c_rtc_mem);
  181. return0;
  182. }
  183. staticint__devinits3c_rtc_probe(structplatform_device*pdev)
  184. {
  185. structrtc_device*rtc;
  186. structresource*res;
  187. intret;
  188. pr_debug(“%s:probe=%p\n”,__func__,pdev);
  189. /*findtheIRQs*/
  190. s3c_rtc_tickno=platform_get_irq(pdev,1);
  191. if(s3c_rtc_tickno<0){
  192. dev_err(&pdev->dev,”noirqforrtctick\n”);
  193. return-ENOENT;
  194. }
  195. /*getthememoryregion*/
  196. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
  197. if(res==NULL){
  198. dev_err(&pdev->dev,”failedtogetmemoryregionresource\n”);
  199. return-ENOENT;
  200. }
  201. s3c_rtc_mem=request_mem_region(res->start,
  202. res->end-res->start+1,
  203. pdev->name);
  204. if(s3c_rtc_mem==NULL){
  205. dev_err(&pdev->dev,”failedtoreservememoryregion\n”);
  206. ret=-ENOENT;
  207. gotoerr_nores;
  208. }
  209. s3c_rtc_base=ioremap(res->start,res->end-res->start+1);
  210. if(s3c_rtc_base==NULL){
  211. dev_err(&pdev->dev,”failedioremap()\n”);
  212. ret=-EINVAL;
  213. gotoerr_nomap;
  214. }
  215. /*checktoseeifeverythingissetupcorrectly*/
  216. s3c_rtc_enable(pdev,1);
  217. pr_debug(“s3c2410_rtc:RTCCON=%02x\n”,
  218. readb(s3c_rtc_base+S3C2410_RTCCON));
  219. s3c_rtc_setfreq(&pdev->dev,1);
  220. /*registerRTCandexit*/
  221. rtc=rtc_device_register(“s3c”,&pdev->dev,&s3c_rtcops,
  222. THIS_MODULE);
  223. if(IS_ERR(rtc)){
  224. dev_err(&pdev->dev,”cannotattachrtc\n”);
  225. ret=PTR_ERR(rtc);
  226. gotoerr_nortc;
  227. }
  228. rtc->max_user_freq=128;
  229. platform_set_drvdata(pdev,rtc);
  230. return0;
  231. err_nortc:
  232. s3c_rtc_enable(pdev,0);
  233. iounmap(s3c_rtc_base);
  234. err_nomap:
  235. release_resource(s3c_rtc_mem);
  236. err_nores:
  237. returnret;
  238. }
  239. staticstructplatform_drivers3c2410_rtc_driver={
  240. .probe=s3c_rtc_probe,
  241. .remove=__devexit_p(s3c_rtc_remove),
  242. .driver={
  243. .name=”s3c2410-rtc”,
  244. .owner=THIS_MODULE,
  245. },
  246. };
  247. staticchar__initdatabanner[]=”S3C24XXRTC,(c)2004,2006SimtecElectronics\n”;
  248. staticint__inits3c_rtc_init(void)
  249. {
  250. printk(banner);
  251. returnplatform_driver_register(&s3c2410_rtc_driver);
  252. }
  253. staticvoid__exits3c_rtc_exit(void)
  254. {
  255. platform_driver_unregister(&s3c2410_rtc_driver);
  256. }
  257. module_init(s3c_rtc_init);
  258. module_exit(s3c_rtc_exit);
  259. MODULE_DESCRIPTION(“Mys3c2440RTCDriver”);
  260. MODULE_AUTHOR(“YanMing-yming0221@gmail.com”);
  261. MODULE_L%&&&&&%ENSE(“GPL”);
  262. MODULE_ALIAS(“platform:s3c2410-rtc”);

Makefile文件

  1. obj-m:=rtc.o
  2. KERNELDIR?=/arm/linux-2.6.28.7-2440
  3. PWD:=$(shellpwd)
  4. default:
  5. $(MAKE)-C$(KERNELDIR)M=$(PWD)modules
  6. clean:
  7. rm-f*.o*.ko*.order*.symvers

make后在目录下生成rtc.ko驱动,使用NFS挂在到方针板,insmod rtc.ko驱动就能够加载,碑文hwclock指令,检查是否能够读取硬件的RTC。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/news/xinwen/264385.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部