S3C2440驱动篇—RTC驱动分析


Linux-2.6.32.2内核自带RTC驱动,但mach_smdk2440.c中没有添加该设备集,因此没有被激活,加入该平台设备,RTC平台设备定义在arch/arm/plat-s3c24xx/devs.c。

static struct platform_device *smdk2440_devices[] __initdata = {

       &s3c_device_usb,          /* arch/arm/mach-s3c2440/mach-smdk2440.c */

       &s3c_device_lcd,

       &s3c_device_wdt,

       &s3c_device_i2c0,

       &s3c_device_iis,

       &s3c_device_rtc,

};

驱动实现:

  1. #include <linux/module.h>   
  2. #include <linux/fs.h>   
  3. #include <linux/string.h>   
  4. #include <linux/init.h>   
  5. #include <linux/platform_device.h>   
  6. #include <linux/interrupt.h>   
  7. #include <linux/rtc.h>   
  8. #include <linux/bcd.h>   
  9. #include <linux/clk.h>   
  10. #include <linux/log2.h>   
  11.   
  12. #include <mach/hardware.h>   
  13. #include <asm/uaccess.h>   
  14. #include <asm/io.h>   
  15. #include <asm/irq.h>   
  16. #include <plat/regs-rtc.h>   
  17.   
  18. /* I have yet to find an S3C implementation with more than one 
  19.  * of these rtc blocks in */  
  20.   
  21. static struct resource *s3c_rtc_mem;  
  22.   
  23. static void __iomem *s3c_rtc_base;  
  24. static int s3c_rtc_alarmno = NO_IRQ;  
  25. static int s3c_rtc_tickno  = NO_IRQ;  
  26.   
  27. static DEFINE_SPINLOCK(s3c_rtc_pie_lock);  
  28.   
  29. /* IRQ Handlers */  
  30.   
  31. static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)  
  32. {  
  33.     struct rtc_device *rdev = id;  
  34.   
  35.     /* 报警中断到来时,设定报警相关信息,函数实现位于drivers/rtc/interface.c */  
  36.     rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);  
  37.     return IRQ_HANDLED;  
  38. }  
  39.   
  40. static irqreturn_t s3c_rtc_tickirq(int irq, void *id)  
  41. {  
  42.     struct rtc_device *rdev = id;  
  43.   
  44.     rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);  
  45.     return IRQ_HANDLED;  
  46. }  
  47.   
  48. /* Update control registers 设置RTCALM全局报警使能位*/  
  49. static void s3c_rtc_setaie(int to)  
  50. {  
  51.     unsigned int tmp;  
  52.   
  53.     pr_debug("%s: aie=%d\n", __func__, to);  
  54.   
  55.     tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;  
  56.   
  57.     if (to)  
  58.         tmp |= S3C2410_RTCALM_ALMEN;  
  59.   
  60.     writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);  
  61. }  
  62.   
  63. /* 节拍时间计数器使能 */  
  64. static int s3c_rtc_setpie(struct device *dev, int enabled)  
  65. {  
  66.     unsigned int tmp;  
  67.   
  68.     pr_debug("%s: pie=%d\n", __func__, enabled);  
  69.   
  70.     spin_lock_irq(&s3c_rtc_pie_lock);  
  71.     tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;  
  72.   
  73.     if (enabled)  
  74.         tmp |= S3C2410_TICNT_ENABLE;  
  75.   
  76.     writeb(tmp, s3c_rtc_base + S3C2410_TICNT);  
  77.     spin_unlock_irq(&s3c_rtc_pie_lock);  
  78.   
  79.     return 0;  
  80. }  
  81.   
  82. /* 节拍时间计数值设置*/  
  83. static int s3c_rtc_setfreq(struct device *dev, int freq)  
  84. {  
  85.     unsigned int tmp;  
  86.   
  87.     if (!is_power_of_2(freq))  
  88.         return -EINVAL;  
  89.   
  90.     spin_lock_irq(&s3c_rtc_pie_lock);  
  91.   
  92.     tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;  
  93.     tmp |= (128 / freq)-1;  
  94.   
  95.     writeb(tmp, s3c_rtc_base + S3C2410_TICNT);  
  96.     spin_unlock_irq(&s3c_rtc_pie_lock);  
  97.   
  98.     return 0;  
  99. }  
  100.   
  101. /* Time read/write */  
  102. /* 读取RTC中时间:分、时、日期、月、年、秒 */  
  103. static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)  
  104. {  
  105.     unsigned int have_retried = 0;  
  106.     void __iomem *base = s3c_rtc_base;  
  107.   
  108.  retry_get_time:  
  109.     rtc_tm->tm_min  = readb(base + S3C2410_RTCMIN);  
  110.     rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);  
  111.     rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE);  
  112.     rtc_tm->tm_mon  = readb(base + S3C2410_RTCMON);  
  113.     rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR);  
  114.     rtc_tm->tm_sec  = readb(base + S3C2410_RTCSEC);  
  115.   
  116.     /* the only way to work out wether the system was mid-update 
  117.      * when we read it is to check the second counter, and if it 
  118.      * is zero, then we re-try the entire read 
  119.      */  
  120.     /* 如果读到秒为0,可能有进位,根据2440手册知道,要重新读一次 */  
  121.     if (rtc_tm->tm_sec == 0 && !have_retried) {  
  122.         have_retried = 1;  
  123.         goto retry_get_time;  
  124.     }  
  125.   
  126.     pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",  
  127.          rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,  
  128.          rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);  
  129.   
  130.     /* 将BCD码转换为二进制数 */  
  131.     rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);  
  132.     rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);  
  133.     rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);  
  134.     rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);  
  135.     rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);  
  136.     rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);  
  137.   
  138.     /*这里为什么要加100年和减1月,查看数据手册得知区别1900年和2000年闰年的因素,1900年不是闰年而2000年是闰年*/  
  139.     rtc_tm->tm_year += 100;  
  140.     rtc_tm->tm_mon -= 1;  
  141.   
  142.     return 0;  
  143. }  
  144.   
  145. /* 与s3c_rtc_gettime功能相反 */  
  146. static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)  
  147. {  
  148.     void __iomem *base = s3c_rtc_base;  
  149.     int year = tm->tm_year - 100;  
  150.   
  151.     pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n",  
  152.          tm->tm_year, tm->tm_mon, tm->tm_mday,  
  153.          tm->tm_hour, tm->tm_min, tm->tm_sec);  
  154.   
  155.     /* we get around y2k by simply not supporting it */  
  156.   
  157.     if (year < 0 || year >= 100) {  
  158.         dev_err(dev, "rtc only supports 100 years\n");  
  159.         return -EINVAL;  
  160.     }  
  161.   
  162.     writeb(bin2bcd(tm->tm_sec),  base + S3C2410_RTCSEC);  
  163.     writeb(bin2bcd(tm->tm_min),  base + S3C2410_RTCMIN);  
  164.     writeb(bin2bcd(tm->tm_hour), base + S3C2410_RTCHOUR);  
  165.     writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE);  
  166.     writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON);  
  167.     writeb(bin2bcd(year), base + S3C2410_RTCYEAR);  
  168.   
  169.     return 0;  
  170. }  
  171.   
  172. /* 读取RTC报警时间值 */  
  173. static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)  
  174. {  
  175.     struct rtc_time *alm_tm = &alrm->time;  
  176.     void __iomem *base = s3c_rtc_base;  
  177.     unsigned int alm_en;  
  178.   
  179.     alm_tm->tm_sec  = readb(base + S3C2410_ALMSEC);  
  180.     alm_tm->tm_min  = readb(base + S3C2410_ALMMIN);  
  181.     alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR);  
  182.     alm_tm->tm_mon  = readb(base + S3C2410_ALMMON);  
  183.     alm_tm->tm_mday = readb(base + S3C2410_ALMDATE);  
  184.     alm_tm->tm_year = readb(base + S3C2410_ALMYEAR);  
  185.   
  186.     alm_en = readb(base + S3C2410_RTCALM);  
  187.   
  188.     alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;  
  189.   
  190.     pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",  
  191.          alm_en,  
  192.          alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,  
  193.          alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);  
  194.   
  195.   
  196.     /* decode the alarm enable field */  
  197.   
  198.     if (alm_en & S3C2410_RTCALM_SECEN)  
  199.         alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);  
  200.     else  
  201.         alm_tm->tm_sec = 0xff;  
  202.   
  203.     if (alm_en & S3C2410_RTCALM_MINEN)  
  204.         alm_tm->tm_min = bcd2bin(alm_tm->tm_min);  
  205.     else  
  206.         alm_tm->tm_min = 0xff;  
  207.   
  208.     if (alm_en & S3C2410_RTCALM_HOUREN)  
  209.         alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);  
  210.     else  
  211.         alm_tm->tm_hour = 0xff;  
  212.   
  213.     if (alm_en & S3C2410_RTCALM_DAYEN)  
  214.         alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);  
  215.     else  
  216.         alm_tm->tm_mday = 0xff;  
  217.   
  218.     if (alm_en & S3C2410_RTCALM_MONEN) {  
  219.         alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);  
  220.         alm_tm->tm_mon -= 1;   //这里减1有待研究,为什么只有月没有年减1   
  221.     } else {  
  222.         alm_tm->tm_mon = 0xff;  
  223.     }  
  224.   
  225.     if (alm_en & S3C2410_RTCALM_YEAREN)  
  226.         alm_tm->tm_year = bcd2bin(alm_tm->tm_year);  
  227.     else  
  228.         alm_tm->tm_year = 0xffff;  
  229.   
  230.     return 0;  
  231. }  
  232. /* 与s3c_rtc_getalarm功能相反 */  
  233. static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)  
  234. {  
  235.     struct rtc_time *tm = &alrm->time;  
  236.     void __iomem *base = s3c_rtc_base;  
  237.     unsigned int alrm_en;  
  238.   
  239.     pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",  
  240.          alrm->enabled,  
  241.          tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,  
  242.          tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);  
  243.   
  244.   
  245.     alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;  
  246.     writeb(0x00, base + S3C2410_RTCALM);  
  247.   
  248.     if (tm->tm_sec < 60 && tm->tm_sec >= 0) {  
  249.         alrm_en |= S3C2410_RTCALM_SECEN;  
  250.         writeb(bin2bcd(tm->tm_sec), base + S3C2410_ALMSEC);  
  251.     }  
  252.   
  253.     if (tm->tm_min < 60 && tm->tm_min >= 0) {  
  254.         alrm_en |= S3C2410_RTCALM_MINEN;  
  255.         writeb(bin2bcd(tm->tm_min), base + S3C2410_ALMMIN);  
  256.     }  
  257.   
  258.     if (tm->tm_hour < 24 && tm->tm_hour >= 0) {  
  259.         alrm_en |= S3C2410_RTCALM_HOUREN;  
  260.         writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR);  
  261.     }  
  262.   
  263.     pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);  
  264.   
  265.     writeb(alrm_en, base + S3C2410_RTCALM);  
  266.   
  267.     s3c_rtc_setaie(alrm->enabled);  
  268.   
  269.     /*根据全局报警使能的状态来决定是唤醒RTC报警中断还是睡眠RTC报警中断*/  
  270.     if (alrm->enabled)  
  271.         enable_irq_wake(s3c_rtc_alarmno);  
  272.     else  
  273.         disable_irq_wake(s3c_rtc_alarmno);  
  274.   
  275.     return 0;  
  276. }  
  277.   
  278. static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)  
  279. {  
  280.     unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);  
  281.   
  282.     seq_printf(seq, "periodic_IRQ\t: %s\n",  
  283.              (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );  
  284.     return 0;  
  285. }  
  286.   
  287. /*RTC设备类打开接口函数*/  
  288. static int s3c_rtc_open(struct device *dev)  
  289. {  
  290.     /*这里主要的目的是从系统平台设备中获取RTC设备类的数据,和RTC探测函数rtc_probe中 
  291.         的platform_set_drvdata(pdev, rtc)的操作刚好相反。定义在platform_device.h中*/  
  292.     struct platform_device *pdev = to_platform_device(dev);  
  293.     struct rtc_device *rtc_dev = platform_get_drvdata(pdev);  
  294.     int ret;  
  295.   
  296.     ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,  
  297.               IRQF_DISABLED,  "s3c2410-rtc alarm", rtc_dev);  
  298.   
  299.     if (ret) {  
  300.         dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);  
  301.         return ret;  
  302.     }  
  303.   
  304.     ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,  
  305.               IRQF_DISABLED,  "s3c2410-rtc tick", rtc_dev);  
  306.   
  307.     if (ret) {  
  308.         dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);  
  309.         goto tick_err;  
  310.     }  
  311.   
  312.     return ret;  
  313.   
  314.  tick_err:  
  315.     free_irq(s3c_rtc_alarmno, rtc_dev);  
  316.     return ret;  
  317. }  
  318.   
  319. static void s3c_rtc_release(struct device *dev)  
  320. {  
  321.     struct platform_device *pdev = to_platform_device(dev);  
  322.     struct rtc_device *rtc_dev = platform_get_drvdata(pdev);  
  323.   
  324.     /* do not clear AIE here, it may be needed for wake */  
  325.   
  326.     s3c_rtc_setpie(dev, 0);  
  327.     free_irq(s3c_rtc_alarmno, rtc_dev);  
  328.     free_irq(s3c_rtc_tickno, rtc_dev);  
  329. }  
  330.   
  331. /*rtc_class_ops是RTC设备类在RTC驱动核心部分中定义的对RTC设备类进行操作的结构体, 
  332.   类似字符设备在驱动中的file_operations对字符设备进行操作的意思。该结构体被定义 
  333.   在include/linux/rtc.h中,对RTC的操作主要有打开、关闭、设置或获取时间、设置或 
  334.   获取报警、设置节拍时间计数值等等,该结构体内接口函数的实现在前面*/  
  335. static const struct rtc_class_ops s3c_rtcops = {  
  336.     .open       = s3c_rtc_open,  
  337.     .release    = s3c_rtc_release,  
  338.     .read_time  = s3c_rtc_gettime,  
  339.     .set_time   = s3c_rtc_settime,  
  340.     .read_alarm = s3c_rtc_getalarm,  
  341.     .set_alarm  = s3c_rtc_setalarm,  
  342.     .irq_set_freq   = s3c_rtc_setfreq,  
  343.     .irq_set_state  = s3c_rtc_setpie,  
  344.     .proc           = s3c_rtc_proc,  
  345. };  
  346.   
  347. /* 控制RTCCON寄存器,rtc使能 */  
  348. static void s3c_rtc_enable(struct platform_device *pdev, int en)  
  349. {  
  350.     void __iomem *base = s3c_rtc_base;  
  351.     unsigned int tmp;  
  352.   
  353.     if (s3c_rtc_base == NULL)  
  354.         return;  
  355.   
  356.     if (!en) {  
  357.         tmp = readb(base + S3C2410_RTCCON);  
  358.         writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);  
  359.   
  360.         tmp = readb(base + S3C2410_TICNT);  
  361.         writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);  
  362.     } else {  
  363.         /* re-enable the device, and check it is ok */  
  364.   
  365.         if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){  
  366.             dev_info(&pdev->dev, "rtc disabled, re-enabling\n");  
  367.   
  368.             tmp = readb(base + S3C2410_RTCCON);  
  369.             writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON);  
  370.         }  
  371.   
  372.         if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){  
  373.             dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n");  
  374.   
  375.             tmp = readb(base + S3C2410_RTCCON);  
  376.             writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON);  
  377.         }  
  378.   
  379.         if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){  
  380.             dev_info(&pdev->dev, "removing RTCCON_CLKRST\n");  
  381.   
  382.             tmp = readb(base + S3C2410_RTCCON);  
  383.             writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON);  
  384.         }  
  385.     }  
  386. }  
  387.   
  388. static int __devexit s3c_rtc_remove(struct platform_device *dev)  
  389. {  
  390.     struct rtc_device *rtc = platform_get_drvdata(dev);  
  391.   
  392.     platform_set_drvdata(dev, NULL);  
  393.     rtc_device_unregister(rtc);   /*注销RTC设备类*/  
  394.   
  395.     s3c_rtc_setpie(&dev->dev, 0);    
  396.     s3c_rtc_setaie(0);  
  397.   
  398.     iounmap(s3c_rtc_base);  
  399.     release_resource(s3c_rtc_mem);  
  400.     kfree(s3c_rtc_mem);  
  401.   
  402.     return 0;  
  403. }  
  404.   
  405. static int __devinit s3c_rtc_probe(struct platform_device *pdev)  
  406. {  
  407.     struct rtc_device *rtc;  
  408.     struct resource *res;  
  409.     int ret;  
  410.   
  411.     pr_debug("%s: probe=%p\n", __func__, pdev);  
  412.   
  413.     /* find the IRQs */  
  414.   
  415.     s3c_rtc_tickno = platform_get_irq(pdev, 1);  
  416.     if (s3c_rtc_tickno < 0) {  
  417.         dev_err(&pdev->dev, "no irq for rtc tick\n");  
  418.         return -ENOENT;  
  419.     }  
  420.   
  421.     s3c_rtc_alarmno = platform_get_irq(pdev, 0);  
  422.     if (s3c_rtc_alarmno < 0) {  
  423.         dev_err(&pdev->dev, "no irq for alarm\n");  
  424.         return -ENOENT;  
  425.     }  
  426.   
  427.     pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",  
  428.          s3c_rtc_tickno, s3c_rtc_alarmno);  
  429.   
  430.     /* get the memory region */  
  431.   
  432.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  433.     if (res == NULL) {  
  434.         dev_err(&pdev->dev, "failed to get memory region resource\n");  
  435.         return -ENOENT;  
  436.     }  
  437.   
  438.     s3c_rtc_mem = request_mem_region(res->start,  
  439.                      res->end-res->start+1,  
  440.                      pdev->name);  
  441.   
  442.     if (s3c_rtc_mem == NULL) {  
  443.         dev_err(&pdev->dev, "failed to reserve memory region\n");  
  444.         ret = -ENOENT;  
  445.         goto err_nores;  
  446.     }  
  447.   
  448.     s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);  
  449.     if (s3c_rtc_base == NULL) {  
  450.         dev_err(&pdev->dev, "failed ioremap()\n");  
  451.         ret = -EINVAL;  
  452.         goto err_nomap;  
  453.     }  
  454.   
  455.     /* check to see if everything is setup correctly */  
  456.   
  457.     s3c_rtc_enable(pdev, 1);  
  458.   
  459.     pr_debug("s3c2410_rtc: RTCCON=%02x\n",  
  460.          readb(s3c_rtc_base + S3C2410_RTCCON));  
  461.   
  462.     s3c_rtc_setfreq(&pdev->dev, 1);  
  463.   
  464.     device_init_wakeup(&pdev->dev, 1);    //驱动支持电源管理   
  465.   
  466.     /* register RTC and exit */  
  467.     /*将RTC注册为RTC设备类,RTC设备类在RTC驱动核心部分中由系统定义好的,注意rtcops这个参数是一个结构体,该结构体的作用和里面的接口函数前面实现。rtc_device_register函数在rtc.h中定义,在drivers/rtc/class.c中实现*/  
  468.     rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,THIS_MODULE);  
  469.   
  470.     if (IS_ERR(rtc)) {  
  471.         dev_err(&pdev->dev, "cannot attach rtc\n");  
  472.         ret = PTR_ERR(rtc);  
  473.         goto err_nortc;  
  474.     }  
  475.   
  476.     rtc->max_user_freq = 128;  
  477.   
  478.     /*将RTC设备类的数据传递给系统平台设备。platform_set_drvdata是定义在platform_device.h的宏,如下: 
  479.          #define platform_set_drvdata(_dev,data)    dev_set_drvdata(&(_dev)->dev, (data)) 
  480.          而dev_set_drvdata又被定义在include/linux/device.h中,如下: 
  481.          static inline void dev_set_drvdata (struct device *dev, void *data) 
  482.       { 
  483.             dev->driver_data = data; 
  484.          }*/  
  485.     platform_set_drvdata(pdev, rtc);  
  486.     return 0;  
  487.   
  488.  err_nortc:  
  489.     s3c_rtc_enable(pdev, 0);  
  490.     iounmap(s3c_rtc_base);  
  491.   
  492.  err_nomap:  
  493.     release_resource(s3c_rtc_mem);  
  494.   
  495.  err_nores:  
  496.     return ret;  
  497. }  
  498.   
  499. #ifdef CONFIG_PM   
  500.   
  501. /* RTC Power management control */  
  502.   
  503. static int ticnt_save;  
  504.   
  505. static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)  
  506. {  
  507.     /* save TICNT for anyone using periodic interrupts */  
  508.     ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);  
  509.     s3c_rtc_enable(pdev, 0);  
  510.     return 0;  
  511. }  
  512.   
  513. static int s3c_rtc_resume(struct platform_device *pdev)  
  514. {  
  515.     s3c_rtc_enable(pdev, 1);  
  516.     writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);  
  517.     return 0;  
  518. }  
  519. #else   
  520. #define s3c_rtc_suspend NULL   
  521. #define s3c_rtc_resume  NULL   
  522. #endif   
  523.   
  524. static struct platform_driver s3c2410_rtc_driver = {  
  525.     .probe      = s3c_rtc_probe,  
  526.     .remove     = __devexit_p(s3c_rtc_remove),  
  527.     .suspend    = s3c_rtc_suspend,  
  528.     .resume     = s3c_rtc_resume,  
  529.     .driver     = {  
  530.         .name   = "s3c2410-rtc",  
  531.         .owner  = THIS_MODULE,  
  532.     },  
  533. };  
  534.   
  535. static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n";  
  536.   
  537. static int __init s3c_rtc_init(void)  
  538. {  
  539.     printk(banner);  
  540.     return platform_driver_register(&s3c2410_rtc_driver); //注册RTC平台驱动   
  541. }  
  542.   
  543. static void __exit s3c_rtc_exit(void)  
  544. {  
  545.     platform_driver_unregister(&s3c2410_rtc_driver);  
  546. }  
  547.   
  548. module_init(s3c_rtc_init);  
  549. module_exit(s3c_rtc_exit);  
  550.   
  551. MODULE_DESCRIPTION("Samsung S3C RTC Driver");  
  552. MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");  
  553. MODULE_LICENSE("GPL");  
  554. MODULE_ALIAS("platform:s3c2410-rtc");  

配置内核,加入RTC驱动支持

Devide drivers --->

       <*> Real Time Clock --->

              <*> Samsung S3C series SoC RTC

测试:

# cat /proc/devices   查看rtc设备号

# ls –l /dev/rtc

crw-r--r--   1  root   root  254,  0 Jan  1  1970  /dev/rtc

lrwxr--r--   1  root   root        3Jan  1  1970  /dev/rtc0 -> rtc

       date –s 072021352011   设置系统时间为2011-07-20 21:35

       hwclock –w       把刚设置的系统时间存入RTC

       开机时使用hwclock –s把RTC时间恢复到系统时间

hwclock参数说明:

Options:

        -r      Show hardware clock time

        -s      Set system time from hardware clock

        -w     Set hardware clock to system time

        -u      Hardware clock is in UTC

        -l      Hardware clock is in local time

        -f FILE Use specified device (e.g. /dev/rtc2)

相关内容