




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、S3C2440上RTC時鐘驅(qū)動開發(fā)實例講解一、開發(fā)環(huán)境 主 機:VMWare-Fedora 9 開發(fā)板:Mini2440-64MB Nand, Kernel: 編譯器:arm-linux-gcc-4.3.2二、相關(guān)概念1、平臺設(shè)備:通常在Linux中,把SoC系統(tǒng)中集成的獨立外設(shè)單元(如:I2C、IIS、RTC、看門狗等)都被當(dāng)作平臺設(shè)備來處理。在Linux中用platform_device結(jié)構(gòu)體來描述一個平臺設(shè)備,在內(nèi)核中定義在:include/linux/platform_device.h中,如下: struct platform_device const
2、char* name; /設(shè)備名稱intid;struct devicedev;u32num_resources; /設(shè)備使用各類資源的數(shù)量struct resource* resource; /設(shè)備使用的資源struct platform_device_id*id_entry;現(xiàn)在你不必深入理解這個結(jié)構(gòu)體,只要知道在Linux中是用這個結(jié)構(gòu)體來定義一些平臺設(shè)備的。比如在:arch/arm/plat-s3c24xx/devs.c中就定義了很多平臺設(shè)備,下面我就只貼出RTC這一種的: /* RTC */static struct resource s3c_rtc_resource = /定義了R
3、TC平臺設(shè)備使用的資源,這些資源在驅(qū)動中都會用到0 = /IO端口資源范圍.start = S3C24XX_PA_RTC,.end = S3C24XX_PA_RTC + 0xff,.flags = IORESOURCE_MEM,1 = /RTC報警中斷資源.start = IRQ_RTC,.end = IRQ_RTC,.flags = IORESOURCE_IRQ,2 = /TICK節(jié)拍時間中斷資源.start = IRQ_TICK,.end = IRQ_TICK,.flags = IORESOURCE_IRQ;struct platform_device s3c_device_rtc = /
4、定義了RTC平臺設(shè)備.name = s3c2410-rtc, /設(shè)備名稱.id = -1,.num_resources = ARRAY_SIZE(s3c_rtc_resource), /資源數(shù)量.resource = s3c_rtc_resource, /引用上面定義的資源;EXPORT_SYMBOL(s3c_device_rtc);好了,定義了平臺設(shè)備,那系統(tǒng)是怎么來使用他的呢?我們打開:arch/arm/mach-s3c2440/mach-smdk2440.c這個ARM 2440平臺的系統(tǒng)入口文件,可以看到在系統(tǒng)初始化函數(shù)smdk2440_machine_init中是使用platform_
5、add_devices這個函數(shù)將一些平臺設(shè)備添加到系統(tǒng)中的,如下:(至于系統(tǒng)是如何實現(xiàn)添加平臺設(shè)備的,這里我們不必研究,這些Linux系統(tǒng)都已經(jīng)做好了的,我們要研究的是后面平臺設(shè)備的驅(qū)動是如何實現(xiàn)的) static struct platform_device *smdk2440_devices _initdata = &s3c_device_usb,&s3c_device_lcd,&s3c_device_wdt,&s3c_device_i2c0,&s3c_device_iis, &s3c_device_rtc, /這里我們添加上RTC平臺設(shè)備,默認是沒添加的; /平臺設(shè)備列表,也就是說我們要
6、使用一個新的平臺設(shè)備要先在上面定義,然后加到這個列表中,最后到驅(qū)動層去實現(xiàn)該設(shè)備的驅(qū)動static void _init smdk2440_machine_init(void)s3c24xx_fb_set_platdata(&smdk2440_fb_info);s3c_i2c0_set_platdata(NULL); /將上面列表中的平臺設(shè)備添加到系統(tǒng)總線中platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices);smdk_machine_init();2、平臺設(shè)備驅(qū)動:這里所講的平臺設(shè)備驅(qū)動是指具體的某種平臺設(shè)備的
7、驅(qū)動,比如上面講的RTC平臺設(shè)備,這里就是指RTC平臺設(shè)備驅(qū)動。在Linux中,系統(tǒng)還為平臺設(shè)備定義了平臺驅(qū)動結(jié)構(gòu)體platform_driver,就好比系統(tǒng)為字符設(shè)備定義了file_operations一樣,但不要把平臺設(shè)備跟字符設(shè)備、塊設(shè)備、網(wǎng)絡(luò)設(shè)備搞成了并列的概念,因平臺設(shè)備也可以是字符設(shè)備等其他設(shè)備。注意:在被定義為平臺設(shè)備的字符設(shè)備的驅(qū)動中,除了要實現(xiàn)字符設(shè)備驅(qū)動中file_operations的open、release、read、write等接口函數(shù)外,還要實現(xiàn)平臺設(shè)備驅(qū)動中platform_driver的probe、remove、suspend、resume等接口函數(shù)。好了,在我
8、們搞明白上面這些后,下面我們就來具體詳細分析講解RTC平臺設(shè)備的驅(qū)動現(xiàn)實。三、實例講解1、RTC在Linux中的整體結(jié)構(gòu):就個人理解,RTC在Linux中整體結(jié)構(gòu)分為兩個部分。第一個是部分就是上面所講的作為平臺設(shè)備被掛接到系統(tǒng)總線中,這里我把他叫做設(shè)備層(呵呵,可能不是很準確的叫法);第二部分就是驅(qū)動部分,這里叫做驅(qū)動層。在Linux中要使一個驅(qū)動在不同的平臺中都能夠使用似乎是不可能的,所以我們先看內(nèi)核驅(qū)動中的RTC部分是單獨的一個文件夾,在文件夾中包含了很多不同體系結(jié)構(gòu)的RTC驅(qū)動,當(dāng)然也有S3C2440的RTC驅(qū)動,然而在這些驅(qū)動中他們都使用了一組文件里面的方法,那么這組文
9、件就是RTC的核心(注意這里的核心不是指對RTC硬件的操作,指的是對RTC操作的方法。對硬件寄存器的操作還是在具體的驅(qū)動中)。好了,我們還是用圖來說明這種關(guān)系吧!2、RTC硬件原理圖分析:以下是S3C2440AL內(nèi)部集成的RTC模塊結(jié)構(gòu)圖和一個外部的晶振接口圖我們從S3C2440內(nèi)部RTC模塊結(jié)構(gòu)圖和數(shù)據(jù)手冊得知,RTC在Linux中主要實現(xiàn)兩種功能,分別是系統(tǒng)掉電后的時間日期維持和時間日期報警(類似定時器功能)。、時間日期維持功能:主要是由RTC實時時鐘控制寄存器RTCCON進行功能的使能控制,由節(jié)拍時間計數(shù)寄存器TICNT來產(chǎn)生節(jié)拍時間中斷來實現(xiàn)實時操作系統(tǒng)功能相關(guān)的時間和實時同步。其中對
10、時間日期的操作實際上是對BCD碼操作,而BCD碼則是由一系列的寄存器組成(BCD秒寄存器BCDSEC、BCD分寄存器BCDMIN、BCD小時寄存器BCDHOUR、BCD日期寄存器BCDDATE、BCD日寄存器BCDDAY、BCD月寄存器BCDMON、BCD年寄存器BCDYEAR)。、報警功能:主要由RTC報警控制寄存器RTCALM進行功能使能控制,并產(chǎn)生報警中斷。報警時間日期的設(shè)置也是對一系列的寄存器進行操作(報警秒數(shù)據(jù)寄存器ALMSEC、報警分鐘數(shù)據(jù)寄存器ALMMIN、報警小時數(shù)據(jù)寄存器ALMHOUR、報警日期數(shù)據(jù)寄存器ALMDATE、報警月數(shù)據(jù)寄存器ALMMON、報警年數(shù)據(jù)寄存器ALMYE
11、AR)。3、RTC驅(qū)動實現(xiàn)步驟(建立驅(qū)動文件my2440_rtc.c):注意:在每步中,為了讓代碼邏輯更加有條理和容易理解,就沒有考慮代碼的順序,比如函數(shù)要先定義后調(diào)用。如果要編譯此代碼,請嚴格按照C語言的規(guī)范來調(diào)整代碼的順序。、依然是驅(qū)動程序的最基本結(jié)構(gòu):RTC驅(qū)動的初始化和退出部分及其他,如下: #include #include #include #include #include /*RTC平臺驅(qū)動結(jié)構(gòu)體,平臺驅(qū)動結(jié)構(gòu)體定義在platform_device.h中,該結(jié)構(gòu)體內(nèi)的接口函數(shù)在第、步中實現(xiàn)*/static struct platform_driver rtc_driver =
12、.probe= rtc_probe, /*RTC探測函數(shù),在第步中實現(xiàn)*/.remove= _devexit_p(rtc_remove),/*RTC移除函數(shù),在第步實現(xiàn),為何使用_devexit_p,在該函數(shù)實現(xiàn)的地方再講*/.suspend = rtc_suspend, /*RTC掛起函數(shù),在第步中實現(xiàn)*/.resume= rtc_resume, /*RTC恢復(fù)函數(shù),在第步中實現(xiàn)*/.driver= /*注意這里的名稱一定要和系統(tǒng)中定義平臺設(shè)備的地方一致,這樣才能把平臺設(shè)備與該平臺設(shè)備的驅(qū)動關(guān)聯(lián)起來*/.name= s3c2410-rtc, .owner= THIS_MODULE,;stat
13、ic int _init rtc_init(void)/*將RTC注冊成平臺設(shè)備驅(qū)動*/return platform_driver_register(&rtc_driver);static void _exit rtc_exit(void)/*注銷RTC平臺設(shè)備驅(qū)動*/platform_driver_unregister(&rtc_driver);module_init(rtc_init);module_exit(rtc_exit);MODULE_LICENSE(GPL);MODULE_AUTHOR(Huang Gang);MODULE_DESCRIPTION(My2440 RTC driv
14、er);、RTC平臺驅(qū)動結(jié)構(gòu)中探測函數(shù)rtc_probe的實現(xiàn)。探測就意味著在系統(tǒng)總線中去檢測設(shè)備的存在,然后獲取設(shè)備有用的相關(guān)資源信息,以便我們使用這些信息。代碼如下: #include #include #include #include #include /*定義了一個用來保存RTC的IO端口占用的IO空間和經(jīng)過虛擬映射后的內(nèi)存地址*/static struct resource *rtc_mem;static void _iomem *rtc_base;/*定義了兩個變量來保存RTC報警中斷號和TICK節(jié)拍時間中斷號,NO_IRQ宏定義在irq.h中*/static int rtc_a
15、larmno = NO_IRQ;static int rtc_tickno = NO_IRQ;/*申明并初始化一個自旋鎖rtc_pie_lock,對RTC資源進行互斥訪問*/static DEFINE_SPINLOCK(rtc_pie_lock);/*RTC平臺驅(qū)動探測函數(shù),注意這里為什么要使用一個_ _devinit,也到rtc_remove實現(xiàn)的地方一起講*/static int _devinit rtc_probe(struct platform_device *pdev)int ret;struct rtc_device *rtc; /*定義一個RTC設(shè)備類,rtc_device定義在
16、rtc.h中*/struct resource *res; /*定義一個資源,用來保存獲取的RTC的資源*/*在系統(tǒng)定義的RTC平臺設(shè)備中獲取RTC報警中斷號 platform_get_irq定義在platform_device.h中*/rtc_alarmno = platform_get_irq(pdev, 0); if (rtc_alarmno dev, no irq for alarmn);return -ENOENT;/在系統(tǒng)定義的RTC平臺設(shè)備中獲取TICK節(jié)拍時間中斷號rtc_tickno = platform_get_irq(pdev, 1);if (rtc_tickno dev
17、, no irq for rtc tickn);return -ENOENT;/*獲取RTC平臺設(shè)備所使用的IO端口資源,注意這個IORESOURCE_MEM標志和RTC平臺設(shè)備定義中的一致*/res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res = NULL) /*錯誤處理*/dev_err(&pdev-dev, failed to get memory region resourcen);return -ENOENT;/*申請RTC的IO端口資源所占用的IO空間(要注意理解IO空間和內(nèi)存空間的區(qū)別), request_me
18、m_region定義在ioport.h中*/rtc_mem = request_mem_region(res-start, res-end - res-start + 1, pdev-name);if (rtc_mem = NULL) /*錯誤處理*/dev_err(&pdev-dev, failed to reserve memory regionn);ret = -ENOENT;goto err_nores;/*將RTC的IO端口占用的這段IO空間映射到內(nèi)存的虛擬地址,ioremap定義在io.h中。 注意:IO空間要映射后才能使用,以后對虛擬地址的操作就是對IO空間的操作,*/rtc_b
19、ase = ioremap(res-start, res-end - res-start + 1);if (rtc_base = NULL) /*錯誤處理*/dev_err(&pdev-dev, failed ioremap()n);ret = -EINVAL;goto err_nomap;/*好了,通過上面的步驟已經(jīng)將RTC的資源都準備好了,下面就開始使用啦*/*這兩個函數(shù)開始對RTC寄存器操作,定義都在下面*/rtc_enable(pdev, 1); /*對RTC的實時時鐘控制寄存器RTCCON進行操作(功能是初始化或者使能RTC)*/rtc_setfreq(&pdev-dev, 1);/
20、*對RTC的節(jié)拍時間計數(shù)寄存器TICNT的0-6位進行操作,即:節(jié)拍時間計數(shù)值的設(shè)定*/*device_init_wakeup該函數(shù)定義在pm_wakeup.h中,定義如下:static inline void device_init_wakeup(struct device *dev, int val)dev-power.can_wakeup = dev-power.should_wakeup = !val;顯然這個函數(shù)是讓驅(qū)動支持電源管理的,這里只要知道,can_wakeup為1時表明這個設(shè)備可以被喚醒,設(shè)備驅(qū)動為了支持Linux中的電源管理,有責(zé)任調(diào)用device_init_wakeup
21、()來初始化can_wakeup,而should_wakeup則是在設(shè)備的電源狀態(tài)發(fā)生變化的時候被device_may_wakeup()用來測試,測試它該不該變化,因此can_wakeup表明的是一種能力,而should_wakeup表明的是有了這種能力以后去不去做某件事。好了,我們沒有必要深入研究電源管理的內(nèi)容了,要不就扯遠了,電源管理以后再講*/device_init_wakeup(&pdev-dev, 1);/*將RTC注冊為RTC設(shè)備類,RTC設(shè)備類在RTC驅(qū)動核心部分中由系統(tǒng)定義好的, 注意rtcops這個參數(shù)是一個結(jié)構(gòu)體,該結(jié)構(gòu)體的作用和里面的接口函數(shù)實現(xiàn)在第步中。 rtc_dev
22、ice_register函數(shù)在rtc.h中定義,在drivers/rtc/class.c中實現(xiàn)*/rtc = rtc_device_register(my2440, &pdev-dev, &rtcops, THIS_MODULE);if (IS_ERR(rtc) /*錯誤處理*/dev_err(&pdev-dev, cannot attach rtcn);ret = PTR_ERR(rtc);goto err_nortc;/*設(shè)置RTC節(jié)拍時間計數(shù)寄存器TICNT的節(jié)拍時間計數(shù)值的用戶最大相對值, 這里你可能不理解這句,沒關(guān)系,等你看到rtc_setfreq函數(shù)實現(xiàn)后自然就明白了*/rtc-m
23、ax_user_freq = 128;/*將RTC設(shè)備類的數(shù)據(jù)傳遞給系統(tǒng)平臺設(shè)備。 platform_set_drvdata是定義在platform_device.h的宏,如下: #define platform_set_drvdata(_dev,data)dev_set_drvdata(&(_dev)-dev, (data) 而dev_set_drvdata又被定義在include/linux/device.h中,如下:static inline void dev_set_drvdata (struct device *dev, void *data)dev-driver_data = da
24、ta;*/platform_set_drvdata(pdev, rtc);return 0;/以下是上面錯誤處理的跳轉(zhuǎn)點err_nortc:rtc_enable(pdev, 0);iounmap(rtc_base);err_nomap:release_resource(rtc_mem);err_nores:return ret;/*該函數(shù)主要是初始化或者使能RTC,以下RTC的各種寄存器的宏定義在arch/arm/plat-s3c/include/plat/regs-rtc.h中,各寄存器的用途和設(shè)置請參考S3C2440數(shù)據(jù)手冊的第十七章實時時鐘部分*/static void rtc_enab
25、le(struct platform_device *pdev, int flag)unsigned int tmp;/*RTC的實時時鐘控制寄存器RTCCON共有4個位,各位的初始值均為0,根據(jù)數(shù)據(jù)手冊介紹第0位(即:RCTEN位) 可以控制CPU和RTC之間的所有接口(即RTC使能功能),所以在系統(tǒng)復(fù)位后應(yīng)該將RTCCON寄存器的第0為置為1; 在關(guān)閉電源前,又應(yīng)該將該位清零,以避免無意的寫RTC寄存器*/if (!flag) /*當(dāng)flag=0時(即屬于關(guān)閉電源前的情況),RTCCON寄存器清零第一位*/tmp = readb(rtc_base + S3C2410_RTCCON); /*
26、讀取RTCCON寄存器的值*/* tmp & S3C2410_RTCCON_RTCEN = 0 即屏蔽RTC使能*/writeb(tmp & S3C2410_RTCCON_RTCEN, rtc_base + S3C2410_RTCCON);tmp = readb(rtc_base + S3C2410_TICNT); /*讀取TICNT寄存器的值*/* tmp & S3C2410_TICNT_ENABLE后第7位為0,即屏蔽節(jié)拍時間中斷使能*/writeb(tmp & S3C2410_TICNT_ENABLE, rtc_base + S3C2410_TICNT); else /*當(dāng)flag!=0
27、時(即屬于系統(tǒng)復(fù)位后的情況),使能RTC*/if (readb(rtc_base + S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) = 0)dev_info(&pdev-dev, rtc disabled, re-enablingn);tmp = readb(rtc_base + S3C2410_RTCCON);writeb(tmp | S3C2410_RTCCON_RTCEN, rtc_base + S3C2410_RTCCON);if (readb(rtc_base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)dev
28、_info(&pdev-dev, removing RTCCON_CNTSELn);tmp = readb(rtc_base + S3C2410_RTCCON);writeb(tmp & S3C2410_RTCCON_CNTSEL, rtc_base + S3C2410_RTCCON);if (readb(rtc_base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)dev_info(&pdev-dev, removing RTCCON_CLKRSTn);tmp = readb(rtc_base + S3C2410_RTCCON);writeb(tmp
29、& S3C2410_RTCCON_CLKRST, rtc_base + S3C2410_RTCCON);/*該函數(shù)主要是對RTC的節(jié)拍時間計數(shù)寄存器TICNT的0-6位進行操作,即:節(jié)拍時間計數(shù)值的設(shè)定*/static int rtc_setfreq(struct device *dev, int freq)unsigned int tmp;if (!is_power_of_2(freq) /*對freq的值進行檢查*/return -EINVAL;spin_lock_irq(&rtc_pie_lock); /*獲取自旋鎖保護臨界區(qū)資源*/*讀取節(jié)拍時間計數(shù)寄存器TICNT的值*/tmp =
30、readb(rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;/*看數(shù)據(jù)手冊得知,節(jié)拍時間計數(shù)值的范圍是1-127, 還記得在rtc_enable函數(shù)中設(shè)置的rtc-max_user_freq=128嗎?所以這里要減1*/tmp |= (128 / freq) - 1; /*將經(jīng)運算后值寫入節(jié)拍時間計數(shù)寄存器TICNT中,這里主要是改變TICNT的第0-6位的值*/writeb(tmp, rtc_base + S3C2410_TICNT);spin_unlock_irq(&rtc_pie_lock);/*釋放自旋鎖,即解鎖*/return 0;、
31、RTC設(shè)備類的操作。在這一步中,才是對RTC硬件的各種寄存器進行操作,代碼如下: #include #include /*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)都在下面*/static const struct rtc_class_ops rtcops = .open= rtc_open,.release = rtc
32、_release,.irq_set_freq= rtc_setfreq, /*在第步中已實現(xiàn)*/.irq_set_state= rtc_setpie,.read_time= rtc_gettime,.set_time= rtc_settime,.read_alarm= rtc_getalarm,.set_alarm= rtc_setalarm,;/*RTC設(shè)備類打開接口函數(shù)*/static int rtc_open(struct device *dev)int ret;/*這里主要的目的是從系統(tǒng)平臺設(shè)備中獲取RTC設(shè)備類的數(shù)據(jù),和RTC探測函數(shù)rtc_probe中 的platform_set_
33、drvdata(pdev, rtc)的操作剛好相反。這些都定義在platform_device.h中*/struct platform_device *pdev = to_platform_device(dev);struct rtc_device *rtc_dev = platform_get_drvdata(pdev);/*申請RTC報警中斷服務(wù),中斷號rtc_alarmno在RTC探測函數(shù)rtc_probe中已經(jīng)獲取得, 這里使用的是快速中斷:IRQF_DISABLED。中斷服務(wù)程序為:rtc_alarmirq,將RTC設(shè)備類rtc_dev做參數(shù)傳遞過去了*/ret = request_
34、irq(rtc_alarmno, rtc_alarmirq, IRQF_DISABLED, my2440-rtc alarm, rtc_dev);if (ret) dev_err(dev, IRQ%d error %dn, rtc_alarmno, ret);return ret;/*同上面一樣,這里申請的是RTC的TICK節(jié)拍時間中斷服務(wù),服務(wù)程序是:rtc_tickirq*/ret = request_irq(rtc_tickno, rtc_tickirq, IRQF_DISABLED, my2440-rtc tick, rtc_dev);if (ret) dev_err(dev, IRQ
35、%d error %dn, rtc_tickno, ret);goto tick_err;return ret;tick_err:/*錯誤處理,注意出現(xiàn)錯誤后也要釋放掉已經(jīng)申請成功的中斷*/free_irq(rtc_alarmno, rtc_dev);return ret;/*RTC報警中斷服務(wù)程序*/static irqreturn_t rtc_alarmirq(int irq, void *argv)struct rtc_device *rdev = argv; /*接收申請中斷時傳遞過來的rtc_dev參數(shù)*/*當(dāng)報警中斷到來的時候,去設(shè)定RTC中報警的相關(guān)信息,具體設(shè)定的方法,RTC核
36、心 部分已經(jīng)在rtc_update_irq接口函數(shù)中實現(xiàn),函數(shù)定義實現(xiàn)在interface.c中*/rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);return IRQ_HANDLED;/*RTC的TICK節(jié)拍時間中斷服務(wù)*/static irqreturn_t rtc_tickirq(int irq, void *argv)struct rtc_device *rdev = argv; /*接收申請中斷時傳遞過來的rtc_dev參數(shù)*/*節(jié)拍時間中斷到來的時候,去設(shè)定RTC中節(jié)拍時間的相關(guān)信息,具體設(shè)定的方法,RTC核心 部分已經(jīng)在rtc_update_
37、irq接口函數(shù)中實現(xiàn),函數(shù)定義實現(xiàn)在interface.c中*/rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);return IRQ_HANDLED;/*RTC設(shè)備類關(guān)閉接口函數(shù)*/static void rtc_release(struct device *dev)/*和rtc_open中的作用相同*/struct platform_device *pdev = to_platform_device(dev);struct rtc_device *rtc_dev = platform_get_drvdata(pdev);/*請見rtc_setpie接口函
38、數(shù)中的解釋*/rtc_setpie(dev, 0);/*同rtc_open中中斷的申請相對應(yīng),在那里申請中斷,這里就釋放中斷*/free_irq(rtc_alarmno, rtc_dev);free_irq(rtc_tickno, rtc_dev);/*該函數(shù)主要是對RTC的節(jié)拍時間計數(shù)寄存器TICNT的第7位進行操作,即:節(jié)拍時間計數(shù)的使能功能*/static int rtc_setpie(struct device *dev, int flag)unsigned int tmp;spin_lock_irq(&rtc_pie_lock);/*獲取自旋鎖保護臨界區(qū)資源*/*讀取節(jié)拍時間計數(shù)寄存
39、器TICNT的值*/tmp = readb(rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;if (flag)tmp |= S3C2410_TICNT_ENABLE; /*根據(jù)標志flag的值來判斷是要使能還是要禁止*/*將經(jīng)運算后值寫入節(jié)拍時間計數(shù)寄存器TICNT中,這里主要是改變TICNT的第7位的值*/writeb(tmp, rtc_base + S3C2410_TICNT);spin_unlock_irq(&rtc_pie_lock);/*釋放自旋鎖,即解鎖*/return 0;/*讀取RTC中BCD數(shù)中的:分、時、日期、月、年、秒*/
40、static int rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)unsigned int have_retried = 0;retry_get_time:rtc_tm-tm_min = readb(rtc_base + S3C2410_RTCMIN); /*讀BCD分寄存器RTCMIN*/rtc_tm-tm_hour = readb(rtc_base + S3C2410_RTCHOUR); /*讀BCD時寄存器RTCHOUR*/rtc_tm-tm_mday = readb(rtc_base + S3C2410_RTCDATE
41、); /*讀BCD日期寄存器RTCDATE*/rtc_tm-tm_mon = readb(rtc_base + S3C2410_RTCMON); /*讀BCD月寄存器RTCMON*/rtc_tm-tm_year = readb(rtc_base + S3C2410_RTCYEAR); /*讀BCD年寄存器RTCYEAR*/rtc_tm-tm_sec = readb(rtc_base + S3C2410_RTCSEC); /*讀BCD秒寄存器RTCSEC*/*我們知道時間是以60為一個周期的,當(dāng)時、分、秒達到60后,他們的上一級會加1,而自身又從0開始計數(shù) 上面我們最后讀的秒,如果讀出來的秒剛好
42、是0,那么前面讀的分、時等就是上一分鐘的,結(jié)果就少了一分鐘, 所以就要重新讀取*/if (rtc_tm-tm_sec = 0 & !have_retried) have_retried = 1;goto retry_get_time;/*將上面讀取的時間日期值保存到RTC核心定義的時間結(jié)構(gòu)體中,該結(jié)構(gòu)體定義在rtc.h中, 這里的bcd2bin主要是編譯器對返回值相同時進行優(yōu)化處理,定義在bcd.h中*/rtc_tm-tm_sec= bcd2bin(rtc_tm-tm_sec);rtc_tm-tm_min= bcd2bin(rtc_tm-tm_min);rtc_tm-tm_hour = bcd
43、2bin(rtc_tm-tm_hour);rtc_tm-tm_mday = bcd2bin(rtc_tm-tm_mday);rtc_tm-tm_mon= bcd2bin(rtc_tm-tm_mon);rtc_tm-tm_year = bcd2bin(rtc_tm-tm_year);/*這里為什么要加100年和減1月呢,我們查看數(shù)據(jù)手冊得知原來是為了區(qū)別1900年和2000年閏年的因素, 1900年不是閏年而2000年是閏年。這時你或許會問那怎么不考慮1800年或2100年???原因很簡單,因為 我們的RTC時鐘只支持100年的時間范圍,呵呵!*/rtc_tm-tm_year += 100;rtc
44、_tm-tm_mon -= 1;return 0;/*和上面的rtc_gettime功能相反,將更改后的分、時、日期、月、年、秒寫入RTC中BCD數(shù)中*/static int rtc_settime(struct device *dev, struct rtc_time *tm)/*這里減100年很清楚了吧,因為上面為了區(qū)別1900年和2000年時加了100年*/int year = tm-tm_year - 100;/*RTC時鐘只支持100年的時間范圍*/if (year = 100) dev_err(dev, rtc only supports 100 yearsn);return -E
45、INVAL;/*將上面保存到RTC核心定義的時間結(jié)構(gòu)體中的時間日期值寫入對應(yīng)的寄存器中*/writeb(bin2bcd(tm-tm_sec), rtc_base + S3C2410_RTCSEC);writeb(bin2bcd(tm-tm_min), rtc_base + S3C2410_RTCMIN);writeb(bin2bcd(tm-tm_hour), rtc_base + S3C2410_RTCHOUR);writeb(bin2bcd(tm-tm_mday), rtc_base + S3C2410_RTCDATE);writeb(bin2bcd(tm-tm_mon + 1), rtc_
46、base + S3C2410_RTCMON); /*這里加1月也明白了吧*/writeb(bin2bcd(year), rtc_base + S3C2410_RTCYEAR);return 0;/*讀取RTC中報警各寄存器的:秒、分、時、月、日期、年的值,保存各值到rtc_time結(jié)構(gòu)體中*/static int rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)unsigned int alm_en;struct rtc_time *alm_tm = &alrm-time;alm_tm-tm_sec = readb(rtc_ba
47、se + S3C2410_ALMSEC);alm_tm-tm_min = readb(rtc_base + S3C2410_ALMMIN);alm_tm-tm_hour = readb(rtc_base + S3C2410_ALMHOUR);alm_tm-tm_mon = readb(rtc_base + S3C2410_ALMMON);alm_tm-tm_mday = readb(rtc_base + S3C2410_ALMDATE);alm_tm-tm_year = readb(rtc_base + S3C2410_ALMYEAR);/*獲取RTC報警控制寄存器RTCALM的值*/alm_
48、en = readb(rtc_base + S3C2410_RTCALM);/*判斷RTCALM值的第6位,來設(shè)置RTC的全局報警使能狀態(tài)到RTC核心定義的報警狀態(tài)結(jié)構(gòu)體rtc_wkalrm中*/alrm-enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;/*判斷如果RTCALM值的第0位的值(秒報警使能)為1時,就設(shè)置報警秒的值到rtc_time結(jié)構(gòu)體中*/if (alm_en & S3C2410_RTCALM_SECEN)alm_tm-tm_sec = bcd2bin(alm_tm-tm_sec);elsealm_tm-tm_sec = 0xff;/*判斷如果RTCALM值的第1位的值(分報警使能)為1時,就設(shè)置報警分的值到rtc_time結(jié)構(gòu)體中*/if (alm_en & S3C2410_RTCALM_MINEN)alm_tm-tm_min = bcd2bin(alm_tm-tm_min);elsealm_tm-tm_min = 0xff;/*判斷如果RT
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 上??照{(diào)清洗維保合同范本
- 個人舊車買賣合同范本
- 出口cip貿(mào)易合同范本
- 亮化耗材采購合同范本
- 半成品供貨合同范本
- 農(nóng)村環(huán)衛(wèi)勞務(wù)合同范本
- 化妝品oem合同范本
- 倉庫分揀合同范本
- 修路收費合同范本
- 主管績效合同范本
- 電梯維保經(jīng)營計劃書
- 工程部部門助理崗位職責(zé)
- 急需學(xué)科專業(yè)引導(dǎo)發(fā)展清單
- DB4401-T 71-2020 臭氧-活性炭深度凈水工藝設(shè)計與運行管理技術(shù)規(guī)程
- 會計廉政培訓(xùn)課件
- 2024年山東出版集團有限公司招聘筆試參考題庫含答案解析
- 熱能動力工程專業(yè)英語課件
- 市政道路工程質(zhì)量保證措施
- 牛奶供貨協(xié)議合同
- 綠色工廠評價指標及評分標準
- 甲型流感患者的護理查房
評論
0/150
提交評論