X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Frtc%2Frtc-sa1100.c;h=e4a44b641702677ba99884f03089477f1c04f3cd;hb=a835fb30954fe92a569206f9f684a755fbed395c;hp=439c41aea31c9d091bcfe66f326d2ba3afdd2679;hpb=ff8371ac9a5a55c956991fed8e5f58640c7a32f3;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 439c41a..e4a44b6 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -9,7 +9,7 @@ * * Modifications from: * CIH - * Nicolas Pitre + * Nicolas Pitre * Andrew Christian * * Converted to the RTC subsystem and Driver Model @@ -29,24 +29,60 @@ #include #include #include +#include -#include -#include +#include #include -#include #ifdef CONFIG_ARCH_PXA -#include +#include +#include #endif -#define TIMER_FREQ CLOCK_TICK_RATE #define RTC_DEF_DIVIDER 32768 - 1 #define RTC_DEF_TRIM 0 static unsigned long rtc_freq = 1024; +static unsigned long timer_freq; static struct rtc_time rtc_alarm; static DEFINE_SPINLOCK(sa1100_rtc_lock); +static inline int rtc_periodic_alarm(struct rtc_time *tm) +{ + return (tm->tm_year == -1) || + ((unsigned)tm->tm_mon >= 12) || + ((unsigned)(tm->tm_mday - 1) >= 31) || + ((unsigned)tm->tm_hour > 23) || + ((unsigned)tm->tm_min > 59) || + ((unsigned)tm->tm_sec > 59); +} + +/* + * Calculate the next alarm time given the requested alarm time mask + * and the current time. + */ +static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm) +{ + unsigned long next_time; + unsigned long now_time; + + next->tm_year = now->tm_year; + next->tm_mon = now->tm_mon; + next->tm_mday = now->tm_mday; + next->tm_hour = alrm->tm_hour; + next->tm_min = alrm->tm_min; + next->tm_sec = alrm->tm_sec; + + rtc_tm_to_time(now, &now_time); + rtc_tm_to_time(next, &next_time); + + if (next_time < now_time) { + /* Advance one day */ + next_time += 60 * 60 * 24; + rtc_time_to_tm(next_time, next); + } +} + static int rtc_update_alarm(struct rtc_time *alrm) { struct rtc_time alarm_tm, now_tm; @@ -68,8 +104,7 @@ static int rtc_update_alarm(struct rtc_time *alrm) return ret; } -static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) { struct platform_device *pdev = to_platform_device(dev_id); struct rtc_device *rtc = platform_get_drvdata(pdev); @@ -94,7 +129,7 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id, if (rtsr & RTSR_HZ) events |= RTC_UF | RTC_IRQF; - rtc_update_irq(&rtc->class_dev, 1, events); + rtc_update_irq(rtc, 1, events); if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm)) rtc_update_alarm(&rtc_alarm); @@ -106,8 +141,7 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id, static int rtc_timer1_count; -static irqreturn_t timer1_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t timer1_interrupt(int irq, void *dev_id) { struct platform_device *pdev = to_platform_device(dev_id); struct rtc_device *rtc = platform_get_drvdata(pdev); @@ -121,10 +155,10 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id, */ OSSR = OSSR_M1; /* clear match on timer1 */ - rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF); + rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF); if (rtc_timer1_count == 1) - rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))); + rtc_timer1_count = (rtc_freq * ((1 << 30) / (timer_freq >> 2))); return IRQ_HANDLED; } @@ -133,7 +167,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data) { if (data & RTC_PF) { /* interpolate missed periods and set match for the next */ - unsigned long period = TIMER_FREQ/rtc_freq; + unsigned long period = timer_freq / rtc_freq; unsigned long oscr = OSCR; unsigned long osmr1 = OSMR1; unsigned long missed = (oscr - osmr1)/period; @@ -230,7 +264,7 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, return 0; case RTC_PIE_ON: spin_lock_irq(&sa1100_rtc_lock); - OSMR1 = TIMER_FREQ/rtc_freq + OSCR; + OSMR1 = timer_freq / rtc_freq + OSCR; OIER |= OIER_E1; rtc_timer1_count = 1; spin_unlock_irq(&sa1100_rtc_lock); @@ -238,7 +272,7 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, case RTC_IRQP_READ: return put_user(rtc_freq, (unsigned long *)arg); case RTC_IRQP_SET: - if (arg < 1 || arg > TIMER_FREQ) + if (arg < 1 || arg > timer_freq) return -EINVAL; rtc_freq = arg; return 0; @@ -265,8 +299,12 @@ static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { + u32 rtsr; + memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time)); - alrm->pending = RTSR & RTSR_AL ? 1 : 0; + rtsr = RTSR; + alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; + alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; return 0; } @@ -277,12 +315,10 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) spin_lock_irq(&sa1100_rtc_lock); ret = rtc_update_alarm(&alrm->time); if (ret == 0) { - memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time)); - if (alrm->enabled) - enable_irq_wake(IRQ_RTCAlrm); + RTSR |= RTSR_ALE; else - disable_irq_wake(IRQ_RTCAlrm); + RTSR &= ~RTSR_ALE; } spin_unlock_irq(&sa1100_rtc_lock); @@ -291,9 +327,7 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) { - seq_printf(seq, "trim/divider\t: 0x%08lx\n", RTTR); - seq_printf(seq, "alarm_IRQ\t: %s\n", - (RTSR & RTSR_ALE) ? "yes" : "no" ); + seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR); seq_printf(seq, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no"); seq_printf(seq, "periodic_IRQ\t: %s\n", @@ -319,6 +353,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; + timer_freq = get_clock_tick_rate(); + /* * According to the manual we should be able to let RTTR be zero * and then a default diviser for a 32.768KHz clock is used. @@ -333,6 +369,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) RCNR = 0; } + device_init_wakeup(&pdev->dev, 1); + rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, THIS_MODULE); @@ -354,11 +392,35 @@ static int sa1100_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int sa1100_rtc_suspend(struct device *dev) +{ + if (device_may_wakeup(dev)) + enable_irq_wake(IRQ_RTCAlrm); + return 0; +} + +static int sa1100_rtc_resume(struct device *dev) +{ + if (device_may_wakeup(dev)) + disable_irq_wake(IRQ_RTCAlrm); + return 0; +} + +static const struct dev_pm_ops sa1100_rtc_pm_ops = { + .suspend = sa1100_rtc_suspend, + .resume = sa1100_rtc_resume, +}; +#endif + static struct platform_driver sa1100_rtc_driver = { .probe = sa1100_rtc_probe, .remove = sa1100_rtc_remove, .driver = { - .name = "sa1100-rtc", + .name = "sa1100-rtc", +#ifdef CONFIG_PM + .pm = &sa1100_rtc_pm_ops, +#endif }, }; @@ -378,3 +440,4 @@ module_exit(sa1100_rtc_exit); MODULE_AUTHOR("Richard Purdie "); MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sa1100-rtc");