📄 rtc-sh.c
字号:
tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900; sec2 = readb(rtc->regbase + R64CNT); cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF; spin_unlock_irq(&rtc->lock); } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);#if RTC_BIT_INVERTED != 0 if ((sec128 & RTC_BIT_INVERTED)) tm->tm_sec--;#endif dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); if (rtc_valid_tm(tm) < 0) { dev_err(dev, "invalid date\n"); rtc_time_to_tm(0, tm); } return 0;}static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm){ struct platform_device *pdev = to_platform_device(dev); struct sh_rtc *rtc = platform_get_drvdata(pdev); unsigned int tmp; int year; spin_lock_irq(&rtc->lock); /* Reset pre-scaler & stop RTC */ tmp = readb(rtc->regbase + RCR2); tmp |= RCR2_RESET; tmp &= ~RCR2_START; writeb(tmp, rtc->regbase + RCR2); writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT); writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT); writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT); writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT); writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT); writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT); if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | BIN2BCD(tm->tm_year % 100); writew(year, rtc->regbase + RYRCNT); } else { year = tm->tm_year % 100; writeb(BIN2BCD(year), rtc->regbase + RYRCNT); } /* Start RTC */ tmp = readb(rtc->regbase + RCR2); tmp &= ~RCR2_RESET; tmp |= RCR2_RTCEN | RCR2_START; writeb(tmp, rtc->regbase + RCR2); spin_unlock_irq(&rtc->lock); return 0;}static inline int sh_rtc_read_alarm_value(struct sh_rtc *rtc, int reg_off){ unsigned int byte; int value = 0xff; /* return 0xff for ignored values */ byte = readb(rtc->regbase + reg_off); if (byte & AR_ENB) { byte &= ~AR_ENB; /* strip the enable bit */ value = BCD2BIN(byte); } return value;}static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm){ struct platform_device *pdev = to_platform_device(dev); struct sh_rtc *rtc = platform_get_drvdata(pdev); struct rtc_time* tm = &wkalrm->time; spin_lock_irq(&rtc->lock); tm->tm_sec = sh_rtc_read_alarm_value(rtc, RSECAR); tm->tm_min = sh_rtc_read_alarm_value(rtc, RMINAR); tm->tm_hour = sh_rtc_read_alarm_value(rtc, RHRAR); tm->tm_wday = sh_rtc_read_alarm_value(rtc, RWKAR); tm->tm_mday = sh_rtc_read_alarm_value(rtc, RDAYAR); tm->tm_mon = sh_rtc_read_alarm_value(rtc, RMONAR); if (tm->tm_mon > 0) tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ tm->tm_year = 0xffff; wkalrm->enabled = (readb(rtc->regbase + RCR1) & RCR1_AIE) ? 1 : 0; spin_unlock_irq(&rtc->lock); return 0;}static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc, int value, int reg_off){ /* < 0 for a value that is ignored */ if (value < 0) writeb(0, rtc->regbase + reg_off); else writeb(BIN2BCD(value) | AR_ENB, rtc->regbase + reg_off);}static int sh_rtc_check_alarm(struct rtc_time* tm){ /* * The original rtc says anything > 0xc0 is "don't care" or "match * all" - most users use 0xff but rtc-dev uses -1 for the same thing. * The original rtc doesn't support years - some things use -1 and * some 0xffff. We use -1 to make out tests easier. */ if (tm->tm_year == 0xffff) tm->tm_year = -1; if (tm->tm_mon >= 0xff) tm->tm_mon = -1; if (tm->tm_mday >= 0xff) tm->tm_mday = -1; if (tm->tm_wday >= 0xff) tm->tm_wday = -1; if (tm->tm_hour >= 0xff) tm->tm_hour = -1; if (tm->tm_min >= 0xff) tm->tm_min = -1; if (tm->tm_sec >= 0xff) tm->tm_sec = -1; if (tm->tm_year > 9999 || tm->tm_mon >= 12 || tm->tm_mday == 0 || tm->tm_mday >= 32 || tm->tm_wday >= 7 || tm->tm_hour >= 24 || tm->tm_min >= 60 || tm->tm_sec >= 60) return -EINVAL; return 0;}static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm){ struct platform_device *pdev = to_platform_device(dev); struct sh_rtc *rtc = platform_get_drvdata(pdev); unsigned int rcr1; struct rtc_time *tm = &wkalrm->time; int mon, err; err = sh_rtc_check_alarm(tm); if (unlikely(err < 0)) return err; spin_lock_irq(&rtc->lock); /* disable alarm interrupt and clear the alarm flag */ rcr1 = readb(rtc->regbase + RCR1); rcr1 &= ~(RCR1_AF|RCR1_AIE); writeb(rcr1, rtc->regbase + RCR1); rtc->rearm_aie = 0; /* set alarm time */ sh_rtc_write_alarm_value(rtc, tm->tm_sec, RSECAR); sh_rtc_write_alarm_value(rtc, tm->tm_min, RMINAR); sh_rtc_write_alarm_value(rtc, tm->tm_hour, RHRAR); sh_rtc_write_alarm_value(rtc, tm->tm_wday, RWKAR); sh_rtc_write_alarm_value(rtc, tm->tm_mday, RDAYAR); mon = tm->tm_mon; if (mon >= 0) mon += 1; sh_rtc_write_alarm_value(rtc, mon, RMONAR); if (wkalrm->enabled) { rcr1 |= RCR1_AIE; writeb(rcr1, rtc->regbase + RCR1); } spin_unlock_irq(&rtc->lock); return 0;}static struct rtc_class_ops sh_rtc_ops = { .open = sh_rtc_open, .release = sh_rtc_release, .ioctl = sh_rtc_ioctl, .read_time = sh_rtc_read_time, .set_time = sh_rtc_set_time, .read_alarm = sh_rtc_read_alarm, .set_alarm = sh_rtc_set_alarm, .proc = sh_rtc_proc,};static int __devinit sh_rtc_probe(struct platform_device *pdev){ struct sh_rtc *rtc; struct resource *res; int ret = -ENOENT; rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); if (unlikely(!rtc)) return -ENOMEM; spin_lock_init(&rtc->lock); rtc->periodic_irq = platform_get_irq(pdev, 0); if (unlikely(rtc->periodic_irq < 0)) { dev_err(&pdev->dev, "No IRQ for period\n"); goto err_badres; } rtc->carry_irq = platform_get_irq(pdev, 1); if (unlikely(rtc->carry_irq < 0)) { dev_err(&pdev->dev, "No IRQ for carry\n"); goto err_badres; } rtc->alarm_irq = platform_get_irq(pdev, 2); if (unlikely(rtc->alarm_irq < 0)) { dev_err(&pdev->dev, "No IRQ for alarm\n"); goto err_badres; } res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (unlikely(res == NULL)) { dev_err(&pdev->dev, "No IO resource\n"); goto err_badres; } rtc->regsize = res->end - res->start + 1; rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name); if (unlikely(!rtc->res)) { ret = -EBUSY; goto err_badres; } rtc->regbase = (void __iomem *)rtc->res->start; if (unlikely(!rtc->regbase)) { ret = -EINVAL; goto err_badmap; } rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, &sh_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc_dev)) { ret = PTR_ERR(rtc->rtc_dev); goto err_badmap; } rtc->capabilities = RTC_DEF_CAPABILITIES; if (pdev->dev.platform_data) { struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data; /* * Some CPUs have special capabilities in addition to the * default set. Add those in here. */ rtc->capabilities |= pinfo->capabilities; } platform_set_drvdata(pdev, rtc); return 0;err_badmap: release_resource(rtc->res);err_badres: kfree(rtc); return ret;}static int __devexit sh_rtc_remove(struct platform_device *pdev){ struct sh_rtc *rtc = platform_get_drvdata(pdev); if (likely(rtc->rtc_dev)) rtc_device_unregister(rtc->rtc_dev); sh_rtc_setpie(&pdev->dev, 0); sh_rtc_setaie(&pdev->dev, 0); release_resource(rtc->res); platform_set_drvdata(pdev, NULL); kfree(rtc); return 0;}static struct platform_driver sh_rtc_platform_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, }, .probe = sh_rtc_probe, .remove = __devexit_p(sh_rtc_remove),};static int __init sh_rtc_init(void){ return platform_driver_register(&sh_rtc_platform_driver);}static void __exit sh_rtc_exit(void){ platform_driver_unregister(&sh_rtc_platform_driver);}module_init(sh_rtc_init);module_exit(sh_rtc_exit);MODULE_DESCRIPTION("SuperH on-chip RTC driver");MODULE_VERSION(DRV_VERSION);MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, Jamie Lenehan <lenehan@twibble.org>");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -