diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2008-07-24 00:30:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-24 13:47:34 -0400 |
commit | 449321b39f6c6ebfa15d6da24f134240bd51db29 (patch) | |
tree | 8ec83906bfc53883cf3da71e9e3eb8b2765eb581 /drivers/rtc/rtc-at91rm9200.c | |
parent | 773be7ee97c11fbb6b8a912a58b268dbe8a6a3fe (diff) |
rtc-at91rm9200: avoid spurious irqs
This fixes kernel http://bugzilla.kernel.org/show_bug.cgi?id=11112 (bogus
RTC update IRQs reported) for rtc-at91rm9200 by scrubbing old IRQ status
before enabling IRQs.
It also removes nonfunctional periodic IRQ support from this driver;
only update IRQs are reported, or provided by the hardware.
I suspect some other RTCs probably have versions of #11112; it's easy to
overlook, since most non-RTC drivers don't care about spurious IRQs:
they're not reported to userspace.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Report-by: W Unruh <unruh@physics.ubc.ca>
Cc: Andrew Victor <avictor.za@gmail.com>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc/rtc-at91rm9200.c')
-rw-r--r-- | drivers/rtc/rtc-at91rm9200.c | 16 |
1 files changed, 6 insertions, 10 deletions
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 9c3db934cc24..cd32d05db773 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c | |||
@@ -171,8 +171,10 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
171 | | BIN2BCD(tm.tm_mday) << 24 | 171 | | BIN2BCD(tm.tm_mday) << 24 |
172 | | AT91_RTC_DATEEN | AT91_RTC_MTHEN); | 172 | | AT91_RTC_DATEEN | AT91_RTC_MTHEN); |
173 | 173 | ||
174 | if (alrm->enabled) | 174 | if (alrm->enabled) { |
175 | at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM); | ||
175 | at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); | 176 | at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); |
177 | } | ||
176 | 178 | ||
177 | pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, | 179 | pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, |
178 | at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, | 180 | at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, |
@@ -191,28 +193,22 @@ static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, | |||
191 | 193 | ||
192 | pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __func__, cmd, arg); | 194 | pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __func__, cmd, arg); |
193 | 195 | ||
196 | /* important: scrub old status before enabling IRQs */ | ||
194 | switch (cmd) { | 197 | switch (cmd) { |
195 | case RTC_AIE_OFF: /* alarm off */ | 198 | case RTC_AIE_OFF: /* alarm off */ |
196 | at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM); | 199 | at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM); |
197 | break; | 200 | break; |
198 | case RTC_AIE_ON: /* alarm on */ | 201 | case RTC_AIE_ON: /* alarm on */ |
202 | at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM); | ||
199 | at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); | 203 | at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM); |
200 | break; | 204 | break; |
201 | case RTC_UIE_OFF: /* update off */ | 205 | case RTC_UIE_OFF: /* update off */ |
202 | case RTC_PIE_OFF: /* periodic off */ | ||
203 | at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV); | 206 | at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV); |
204 | break; | 207 | break; |
205 | case RTC_UIE_ON: /* update on */ | 208 | case RTC_UIE_ON: /* update on */ |
206 | case RTC_PIE_ON: /* periodic on */ | 209 | at91_sys_write(AT91_RTC_SCCR, AT91_RTC_SECEV); |
207 | at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV); | 210 | at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV); |
208 | break; | 211 | break; |
209 | case RTC_IRQP_READ: /* read periodic alarm frequency */ | ||
210 | ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg); | ||
211 | break; | ||
212 | case RTC_IRQP_SET: /* set periodic alarm frequency */ | ||
213 | if (arg != AT91_RTC_FREQ) | ||
214 | ret = -EINVAL; | ||
215 | break; | ||
216 | default: | 212 | default: |
217 | ret = -ENOIOCTLCMD; | 213 | ret = -ENOIOCTLCMD; |
218 | break; | 214 | break; |