Marvelllinux研究pxartc.c源代码分析

Marvell-linux研究-pxa-rtc.c源代码分析

 

转载时请注明出处和作者联系方式

作者联系方式:李先静 <xianjimli at hotmail dot com>

 

我对RTC感兴趣的原因有两个,一是如何把修改后的时间保存下来,下次开机后,修改后的时间仍然有效,这要把修改后的时间写入RTC的寄存器中去。二是如何实现关机响闹和定时开机,这也要设置RTCALARM寄存器。

 

这里我们分析一下pxa-rtc.c的源代码

 

67 static irqreturn_t pxa_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 68 {
 69         unsigned int rtsr;
 70         unsigned long num = 0, events = RTC_IRQF;
 71
 72         rtsr = RTSR;
 73
 74         /* clear interrupt sources */
 75         RTSR = 0;
 76         RTSR = (RTSR_AL | RTSR_HZ | RTSR_RDAL1 | RTSR_RDAL2 | RTSR_SWAL1 |
 77                 RTSR_SWAL2 | RTSR_PIAL);
 78
 79         /* clear alarm interrupt if it has occurred */
 80 #ifdef  CONFIG_PXA_RTC_WRISTWATCH
 81         if (rtsr & (RTSR_RDAL1)) {
 82                 rtsr &= ~(RTSR_RDALE1 | RTSR_RDALE2);
 83                 num++;
 84                 events |= RTC_AF;
 85         }
 86 #else
 87         if (rtsr & RTSR_AL) {
 88                 rtsr &= ~RTSR_ALE;
 89                 num++;
 90                 events |= RTC_AF;
 91         }
 92 #endif
 93         if (rtsr & RTSR_HZ) {
 94                 /* rtsr &= ~RTSR_HZE; */
 95                 num++;
 96                 events |= RTC_UF;
 97         }
 98         if (rtsr & RTSR_SWAL1) {
 99                 rtsr &= ~RTSR_SWALE1;
100                 num++;
101                 events |= RTC_SWF;
102         }
103         if (rtsr & RTSR_SWAL2) {
104                 rtsr &= ~RTSR_SWALE2;
105                 num++;
106                 events |= RTC_SWF;
107         }
108         if (rtsr & RTSR_PIAL) {
109                 /* rtsr &= ~RTSR_PIALE; */
110                 num++;
111                 events |= RTC_PF;
112         }
113         RTSR = rtsr & (RTSR_ALE | RTSR_HZE | RTSR_RDALE1 |
114                         RTSR_SWALE1 | RTSR_SWALE2 | RTSR_PIALE |RTSR_PICE |
115                         RTSR_SWCE);
116
117 /*
118         printk(KERN_INFO "IRQ num:%d IRQ Events:0x%x/n", (int)num,
119                 (unsigned int)events);
120 */
121         /* update irq data & counter */
122         rtc_update(num, events);
123         return IRQ_HANDLED;
124 }

 

72 读取RTSR中的值到rtsr变量。

75 禁止所有RTC中断。

76 清除所有RTC中断的状态。

81-112 这段代码检测是否发现了某种中断,若发生了则把计数加1,并设置相应事件位域。

113 恢复中断设置。

122 调用rtc_update更新rtc_irq_data,并唤醒相应的等待者。

 

127 static irqreturn_t pxa_rtc_tickirq(int irq, void *dev_id, struct pt_regs *regs)
128 {
129         unsigned long num = 0, events = RTC_IRQF;
130         /*
131          * If we match for the first time, the periodic interrupt flag won't
132          * be set.  If it is, then we did wrap around (very unlikely but
133          * still possible) and compute the amount of missed periods.
134          * The match reg is updated only when the data is actually retrieved
135          * to avoid unnecessary interrupts.
136          */
137         OSSR = OSSR_M1; /* clear match on timer1 */
138         OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
139         num++;
140         events |= RTC_PF;
141
142         /* update irq data & counter */
143         rtc_update(num, events);
144         return IRQ_HANDLED;
145 }

 

137 清除标志。

138 设置下一次的中断时间,间隔时间长度主要用rtc_freq决定,该参数由用户设置。

139 增加事件计数。

140-143调用rtc_update更新rtc_irq_data,并唤醒相应的等待者。

 

148 static void tm_to_wwtime(struct rtc_time *tm, unsigned int *dreg,
149                         unsigned int *yreg)

165 static int wwtime_to_tm(unsigned int dreg, unsigned int yreg,
166                         struct rtc_time *tm)

184 static unsigned int tm_to_swtime(struct sw_time *tm)

195 static void swtime_to_tm(unsigned int swreg, struct sw_time *tm)

206 static int pxa_sw_get(struct sw_time *tm, unsigned long cmd, unsigned long arg)

227 static int pxa_sw_set(struct sw_time *tm, unsigned long cmd, unsigned long arg)

267 static int pxa_rtc_getalarm(struct rtc_wkalrm *alrm)

279 static int pxa_rtc_settime(struct rtc_time *tm)

297 static int pxa_rtc_setalarm(struct rtc_wkalrm *alrm)

 

以上函数都非常简单,主要是时间格式的转换,这里不再多说。

 

315 static int pxa_rtc_ioctl(unsigned int cmd, unsigned long arg)

 

提供了RTC比较完整的控制,直接操作寄存器,没有什么复杂的逻辑,这也就不列出代码了。

 

490 static struct rtc_ops   pxa_rtc_ops = {
491         .owner          = THIS_MODULE,
492         .ioctl          = pxa_rtc_ioctl,
493         .proc           = pxa_rtc_read_proc,
494         .read_time      = pxa_rtc_gettime,
495         .set_time       = pxa_rtc_settime,
496         .read_alarm     = pxa_rtc_getalarm,
497         .set_alarm      = pxa_rtc_setalarm,
498 };

 

该结构定义了RTC的基本操作,其中pxa_rtc_settime就是用来更新时间到RTC中,而pxa_rtc_setalarm就是用来设置硬件ALARM事件的。

 

500 static int pxa_rtc_probe(struct device *dev)
501 {
502         int ret;
503
504         /* find the IRQs */
505         ret = request_irq(IRQ_RTC1Hz, pxa_rtc_interrupt,
506                         SA_INTERRUPT, "RTC 1Hz", NULL);
507         if (ret) {
508                 printk(KERN_ERR "RTC:IRQ %d already in use./n", IRQ_RTC1Hz);
509                 goto IRQ_RTC1Hz_failed;
510         }
511         ret = request_irq(IRQ_RTCAlrm, pxa_rtc_interrupt,
512                         SA_INTERRUPT, "RTC Alrm", NULL);
513         if (ret) {
514                 printk(KERN_ERR "RTC:IRQ %d already in use./n", IRQ_RTCAlrm);
515                 goto IRQ_RTCAlrm_failed;
516         }
517 #ifdef SOFT_IRQP
518         ret = request_irq (IRQ_OST1, pxa_rtc_tickirq, SA_INTERRUPT, "rtc timer", NULL);
519         if (ret) {
520                 printk(KERN_ERR "rtc: IRQ %d already in use./n", IRQ_OST1);
521                 goto IRQ_OST1_failed;
522         }
523 #endif
524
525         /* initialization */
526         RTSR = 0;
527         
528         /* register RTC */
529         register_rtc(&pxa_rtc_ops);
530         return 0;
531
532 #ifdef SOFT_IRQP
533 IRQ_OST1_failed:
534         free_irq (IRQ_RTCAlrm, NULL);
535 #endif
536 IRQ_RTCAlrm_failed:
537         free_irq(IRQ_RTC1Hz, NULL);
538 IRQ_RTC1Hz_failed:
539         return -EBUSY;
540 }

 

先注册中断处理函数,初始化RTC,然后注册RTC设备。Pxa-rtcRTC的一个种实现,它并不直接暴露给用户空间,而是在rtc.c中以标准的接口/dev/rtc提供给应用程序使用。

 

542 static int pxa_rtc_remove(struct device *dev)
543 {
544         unregister_rtc(&pxa_rtc_ops);
545
546 #ifdef SOFT_IRQP
547         free_irq (IRQ_OST1, NULL);
548 #endif
549         free_irq(IRQ_RTCAlrm, NULL);
550         free_irq(IRQ_RTC1Hz, NULL);
551         return 0;
552 }

 

注销RTC,注销中断处理函数。

 

568 static int pxa_rtc_suspend(struct device *dev, pm_message_t state, u32 level)
569 {
570         struct rtc_time tm;
571         struct timespec time;
572
573         if (level == SUSPEND_POWER_DOWN) {
574                 memset(&time, 0, sizeof(struct timespec));
575
576                 pxa_rtc_gettime(&tm);
577                 rtc_tm_to_time(&tm, &time.tv_sec);
578                 save_time_delta(&pxa_rtc_delta, &time);
579         }
580
581         return 0;
582 }
583
584 static int pxa_rtc_resume(struct device *dev, u32 level)
585 {
586         struct rtc_time tm;
587         struct timespec time;
588
589         if (level == RESUME_POWER_ON) {
590                 memset(&time, 0, sizeof(struct timespec));
591
592                 pxa_rtc_gettime(&tm);
593                 rtc_tm_to_time(&tm, &time.tv_sec);
594                 restore_time_delta(&pxa_rtc_delta, &time);
595         }
596
597         return 0;
598 }

 

电源管理函数,这里要注意的是,这里的saverestore并非两个相反的动作,save是保存当前系统时间与RTC时间的差值,而restore是用上次保存的时间差值和RTC的时间来恢复当前系统时间。

 

604 static struct device_driver pxa_rtc_drv = {
605         name:           "pxa-rtc",
606         .bus            = &platform_bus_type,
607         .probe          = pxa_rtc_probe,
608         .remove         = pxa_rtc_remove,
609         .suspend        = pxa_rtc_suspend,
610         .resume         = pxa_rtc_resume,
611 };
612
613 static int __init pxa_rtc_init(void)
614 {
615         int ret;
616         ret = driver_register(&pxa_rtc_drv);
617         if (ret) {
618                 printk(KERN_ERR "rtc: register error./n");
619         }
620         printk(KERN_INFO "PXA Real Time Clock driver v" DRIVER_VERSION "/n");
621         return 0;
622 }
623
624 static void __exit pxa_rtc_exit(void)
625 {
626         driver_unregister(&pxa_rtc_drv);
627 }

 

注册/注销设备驱动程序。

 

~~end~~

 
原文地址:https://www.cnblogs.com/zhangyunlin/p/6167702.html