在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > ARM-Linux驅(qū)動--RTC(實時時鐘)驅(qū)動分析

            ARM-Linux驅(qū)動--RTC(實時時鐘)驅(qū)動分析

            作者: 時間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
            硬件平臺:FL2440(S3C2440)

            內(nèi)核版本:Linux 2.6.28

            本文引用地址:http://www.biyoush.com/article/201611/318867.htm

            主機平臺:Ubuntu 11.04

            內(nèi)核版本:Linux 2.6.39

            交叉編譯器版本:arm-linux-gcc 3.4.1

            原創(chuàng)作品,轉(zhuǎn)載請標(biāo)明出處http://blog.csdn.net/yming0221/article/details/6584285

            1、實時時鐘概述

            實時時鐘(RTC)單元可以在斷電的情況下使用紐扣電池繼續(xù)計時工作。RTC使用STRB/LDRB ARM操作傳輸二進制碼十進制數(shù)的8位數(shù)據(jù)給CPU。其中的數(shù)據(jù)包括秒、分、時、日期、天、月、年的時間信息。可以執(zhí)行報警功能。

            2、實時時鐘操作

            下面是RTC模塊的電路圖

            3、RTC寄存器介紹

            實時時鐘控制寄存器(RTCCON)-REAL TIME CLOCK CONTROL REGISTER

            節(jié)拍時間計數(shù)寄存器(TICNT)-TICK TIME COUNT REGISTER

            RTC報警控制寄存器(RTCALM)-RTC ALARM CONTROL REGISTER

            報警秒數(shù)寄存器(ALMSEC)-ALARM SECOND DATA REGISTER

            報警分鐘計數(shù)寄存器(ALMMIN)-ALARM MIN DATA REGISTER

            報警小時數(shù)據(jù)寄存器(ALMHOUR)-ALARM HOUR DATA REGISTER

            報警日期數(shù)據(jù)寄存器(ALMDATE)-ALARM DATE DATA REGISTER

            報警月數(shù)數(shù)據(jù)寄存器(ALMMON)-ALARM MON DATA REGISTER

            報警年數(shù)數(shù)據(jù)寄存器(ALMYEAR)-ALARM YEAR DATA REGISTER

            BCD數(shù)據(jù)寄存器的格式和報警寄存器結(jié)構(gòu)相同,只是對應(yīng)的地址不同。

            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、驅(qū)動實例分析

            為了使驅(qū)動更容易理解,現(xiàn)在這個RTC驅(qū)動只完成了計時功能,沒有添加相應(yīng)的報警功能,也沒有添加電源管理的功能,缺少的功能今后完善。

            下面先總體了解驅(qū)動:

            首先是RTC驅(qū)動的結(jié)構(gòu)體,在/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. };
            驅(qū)動中定義對應(yīng)的結(jié)構(gòu)體

            [cpp]view plaincopy
            1. staticstructplatform_drivers3c2410_rtc_driver={
            2. .probe=s3c_rtc_probe,//RTC探測函數(shù)
            3. .remove=__devexit_p(s3c_rtc_remove),//RTC移除函數(shù)
            4. .driver={
            5. .name="s3c2410-rtc",
            6. .owner=THIS_MODULE,
            7. },
            8. };
            下面是驅(qū)動中驅(qū)動的初始化和退出函數(shù)

            [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()函數(shù)在/drivers/base/platform.c中實現(xiàn)的。

            可以看出,platform_driver_register()函數(shù)的作用就是為platform_driver中的driver中的probe、remove等提供接口函數(shù)

            [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);//注冊老的驅(qū)動
            17. }
            [cpp]view plaincopy
            1. voidplatform_driver_unregister(structplatform_driver*drv)
            2. {
            3. driver_unregister(&drv->driver);
            4. }

            接下來是RTC平臺驅(qū)動探測函數(shù)s3c_rtc_probe,下面函數(shù)定義的時候使用了__devinit的作用是使編譯器優(yōu)化代碼,將其放在和是的內(nèi)存位置,減少內(nèi)存占用和提高內(nèi)核效率。

            probe函數(shù)接收到plarform_device這個參數(shù)后,就需要從中提取出需要的信息。它一般會通過調(diào)用內(nèi)核提供的platform_get_resource和platform_get_irq等函數(shù)來獲得相關(guān)信息。如通過platform_get_resource獲得設(shè)備的起始地址后,可以對其進行request_mem_region和ioremap等操作,以便應(yīng)用程序?qū)ζ溥M行操作。通過platform_get_irq得到設(shè)備的中斷號以后,就可以調(diào)用request_irq函數(shù)來向系統(tǒng)申請中斷。這些操作在設(shè)備驅(qū)動程序中一般都要完成。

            [cpp]view plaincopy
            1. staticint__devinits3c_rtc_probe(structplatform_device*pdev)
            2. {
            3. structrtc_device*rtc;//定義rtc_device結(jié)構(gòu)體,定義在/include/linux/rtc.h
            4. structresource*res;//定義資源結(jié)構(gòu)體,定義在/include/linux/ioport.h
            5. intret;
            6. pr_debug("%s:probe=%pn",__func__,pdev);
            7. /*findtheIRQs*/
            8. s3c_rtc_tickno=platform_get_irq(pdev,1);//在系統(tǒng)定義的平臺設(shè)備中獲取中斷號
            9. if(s3c_rtc_tickno<0){//異常處理
            10. dev_err(&pdev->dev,"noirqforrtctickn");
            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,"failedtogetmemoryregionresourcen");
            17. return-ENOENT;
            18. }
            19. //申請內(nèi)存區(qū)域,res是structresource類型,見本函數(shù)后面
            20. s3c_rtc_mem=request_mem_region(res->start,
            21. res->end-res->start+1,
            22. pdev->name);
            23. if(s3c_rtc_mem==NULL){//申請內(nèi)存出錯
            24. dev_err(&pdev->dev,"failedtoreservememoryregionn");
            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寄存器設(shè)置,詳情見下面的函數(shù)實現(xiàn)
            37. pr_debug("s3c2410_rtc:RTCCON=%02xn",
            38. readb(s3c_rtc_base+S3C2410_RTCCON));
            39. s3c_rtc_setfreq(&pdev->dev,1);//詳情見下面的函數(shù)實現(xiàn)
            40. /*registerRTCandexit*/
            41. rtc=rtc_device_register("s3c",&pdev->dev,&s3c_rtcops,
            42. THIS_MODULE);//注冊RTC為RTC設(shè)備,其中s3c_rtcops定義見下
            43. if(IS_ERR(rtc)){
            44. dev_err(&pdev->dev,"cannotattachrtcn");
            45. ret=PTR_ERR(rtc);
            46. gotoerr_nortc;
            47. }
            48. rtc->max_user_freq=128;//設(shè)置RTC節(jié)拍時間計數(shù)寄存器TICNT的節(jié)拍時間計數(shù)值的用戶最大相對值
            49. //將RTC類的設(shè)備數(shù)據(jù)傳遞給系統(tǒng)設(shè)備,在/include/linux/platform_device.h中
            [cpp]view plaincopy
            1. //#defineplatform_set_drvdata(_dev,data)dev_set_drvdata(&(_dev)->dev,(data)),該函數(shù)在/include/linux/device.h中定義,見本函數(shù)下面
            [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結(jié)構(gòu)體定義
            [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()的函數(shù)定義:

            [cpp]view plaincopy
            1. staticinlinevoiddev_set_drvdata(structdevice*dev,void*data)
            2. {
            3. dev->driver_data=data;
            4. }
            接下來是在s3c_rtc_probe()函數(shù)用到的兩個函數(shù)s3c_rtc_enable()和s3c_rtc_setfreq()

            1. staticvoids3c_rtc_enable(structplatform_device*pdev,inten)
            2. {
            1. void__iomem*base=s3c_rtc_base;//__iomem的作用就是為了使編譯器更好的優(yōu)化編譯
            2. unsignedinttmp;
            3. if(s3c_rtc_base==NULL)
            4. return;
            5. //en作為參數(shù)傳遞過來如果en==0,關(guān)閉電源前的情況
            6. if(!en){
            7. tmp=readb(base+S3C2410_RTCCON);
            1. writeb(tmp&~S3C2410_RTCCON_RTCEN,base+S3C2410_RTCCON);//設(shè)置RTCCON寄存器,屏蔽RTC使能,可以參考數(shù)據(jù)手冊中寄存器的相關(guān)定義
            2. tmp=readb(base+S3C2410_TICNT);
            3. writeb(tmp&~S3C2410_TICNT_ENABLE,base+S3C2410_TICNT);//設(shè)置TICNT寄存器,屏蔽節(jié)拍時間中斷使能
            4. }else{
            5. /*re-enablethedevice,andcheckitisok*/
            6. //en!=0的情況,表示系統(tǒng)復(fù)位,重新使能RTC驅(qū)動
            7. if((readb(base+S3C2410_RTCCON)&S3C2410_RTCCON_RTCEN)==0){//RTCCON第0位為0,將其設(shè)置為1,重新使能
            8. dev_info(&pdev->dev,"rtcdisabled,re-enablingn");
            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_CNTSELn");
            14. tmp=readb(base+S3C2410_RTCCON);
            15. writeb(tmp&~S3C2410_RTCCON_CNTSEL,base+S3C2410_RTCCON);//設(shè)置RTCCON第2位為0,設(shè)置BCD計數(shù)為混合BCD計數(shù)
            16. }
            17. if((readb(base+S3C2410_RTCCON)&S3C2410_RTCCON_CLKRST)){
            18. dev_info(&pdev->dev,"removingRTCCON_CLKRSTn");
            19. tmp=readb(base+S3C2410_RTCCON);
            20. writeb(tmp&~S3C2410_RTCCON_CLKRST,base+S3C2410_RTCCON);//RTC時鐘計數(shù)器復(fù)位
            21. }
            22. }
            23. }
            [cpp]view plaincopy
            1. staticints3c_rtc_setfreq(structdevice*dev,intfreq)//設(shè)定節(jié)拍時間計數(shù)值
            2. {
            3. unsignedinttmp;
            4. spin_lock_irq(&s3c_rtc_pie_lock);//獲取自旋鎖,對資源互斥訪問
            5. tmp=readb(s3c_rtc_base+S3C2410_TICNT)&S3C2410_TICNT_ENABLE;//節(jié)拍時間使能有效
            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設(shè)備類的操作。

            下面是rtc_class_ops是RTC設(shè)備類在RTC驅(qū)動核心部分中定義的對RTC設(shè)備類進行操作的結(jié)構(gòu)體,類似字符設(shè)備在驅(qū)動中的file_operations對字符設(shè)備進行操作的意思。該結(jié)構(gòu)體被定義在rtc.h中,對RTC的操作主要有打開、關(guān)閉、設(shè)置或獲取時間、設(shè)置或獲取報警、設(shè)置節(jié)拍時間計數(shù)值等等,該結(jié)構(gòu)體內(nèi)接口函數(shù)的實現(xiàn)都在下面

            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打開設(shè)備函數(shù)s3c_rtc_open()
            1. staticints3c_rtc_open(structdevice*dev)
            2. {
            3. structplatform_device*pdev=to_platform_device(dev);//從平臺設(shè)備中獲取RTC設(shè)備類的數(shù)據(jù)
            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%dn",s3c_rtc_tickno,ret);
            10. gototick_err;
            11. }
            12. tick_err:
            13. returnret;
            14. }
            RTC TICK節(jié)拍時間中斷服務(wù)程序
            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關(guān)閉設(shè)備函數(shù)s3c_rtc_release()

            1. staticvoids3c_rtc_release(structdevice*dev)
            2. {
            3. structplatform_device*pdev=to_platform_device(dev);//從平臺設(shè)備中獲取RTC設(shè)備類的數(shù)據(jù)
            4. structrtc_device*rtc_dev=platform_get_drvdata(pdev);
            5. /*donotclearAIEhere,itmaybeneededforwake*/
            6. s3c_rtc_setpie(dev,0);//函數(shù)定義見下面
            7. free_irq(s3c_rtc_tickno,rtc_dev);
            8. }
            s3c_rtc_setpie()函數(shù),該函數(shù)主要作用就是根據(jù)參數(shù)設(shè)置TICNT寄存器的最高位,參數(shù)為0,禁止使能,參數(shù)為1,使能
            1. staticints3c_rtc_setpie(structdevice*dev,intenabled)
            2. {
            3. unsignedinttmp;
            4. pr_debug("%s:pie=%dn",__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. }
            下面兩個函數(shù)是設(shè)置和讀取BCD寄存器的時間,邏輯很簡單,只是讀取和設(shè)置相應(yīng)寄存器的值

            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/%02xn",
            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/%02dn",
            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,"rtconlysupports100yearsn");
            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驅(qū)動的計時功能實現(xiàn),報警功能還沒有完成。下面是這個驅(qū)動源代碼

            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=%dn",__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=%dn",__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/%02xn",
            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/%02dn",
            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,"rtconlysupports100yearsn");
            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%dn",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-enablingn");
            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_CNTSELn");
            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_CLKRSTn");
            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=%pn",__func__,pdev);
            189. /*findtheIRQs*/
            190. s3c_rtc_tickno=platform_get_irq(pdev,1);
            191. if(s3c_rtc_tickno<0){
            192. dev_err(&pdev->dev,"noirqforrtctickn");
            193. return-ENOENT;
            194. }
            195. /*getthememoryregion*/
            196. res=platform_get_resource(pdev,IORESOURCE_MEM,0);
            197. if(res==NULL){
            198. dev_err(&pdev->dev,"failedtogetmemoryregionresourcen");
            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,"failedtoreservememoryregionn");
            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=%02xn",
            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,"cannotattachrtcn");
            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,2006SimtecElectronicsn";
            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("[email protected]");
            261. MODULE_LICENSE("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驅(qū)動,利用NFS掛在到目標(biāo)板,insmod rtc.ko驅(qū)動就可以加載,執(zhí)行hwclock命令,查看是否可以讀取硬件的RTC。


            評論


            技術(shù)專區(qū)

            關(guān)閉