mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-11 13:04:03 +08:00
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>
This commit is contained in:
parent
fd3ee6d342
commit
7decaa557a
@ -117,7 +117,23 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
|
||||
rtsr = RTSR;
|
||||
/* clear interrupt sources */
|
||||
RTSR = 0;
|
||||
RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
|
||||
/* Fix for a nasty initialization problem the in SA11xx RTSR register.
|
||||
* See also the comments in sa1100_rtc_probe(). */
|
||||
if (rtsr & (RTSR_ALE | RTSR_HZE)) {
|
||||
/* This is the original code, before there was the if test
|
||||
* above. This code does not clear interrupts that were not
|
||||
* enabled. */
|
||||
RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
|
||||
} else {
|
||||
/* For some reason, it is possible to enter this routine
|
||||
* without interruptions enabled, it has been tested with
|
||||
* several units (Bug in SA11xx chip?).
|
||||
*
|
||||
* This situation leads to an infinite "loop" of interrupt
|
||||
* routine calling and as a result the processor seems to
|
||||
* lock on its first call to open(). */
|
||||
RTSR = RTSR_AL | RTSR_HZ;
|
||||
}
|
||||
|
||||
/* clear alarm interrupt if it has occurred */
|
||||
if (rtsr & RTSR_AL)
|
||||
@ -382,6 +398,30 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
/* Fix for a nasty initialization problem the in SA11xx RTSR register.
|
||||
* See also the comments in sa1100_rtc_interrupt().
|
||||
*
|
||||
* Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an
|
||||
* interrupt pending, even though interrupts were never enabled.
|
||||
* In this case, this bit it must be reset before enabling
|
||||
* interruptions to avoid a nonexistent interrupt to occur.
|
||||
*
|
||||
* In principle, the same problem would apply to bit 0, although it has
|
||||
* never been observed to happen.
|
||||
*
|
||||
* This issue is addressed both here and in sa1100_rtc_interrupt().
|
||||
* If the issue is not addressed here, in the times when the processor
|
||||
* wakes up with the bit set there will be one spurious interrupt.
|
||||
*
|
||||
* The issue is also dealt with in sa1100_rtc_interrupt() to be on the
|
||||
* safe side, once the condition that lead to this strange
|
||||
* initialization is unknown and could in principle happen during
|
||||
* normal processing.
|
||||
*
|
||||
* Notice that clearing bit 1 and 0 is accomplished by writting ONES to
|
||||
* the corresponding bits in RTSR. */
|
||||
RTSR = RTSR_AL | RTSR_HZ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user