• 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~~

     
  • 相关阅读:
    [de2_tv] PAL制TV_VGA
    【转】NiosII中SDRAM相移计算
    VGA controller的代码分析
    TIOBE 2012年2月编程语言排行榜:C#力压C++
    ZendFramework入门2 使用布局
    转载 20个数据库设计最佳实践
    转载 20个很有用的CSS图形和图表技术和教程
    转载 10款实用的Ajax/JavaScript编码工具推荐
    转载 打造优秀Web设计的10项原则
    2012年1月编程语言排行榜:ObjectiveC成为年度语言
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167702.html
Copyright © 2020-2023  润新知