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

本文深入分析了 Marvell Linux 平台 PXA 实现的 RTC (实时时钟) 源代码,详细解释了中断处理函数、时间同步及电源管理等核心功能的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

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

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

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

67 staticirqreturn_t pxa_rtc_interrupt(intirq, void*dev_id, structpt_regs *regs)
68 {
69 unsignedintrtsr;
70 unsignedlongnum = 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 #ifdefCONFIG_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 returnIRQ_HANDLED;
124 }

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

75 禁止所有RTC中断。

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

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

113 恢复中断设置。

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

127 staticirqreturn_t pxa_rtc_tickirq(intirq, void*dev_id, structpt_regs *regs)
128 {
129 unsignedlongnum = 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 returnIRQ_HANDLED;
145 }

137 清除标志。

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

139 增加事件计数。

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

148 staticvoidtm_to_wwtime(structrtc_time *tm, unsignedint*dreg,
149 unsignedint*yreg)

165 staticintwwtime_to_tm(unsignedintdreg, unsignedintyreg,
166 structrtc_time *tm)

184 staticunsignedinttm_to_swtime(structsw_time *tm)

195 staticvoidswtime_to_tm(unsignedintswreg, structsw_time *tm)

206 staticintpxa_sw_get(structsw_time *tm, unsignedlongcmd, unsignedlongarg)

227 staticintpxa_sw_set(structsw_time *tm, unsignedlongcmd, unsignedlongarg)

267 staticintpxa_rtc_getalarm(structrtc_wkalrm *alrm)

279 staticintpxa_rtc_settime(structrtc_time *tm)

297 staticintpxa_rtc_setalarm(structrtc_wkalrm *alrm)

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

315 staticintpxa_rtc_ioctl(unsignedintcmd, unsignedlongarg)

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

490 staticstructrtc_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 staticintpxa_rtc_probe(structdevice *dev)
501 {
502 intret;
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 %dalready in use./n", IRQ_RTC1Hz);
509 gotoIRQ_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 %dalready in use./n", IRQ_RTCAlrm);
515 gotoIRQ_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 %dalready in use./n", IRQ_OST1);
521 gotoIRQ_OST1_failed;
522 }
523 #endif
524
525 /*initialization */
526 RTSR = 0;
527
528 /*register RTC */
529 register_rtc(&pxa_rtc_ops);
530 return0;
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 staticintpxa_rtc_remove(structdevice *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 return0;
552 }

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

568 staticintpxa_rtc_suspend(structdevice *dev, pm_message_t state, u32 level)
569 {
570 structrtc_time tm;
571 structtimespec time;
572
573 if(level == SUSPEND_POWER_DOWN) {
574 memset(&time, 0, sizeof(structtimespec));
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 return0;
582 }
583
584 staticintpxa_rtc_resume(structdevice *dev, u32 level)
585 {
586 structrtc_time tm;
587 structtimespec time;
588
589 if(level == RESUME_POWER_ON) {
590 memset(&time, 0, sizeof(structtimespec));
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 return0;
598 }

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

604 staticstructdevice_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 staticint__init pxa_rtc_init(void)
614 {
615 intret;
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 return0;
622 }
623
624 staticvoid__exit pxa_rtc_exit(void)
625 {
626 driver_unregister(&pxa_rtc_drv);
627 }

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

~~end~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值