diff options
| author | Marcelo Roberto Jimenez <mroberto@cpti.cetuc.puc-rio.br> | 2010-10-18 17:35:54 -0400 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-11-10 08:34:45 -0500 |
| commit | 7decaa557a20f48aabef35f817ec16ef563567b0 (patch) | |
| tree | c5b5bed714af85ff5715d81c6fd3807b3d0b3888 /drivers/rtc | |
| parent | fd3ee6d3421bc05ce42ee7f48071aee72051af28 (diff) | |
ARM: 6454/1: sa1100: Fix for a nasty initialization bug in the RTSR.
This patch fixes a nasty initialization condition on the RTSR register.
Sometimes, bit 1 will wake up set, sometimes not. This can be seen
by checking the value of the RTSR by typing '$ cat /proc/driver/rtc',
which has been provided by the previous patch.
If this bit is set, the command '$ cat /dev/rtc0' will lock the system
in an endless interrupt routine calling loop.
This patch fixes the issue both at sa1100_rtc_probe(), where it avoids
a spurious interrupt from happening, and at sa1100_rtc_interrupt(),
which is the robust solution, though it does not avoid the first
spurious interrupt.
Signed-off-by: Marcelo Roberto Jimenez <mroberto@cpti.cetuc.puc-rio.br>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/rtc-sa1100.c | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index b04c8374a279..b0985f727078 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c | |||
| @@ -117,7 +117,23 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | |||
| 117 | rtsr = RTSR; | 117 | rtsr = RTSR; |
| 118 | /* clear interrupt sources */ | 118 | /* clear interrupt sources */ |
| 119 | RTSR = 0; | 119 | RTSR = 0; |
| 120 | RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); | 120 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. |
| 121 | * See also the comments in sa1100_rtc_probe(). */ | ||
| 122 | if (rtsr & (RTSR_ALE | RTSR_HZE)) { | ||
| 123 | /* This is the original code, before there was the if test | ||
| 124 | * above. This code does not clear interrupts that were not | ||
| 125 | * enabled. */ | ||
| 126 | RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); | ||
| 127 | } else { | ||
| 128 | /* For some reason, it is possible to enter this routine | ||
| 129 | * without interruptions enabled, it has been tested with | ||
| 130 | * several units (Bug in SA11xx chip?). | ||
| 131 | * | ||
| 132 | * This situation leads to an infinite "loop" of interrupt | ||
| 133 | * routine calling and as a result the processor seems to | ||
| 134 | * lock on its first call to open(). */ | ||
| 135 | RTSR = RTSR_AL | RTSR_HZ; | ||
| 136 | } | ||
| 121 | 137 | ||
| 122 | /* clear alarm interrupt if it has occurred */ | 138 | /* clear alarm interrupt if it has occurred */ |
| 123 | if (rtsr & RTSR_AL) | 139 | if (rtsr & RTSR_AL) |
| @@ -382,6 +398,30 @@ static int sa1100_rtc_probe(struct platform_device *pdev) | |||
| 382 | 398 | ||
| 383 | platform_set_drvdata(pdev, rtc); | 399 | platform_set_drvdata(pdev, rtc); |
| 384 | 400 | ||
| 401 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. | ||
| 402 | * See also the comments in sa1100_rtc_interrupt(). | ||
| 403 | * | ||
| 404 | * Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an | ||
| 405 | * interrupt pending, even though interrupts were never enabled. | ||
| 406 | * In this case, this bit it must be reset before enabling | ||
| 407 | * interruptions to avoid a nonexistent interrupt to occur. | ||
| 408 | * | ||
| 409 | * In principle, the same problem would apply to bit 0, although it has | ||
| 410 | * never been observed to happen. | ||
| 411 | * | ||
| 412 | * This issue is addressed both here and in sa1100_rtc_interrupt(). | ||
| 413 | * If the issue is not addressed here, in the times when the processor | ||
| 414 | * wakes up with the bit set there will be one spurious interrupt. | ||
| 415 | * | ||
| 416 | * The issue is also dealt with in sa1100_rtc_interrupt() to be on the | ||
| 417 | * safe side, once the condition that lead to this strange | ||
| 418 | * initialization is unknown and could in principle happen during | ||
| 419 | * normal processing. | ||
| 420 | * | ||
| 421 | * Notice that clearing bit 1 and 0 is accomplished by writting ONES to | ||
| 422 | * the corresponding bits in RTSR. */ | ||
| 423 | RTSR = RTSR_AL | RTSR_HZ; | ||
| 424 | |||
| 385 | return 0; | 425 | return 0; |
| 386 | } | 426 | } |
| 387 | 427 | ||
