Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: at91sam9: rework wakeup and interrupt handling

The IRQ line used by the RTC device is usually shared with the system timer
(PIT) on at91 platforms.

Since timers are registering their handlers with IRQF_NO_SUSPEND, we should
expect being called in suspended state, and properly wake the system up
when this is the case.

Set IRQF_COND_SUSPEND flag when registering the IRQ handler to inform
irq core that it can safely be called while the system is suspended.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Boris BREZILLON and committed by
Rafael J. Wysocki
603b1a23 432ec92b

+63 -14
+63 -14
drivers/rtc/rtc-at91sam9.c
··· 23 23 #include <linux/io.h> 24 24 #include <linux/mfd/syscon.h> 25 25 #include <linux/regmap.h> 26 + #include <linux/suspend.h> 26 27 #include <linux/clk.h> 27 28 28 29 /* ··· 78 77 unsigned int gpbr_offset; 79 78 int irq; 80 79 struct clk *sclk; 80 + bool suspended; 81 + unsigned long events; 82 + spinlock_t lock; 81 83 }; 82 84 83 85 #define rtt_readl(rtc, field) \ ··· 275 271 return 0; 276 272 } 277 273 278 - /* 279 - * IRQ handler for the RTC 280 - */ 281 - static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) 274 + static irqreturn_t at91_rtc_cache_events(struct sam9_rtc *rtc) 282 275 { 283 - struct sam9_rtc *rtc = _rtc; 284 276 u32 sr, mr; 285 - unsigned long events = 0; 286 277 287 278 /* Shared interrupt may be for another device. Note: reading 288 279 * SR clears it, so we must only read it in this irq handler! ··· 289 290 290 291 /* alarm status */ 291 292 if (sr & AT91_RTT_ALMS) 292 - events |= (RTC_AF | RTC_IRQF); 293 + rtc->events |= (RTC_AF | RTC_IRQF); 293 294 294 295 /* timer update/increment */ 295 296 if (sr & AT91_RTT_RTTINC) 296 - events |= (RTC_UF | RTC_IRQF); 297 - 298 - rtc_update_irq(rtc->rtcdev, 1, events); 299 - 300 - pr_debug("%s: num=%ld, events=0x%02lx\n", __func__, 301 - events >> 8, events & 0x000000FF); 297 + rtc->events |= (RTC_UF | RTC_IRQF); 302 298 303 299 return IRQ_HANDLED; 300 + } 301 + 302 + static void at91_rtc_flush_events(struct sam9_rtc *rtc) 303 + { 304 + if (!rtc->events) 305 + return; 306 + 307 + rtc_update_irq(rtc->rtcdev, 1, rtc->events); 308 + rtc->events = 0; 309 + 310 + pr_debug("%s: num=%ld, events=0x%02lx\n", __func__, 311 + rtc->events >> 8, rtc->events & 0x000000FF); 312 + } 313 + 314 + /* 315 + * IRQ handler for the RTC 316 + */ 317 + static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) 318 + { 319 + struct sam9_rtc *rtc = _rtc; 320 + int ret; 321 + 322 + spin_lock(&rtc->lock); 323 + 324 + ret = at91_rtc_cache_events(rtc); 325 + 326 + /* We're called in suspended state */ 327 + if (rtc->suspended) { 328 + /* Mask irqs coming from this peripheral */ 329 + rtt_writel(rtc, MR, 330 + rtt_readl(rtc, MR) & 331 + ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); 332 + /* Trigger a system wakeup */ 333 + pm_system_wakeup(); 334 + } else { 335 + at91_rtc_flush_events(rtc); 336 + } 337 + 338 + spin_unlock(&rtc->lock); 339 + 340 + return ret; 304 341 } 305 342 306 343 static const struct rtc_class_ops at91_rtc_ops = { ··· 456 421 457 422 /* register irq handler after we know what name we'll use */ 458 423 ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt, 459 - IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc); 424 + IRQF_SHARED | IRQF_COND_SUSPEND, 425 + dev_name(&rtc->rtcdev->dev), rtc); 460 426 if (ret) { 461 427 dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq); 462 428 return ret; ··· 518 482 rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); 519 483 if (rtc->imr) { 520 484 if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) { 485 + unsigned long flags; 486 + 521 487 enable_irq_wake(rtc->irq); 488 + spin_lock_irqsave(&rtc->lock, flags); 489 + rtc->suspended = true; 490 + spin_unlock_irqrestore(&rtc->lock, flags); 522 491 /* don't let RTTINC cause wakeups */ 523 492 if (mr & AT91_RTT_RTTINCIEN) 524 493 rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); ··· 540 499 u32 mr; 541 500 542 501 if (rtc->imr) { 502 + unsigned long flags; 503 + 543 504 if (device_may_wakeup(dev)) 544 505 disable_irq_wake(rtc->irq); 545 506 mr = rtt_readl(rtc, MR); 546 507 rtt_writel(rtc, MR, mr | rtc->imr); 508 + 509 + spin_lock_irqsave(&rtc->lock, flags); 510 + rtc->suspended = false; 511 + at91_rtc_cache_events(rtc); 512 + at91_rtc_flush_events(rtc); 513 + spin_unlock_irqrestore(&rtc->lock, flags); 547 514 } 548 515 549 516 return 0;