Commit 0ef1594c017521ea89278e80fe3f80dafb17abde

Authored by Nicolas Ferre
Committed by Linus Torvalds
1 parent e66b05873a

drivers/rtc/rtc-at91rm9200.c: use a variable for storing IMR

On some revisions of AT91 SoCs, the RTC IMR register is not working.
Instead of elaborating a workaround for that specific SoC or IP version,
we simply use a software variable to store the Interrupt Mask Register
and modify it for each enabling/disabling of an interrupt.  The overhead
of this is negligible anyway.

The interrupt mask register (IMR) for the RTC is broken on the AT91SAM9x5
sub-family of SoCs (good overview of the members here:
http://www.eewiki.net/display/linuxonarm/AT91SAM9x5 ).  The "user visible
effect" is the RTC doesn't work.

That sub-family is less than two years old and only has devicetree (DT)
support and came online circa lk 3.7 .  The dust is yet to settle on the
DT stuff at least for AT91 SoCs (translation: lots of stuff is still
broken, so much that it is hard to know where to start).

The fix in the patch is pretty simple: just shadow the silicon IMR
register with a variable in the driver.  Some older SoCs (pre-DT) use the
the rtc-at91rm9200 driver (e.g.  obviously the AT91RM9200) and they should
not be impacted by the change.  There shouldn't be a large volume of
interrupts associated with a RTC.

Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Reported-by: Douglas Gilbert <dgilbert@interlog.com>
Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Cc: Ludovic Desroches <ludovic.desroches@atmel.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 2 changed files with 31 additions and 20 deletions Side-by-side Diff

drivers/rtc/rtc-at91rm9200.c
... ... @@ -44,6 +44,7 @@
44 44 static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
45 45 static void __iomem *at91_rtc_regs;
46 46 static int irq;
  47 +static u32 at91_rtc_imr;
47 48  
48 49 /*
49 50 * Decode time/date into rtc_time structure
50 51  
... ... @@ -108,9 +109,11 @@
108 109 cr = at91_rtc_read(AT91_RTC_CR);
109 110 at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
110 111  
  112 + at91_rtc_imr |= AT91_RTC_ACKUPD;
111 113 at91_rtc_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
112 114 wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
113 115 at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
  116 + at91_rtc_imr &= ~AT91_RTC_ACKUPD;
114 117  
115 118 at91_rtc_write(AT91_RTC_TIMR,
116 119 bin2bcd(tm->tm_sec) << 0
... ... @@ -142,7 +145,7 @@
142 145 tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
143 146 tm->tm_year = at91_alarm_year - 1900;
144 147  
145   - alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
  148 + alrm->enabled = (at91_rtc_imr & AT91_RTC_ALARM)
146 149 ? 1 : 0;
147 150  
148 151 dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
... ... @@ -168,6 +171,7 @@
168 171 tm.tm_sec = alrm->time.tm_sec;
169 172  
170 173 at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
  174 + at91_rtc_imr &= ~AT91_RTC_ALARM;
171 175 at91_rtc_write(AT91_RTC_TIMALR,
172 176 bin2bcd(tm.tm_sec) << 0
173 177 | bin2bcd(tm.tm_min) << 8
... ... @@ -180,6 +184,7 @@
180 184  
181 185 if (alrm->enabled) {
182 186 at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
  187 + at91_rtc_imr |= AT91_RTC_ALARM;
183 188 at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
184 189 }
185 190  
186 191  
187 192  
... ... @@ -196,9 +201,12 @@
196 201  
197 202 if (enabled) {
198 203 at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
  204 + at91_rtc_imr |= AT91_RTC_ALARM;
199 205 at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
200   - } else
  206 + } else {
201 207 at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
  208 + at91_rtc_imr &= ~AT91_RTC_ALARM;
  209 + }
202 210  
203 211 return 0;
204 212 }
205 213  
206 214  
... ... @@ -207,12 +215,10 @@
207 215 */
208 216 static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
209 217 {
210   - unsigned long imr = at91_rtc_read(AT91_RTC_IMR);
211   -
212 218 seq_printf(seq, "update_IRQ\t: %s\n",
213   - (imr & AT91_RTC_ACKUPD) ? "yes" : "no");
  219 + (at91_rtc_imr & AT91_RTC_ACKUPD) ? "yes" : "no");
214 220 seq_printf(seq, "periodic_IRQ\t: %s\n",
215   - (imr & AT91_RTC_SECEV) ? "yes" : "no");
  221 + (at91_rtc_imr & AT91_RTC_SECEV) ? "yes" : "no");
216 222  
217 223 return 0;
218 224 }
... ... @@ -227,7 +233,7 @@
227 233 unsigned int rtsr;
228 234 unsigned long events = 0;
229 235  
230   - rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read(AT91_RTC_IMR);
  236 + rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_imr;
231 237 if (rtsr) { /* this interrupt is shared! Is it ours? */
232 238 if (rtsr & AT91_RTC_ALARM)
233 239 events |= (RTC_AF | RTC_IRQF);
... ... @@ -291,6 +297,7 @@
291 297 at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
292 298 AT91_RTC_SECEV | AT91_RTC_TIMEV |
293 299 AT91_RTC_CALEV);
  300 + at91_rtc_imr = 0;
294 301  
295 302 ret = request_irq(irq, at91_rtc_interrupt,
296 303 IRQF_SHARED,
... ... @@ -329,6 +336,7 @@
329 336 at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
330 337 AT91_RTC_SECEV | AT91_RTC_TIMEV |
331 338 AT91_RTC_CALEV);
  339 + at91_rtc_imr = 0;
332 340 free_irq(irq, pdev);
333 341  
334 342 rtc_device_unregister(rtc);
335 343  
336 344  
337 345  
338 346  
339 347  
... ... @@ -341,31 +349,35 @@
341 349  
342 350 /* AT91RM9200 RTC Power management control */
343 351  
344   -static u32 at91_rtc_imr;
  352 +static u32 at91_rtc_bkpimr;
345 353  
  354 +
346 355 static int at91_rtc_suspend(struct device *dev)
347 356 {
348 357 /* this IRQ is shared with DBGU and other hardware which isn't
349 358 * necessarily doing PM like we are...
350 359 */
351   - at91_rtc_imr = at91_rtc_read(AT91_RTC_IMR)
352   - & (AT91_RTC_ALARM|AT91_RTC_SECEV);
353   - if (at91_rtc_imr) {
354   - if (device_may_wakeup(dev))
  360 + at91_rtc_bkpimr = at91_rtc_imr & (AT91_RTC_ALARM|AT91_RTC_SECEV);
  361 + if (at91_rtc_bkpimr) {
  362 + if (device_may_wakeup(dev)) {
355 363 enable_irq_wake(irq);
356   - else
357   - at91_rtc_write(AT91_RTC_IDR, at91_rtc_imr);
358   - }
  364 + } else {
  365 + at91_rtc_write(AT91_RTC_IDR, at91_rtc_bkpimr);
  366 + at91_rtc_imr &= ~at91_rtc_bkpimr;
  367 + }
  368 +}
359 369 return 0;
360 370 }
361 371  
362 372 static int at91_rtc_resume(struct device *dev)
363 373 {
364   - if (at91_rtc_imr) {
365   - if (device_may_wakeup(dev))
  374 + if (at91_rtc_bkpimr) {
  375 + if (device_may_wakeup(dev)) {
366 376 disable_irq_wake(irq);
367   - else
368   - at91_rtc_write(AT91_RTC_IER, at91_rtc_imr);
  377 + } else {
  378 + at91_rtc_imr |= at91_rtc_bkpimr;
  379 + at91_rtc_write(AT91_RTC_IER, at91_rtc_bkpimr);
  380 + }
369 381 }
370 382 return 0;
371 383 }
drivers/rtc/rtc-at91rm9200.h
... ... @@ -64,7 +64,6 @@
64 64 #define AT91_RTC_SCCR 0x1c /* Status Clear Command Register */
65 65 #define AT91_RTC_IER 0x20 /* Interrupt Enable Register */
66 66 #define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
67   -#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
68 67  
69 68 #define AT91_RTC_VER 0x2c /* Valid Entry Register */
70 69 #define AT91_RTC_NVTIM (1 << 0) /* Non valid Time */