您的位置:首页 > 运维架构 > Linux

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

2007-11-10 21:52 471 查看
导读:
  Marvell-linux研究-pxa-rtc.c源代码分析
  
  转载时请注明出处和作者联系方式
  作者联系方式:李先静
  
  我对RTC感兴趣的原因有两个,一是如何把修改后的时间保存下来,下次开机后,修改后的时间仍然有效,这要把修改后的时间写入RTC的寄存器中去。二是如何实现关机响闹和定时开机,这也要设置RTC的ALARM寄存器。
  
  这里我们分析一下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-rtc是RTC的一个种实现,它并不直接暴露给用户空间,而是在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 }
  
  电源管理函数,这里要注意的是,这里的save和restore并非两个相反的动作,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~~
  
  Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1703639
本文转自
http://blog.csdn.net/absurd/archive/2007/07/23/1703639.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: