diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-at91rm9200.c | 62 | ||||
-rw-r--r-- | drivers/rtc/rtc-at91sam9.c | 73 | ||||
-rw-r--r-- | drivers/rtc/rtc-mrst.c | 17 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 1 |
4 files changed, 119 insertions, 34 deletions
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 70a5d94cc766..b283a1a573b3 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/io.h> | 31 | #include <linux/io.h> |
32 | #include <linux/of.h> | 32 | #include <linux/of.h> |
33 | #include <linux/of_device.h> | 33 | #include <linux/of_device.h> |
34 | #include <linux/suspend.h> | ||
34 | #include <linux/uaccess.h> | 35 | #include <linux/uaccess.h> |
35 | 36 | ||
36 | #include "rtc-at91rm9200.h" | 37 | #include "rtc-at91rm9200.h" |
@@ -54,6 +55,10 @@ static void __iomem *at91_rtc_regs; | |||
54 | static int irq; | 55 | static int irq; |
55 | static DEFINE_SPINLOCK(at91_rtc_lock); | 56 | static DEFINE_SPINLOCK(at91_rtc_lock); |
56 | static u32 at91_rtc_shadow_imr; | 57 | static u32 at91_rtc_shadow_imr; |
58 | static bool suspended; | ||
59 | static DEFINE_SPINLOCK(suspended_lock); | ||
60 | static unsigned long cached_events; | ||
61 | static u32 at91_rtc_imr; | ||
57 | 62 | ||
58 | static void at91_rtc_write_ier(u32 mask) | 63 | static void at91_rtc_write_ier(u32 mask) |
59 | { | 64 | { |
@@ -290,7 +295,9 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) | |||
290 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 295 | struct rtc_device *rtc = platform_get_drvdata(pdev); |
291 | unsigned int rtsr; | 296 | unsigned int rtsr; |
292 | unsigned long events = 0; | 297 | unsigned long events = 0; |
298 | int ret = IRQ_NONE; | ||
293 | 299 | ||
300 | spin_lock(&suspended_lock); | ||
294 | rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read_imr(); | 301 | rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read_imr(); |
295 | if (rtsr) { /* this interrupt is shared! Is it ours? */ | 302 | if (rtsr) { /* this interrupt is shared! Is it ours? */ |
296 | if (rtsr & AT91_RTC_ALARM) | 303 | if (rtsr & AT91_RTC_ALARM) |
@@ -304,14 +311,22 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) | |||
304 | 311 | ||
305 | at91_rtc_write(AT91_RTC_SCCR, rtsr); /* clear status reg */ | 312 | at91_rtc_write(AT91_RTC_SCCR, rtsr); /* clear status reg */ |
306 | 313 | ||
307 | rtc_update_irq(rtc, 1, events); | 314 | if (!suspended) { |
315 | rtc_update_irq(rtc, 1, events); | ||
308 | 316 | ||
309 | dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__, | 317 | dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", |
310 | events >> 8, events & 0x000000FF); | 318 | __func__, events >> 8, events & 0x000000FF); |
319 | } else { | ||
320 | cached_events |= events; | ||
321 | at91_rtc_write_idr(at91_rtc_imr); | ||
322 | pm_system_wakeup(); | ||
323 | } | ||
311 | 324 | ||
312 | return IRQ_HANDLED; | 325 | ret = IRQ_HANDLED; |
313 | } | 326 | } |
314 | return IRQ_NONE; /* not handled */ | 327 | spin_unlock(&suspended_lock); |
328 | |||
329 | return ret; | ||
315 | } | 330 | } |
316 | 331 | ||
317 | static const struct at91_rtc_config at91rm9200_config = { | 332 | static const struct at91_rtc_config at91rm9200_config = { |
@@ -401,8 +416,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev) | |||
401 | AT91_RTC_CALEV); | 416 | AT91_RTC_CALEV); |
402 | 417 | ||
403 | ret = devm_request_irq(&pdev->dev, irq, at91_rtc_interrupt, | 418 | ret = devm_request_irq(&pdev->dev, irq, at91_rtc_interrupt, |
404 | IRQF_SHARED, | 419 | IRQF_SHARED | IRQF_COND_SUSPEND, |
405 | "at91_rtc", pdev); | 420 | "at91_rtc", pdev); |
406 | if (ret) { | 421 | if (ret) { |
407 | dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); | 422 | dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); |
408 | return ret; | 423 | return ret; |
@@ -454,8 +469,6 @@ static void at91_rtc_shutdown(struct platform_device *pdev) | |||
454 | 469 | ||
455 | /* AT91RM9200 RTC Power management control */ | 470 | /* AT91RM9200 RTC Power management control */ |
456 | 471 | ||
457 | static u32 at91_rtc_imr; | ||
458 | |||
459 | static int at91_rtc_suspend(struct device *dev) | 472 | static int at91_rtc_suspend(struct device *dev) |
460 | { | 473 | { |
461 | /* this IRQ is shared with DBGU and other hardware which isn't | 474 | /* this IRQ is shared with DBGU and other hardware which isn't |
@@ -464,21 +477,42 @@ static int at91_rtc_suspend(struct device *dev) | |||
464 | at91_rtc_imr = at91_rtc_read_imr() | 477 | at91_rtc_imr = at91_rtc_read_imr() |
465 | & (AT91_RTC_ALARM|AT91_RTC_SECEV); | 478 | & (AT91_RTC_ALARM|AT91_RTC_SECEV); |
466 | if (at91_rtc_imr) { | 479 | if (at91_rtc_imr) { |
467 | if (device_may_wakeup(dev)) | 480 | if (device_may_wakeup(dev)) { |
481 | unsigned long flags; | ||
482 | |||
468 | enable_irq_wake(irq); | 483 | enable_irq_wake(irq); |
469 | else | 484 | |
485 | spin_lock_irqsave(&suspended_lock, flags); | ||
486 | suspended = true; | ||
487 | spin_unlock_irqrestore(&suspended_lock, flags); | ||
488 | } else { | ||
470 | at91_rtc_write_idr(at91_rtc_imr); | 489 | at91_rtc_write_idr(at91_rtc_imr); |
490 | } | ||
471 | } | 491 | } |
472 | return 0; | 492 | return 0; |
473 | } | 493 | } |
474 | 494 | ||
475 | static int at91_rtc_resume(struct device *dev) | 495 | static int at91_rtc_resume(struct device *dev) |
476 | { | 496 | { |
497 | struct rtc_device *rtc = dev_get_drvdata(dev); | ||
498 | |||
477 | if (at91_rtc_imr) { | 499 | if (at91_rtc_imr) { |
478 | if (device_may_wakeup(dev)) | 500 | if (device_may_wakeup(dev)) { |
501 | unsigned long flags; | ||
502 | |||
503 | spin_lock_irqsave(&suspended_lock, flags); | ||
504 | |||
505 | if (cached_events) { | ||
506 | rtc_update_irq(rtc, 1, cached_events); | ||
507 | cached_events = 0; | ||
508 | } | ||
509 | |||
510 | suspended = false; | ||
511 | spin_unlock_irqrestore(&suspended_lock, flags); | ||
512 | |||
479 | disable_irq_wake(irq); | 513 | disable_irq_wake(irq); |
480 | else | 514 | } |
481 | at91_rtc_write_ier(at91_rtc_imr); | 515 | at91_rtc_write_ier(at91_rtc_imr); |
482 | } | 516 | } |
483 | return 0; | 517 | return 0; |
484 | } | 518 | } |
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 2183fd2750ab..5ccaee32df72 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/mfd/syscon.h> | 24 | #include <linux/mfd/syscon.h> |
25 | #include <linux/regmap.h> | 25 | #include <linux/regmap.h> |
26 | #include <linux/suspend.h> | ||
26 | #include <linux/clk.h> | 27 | #include <linux/clk.h> |
27 | 28 | ||
28 | /* | 29 | /* |
@@ -77,6 +78,9 @@ struct sam9_rtc { | |||
77 | unsigned int gpbr_offset; | 78 | unsigned int gpbr_offset; |
78 | int irq; | 79 | int irq; |
79 | struct clk *sclk; | 80 | struct clk *sclk; |
81 | bool suspended; | ||
82 | unsigned long events; | ||
83 | spinlock_t lock; | ||
80 | }; | 84 | }; |
81 | 85 | ||
82 | #define rtt_readl(rtc, field) \ | 86 | #define rtt_readl(rtc, field) \ |
@@ -271,14 +275,9 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq) | |||
271 | return 0; | 275 | return 0; |
272 | } | 276 | } |
273 | 277 | ||
274 | /* | 278 | static irqreturn_t at91_rtc_cache_events(struct sam9_rtc *rtc) |
275 | * IRQ handler for the RTC | ||
276 | */ | ||
277 | static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) | ||
278 | { | 279 | { |
279 | struct sam9_rtc *rtc = _rtc; | ||
280 | u32 sr, mr; | 280 | u32 sr, mr; |
281 | unsigned long events = 0; | ||
282 | 281 | ||
283 | /* Shared interrupt may be for another device. Note: reading | 282 | /* Shared interrupt may be for another device. Note: reading |
284 | * SR clears it, so we must only read it in this irq handler! | 283 | * SR clears it, so we must only read it in this irq handler! |
@@ -290,18 +289,54 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) | |||
290 | 289 | ||
291 | /* alarm status */ | 290 | /* alarm status */ |
292 | if (sr & AT91_RTT_ALMS) | 291 | if (sr & AT91_RTT_ALMS) |
293 | events |= (RTC_AF | RTC_IRQF); | 292 | rtc->events |= (RTC_AF | RTC_IRQF); |
294 | 293 | ||
295 | /* timer update/increment */ | 294 | /* timer update/increment */ |
296 | if (sr & AT91_RTT_RTTINC) | 295 | if (sr & AT91_RTT_RTTINC) |
297 | events |= (RTC_UF | RTC_IRQF); | 296 | rtc->events |= (RTC_UF | RTC_IRQF); |
297 | |||
298 | return IRQ_HANDLED; | ||
299 | } | ||
300 | |||
301 | static void at91_rtc_flush_events(struct sam9_rtc *rtc) | ||
302 | { | ||
303 | if (!rtc->events) | ||
304 | return; | ||
298 | 305 | ||
299 | rtc_update_irq(rtc->rtcdev, 1, events); | 306 | rtc_update_irq(rtc->rtcdev, 1, rtc->events); |
307 | rtc->events = 0; | ||
300 | 308 | ||
301 | pr_debug("%s: num=%ld, events=0x%02lx\n", __func__, | 309 | pr_debug("%s: num=%ld, events=0x%02lx\n", __func__, |
302 | events >> 8, events & 0x000000FF); | 310 | rtc->events >> 8, rtc->events & 0x000000FF); |
311 | } | ||
303 | 312 | ||
304 | return IRQ_HANDLED; | 313 | /* |
314 | * IRQ handler for the RTC | ||
315 | */ | ||
316 | static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) | ||
317 | { | ||
318 | struct sam9_rtc *rtc = _rtc; | ||
319 | int ret; | ||
320 | |||
321 | spin_lock(&rtc->lock); | ||
322 | |||
323 | ret = at91_rtc_cache_events(rtc); | ||
324 | |||
325 | /* We're called in suspended state */ | ||
326 | if (rtc->suspended) { | ||
327 | /* Mask irqs coming from this peripheral */ | ||
328 | rtt_writel(rtc, MR, | ||
329 | rtt_readl(rtc, MR) & | ||
330 | ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); | ||
331 | /* Trigger a system wakeup */ | ||
332 | pm_system_wakeup(); | ||
333 | } else { | ||
334 | at91_rtc_flush_events(rtc); | ||
335 | } | ||
336 | |||
337 | spin_unlock(&rtc->lock); | ||
338 | |||
339 | return ret; | ||
305 | } | 340 | } |
306 | 341 | ||
307 | static const struct rtc_class_ops at91_rtc_ops = { | 342 | static const struct rtc_class_ops at91_rtc_ops = { |
@@ -421,7 +456,8 @@ static int at91_rtc_probe(struct platform_device *pdev) | |||
421 | 456 | ||
422 | /* register irq handler after we know what name we'll use */ | 457 | /* register irq handler after we know what name we'll use */ |
423 | ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt, | 458 | ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt, |
424 | IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc); | 459 | IRQF_SHARED | IRQF_COND_SUSPEND, |
460 | dev_name(&rtc->rtcdev->dev), rtc); | ||
425 | if (ret) { | 461 | if (ret) { |
426 | dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq); | 462 | dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq); |
427 | return ret; | 463 | return ret; |
@@ -482,7 +518,12 @@ static int at91_rtc_suspend(struct device *dev) | |||
482 | rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); | 518 | rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); |
483 | if (rtc->imr) { | 519 | if (rtc->imr) { |
484 | if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) { | 520 | if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) { |
521 | unsigned long flags; | ||
522 | |||
485 | enable_irq_wake(rtc->irq); | 523 | enable_irq_wake(rtc->irq); |
524 | spin_lock_irqsave(&rtc->lock, flags); | ||
525 | rtc->suspended = true; | ||
526 | spin_unlock_irqrestore(&rtc->lock, flags); | ||
486 | /* don't let RTTINC cause wakeups */ | 527 | /* don't let RTTINC cause wakeups */ |
487 | if (mr & AT91_RTT_RTTINCIEN) | 528 | if (mr & AT91_RTT_RTTINCIEN) |
488 | rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); | 529 | rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); |
@@ -499,10 +540,18 @@ static int at91_rtc_resume(struct device *dev) | |||
499 | u32 mr; | 540 | u32 mr; |
500 | 541 | ||
501 | if (rtc->imr) { | 542 | if (rtc->imr) { |
543 | unsigned long flags; | ||
544 | |||
502 | if (device_may_wakeup(dev)) | 545 | if (device_may_wakeup(dev)) |
503 | disable_irq_wake(rtc->irq); | 546 | disable_irq_wake(rtc->irq); |
504 | mr = rtt_readl(rtc, MR); | 547 | mr = rtt_readl(rtc, MR); |
505 | rtt_writel(rtc, MR, mr | rtc->imr); | 548 | rtt_writel(rtc, MR, mr | rtc->imr); |
549 | |||
550 | spin_lock_irqsave(&rtc->lock, flags); | ||
551 | rtc->suspended = false; | ||
552 | at91_rtc_cache_events(rtc); | ||
553 | at91_rtc_flush_events(rtc); | ||
554 | spin_unlock_irqrestore(&rtc->lock, flags); | ||
506 | } | 555 | } |
507 | 556 | ||
508 | return 0; | 557 | return 0; |
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index e2436d140175..3a6fd3a8a2ec 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c | |||
@@ -413,8 +413,8 @@ static void rtc_mrst_do_remove(struct device *dev) | |||
413 | mrst->dev = NULL; | 413 | mrst->dev = NULL; |
414 | } | 414 | } |
415 | 415 | ||
416 | #ifdef CONFIG_PM | 416 | #ifdef CONFIG_PM_SLEEP |
417 | static int mrst_suspend(struct device *dev, pm_message_t mesg) | 417 | static int mrst_suspend(struct device *dev) |
418 | { | 418 | { |
419 | struct mrst_rtc *mrst = dev_get_drvdata(dev); | 419 | struct mrst_rtc *mrst = dev_get_drvdata(dev); |
420 | unsigned char tmp; | 420 | unsigned char tmp; |
@@ -453,7 +453,7 @@ static int mrst_suspend(struct device *dev, pm_message_t mesg) | |||
453 | */ | 453 | */ |
454 | static inline int mrst_poweroff(struct device *dev) | 454 | static inline int mrst_poweroff(struct device *dev) |
455 | { | 455 | { |
456 | return mrst_suspend(dev, PMSG_HIBERNATE); | 456 | return mrst_suspend(dev); |
457 | } | 457 | } |
458 | 458 | ||
459 | static int mrst_resume(struct device *dev) | 459 | static int mrst_resume(struct device *dev) |
@@ -490,9 +490,11 @@ static int mrst_resume(struct device *dev) | |||
490 | return 0; | 490 | return 0; |
491 | } | 491 | } |
492 | 492 | ||
493 | static SIMPLE_DEV_PM_OPS(mrst_pm_ops, mrst_suspend, mrst_resume); | ||
494 | #define MRST_PM_OPS (&mrst_pm_ops) | ||
495 | |||
493 | #else | 496 | #else |
494 | #define mrst_suspend NULL | 497 | #define MRST_PM_OPS NULL |
495 | #define mrst_resume NULL | ||
496 | 498 | ||
497 | static inline int mrst_poweroff(struct device *dev) | 499 | static inline int mrst_poweroff(struct device *dev) |
498 | { | 500 | { |
@@ -529,9 +531,8 @@ static struct platform_driver vrtc_mrst_platform_driver = { | |||
529 | .remove = vrtc_mrst_platform_remove, | 531 | .remove = vrtc_mrst_platform_remove, |
530 | .shutdown = vrtc_mrst_platform_shutdown, | 532 | .shutdown = vrtc_mrst_platform_shutdown, |
531 | .driver = { | 533 | .driver = { |
532 | .name = (char *) driver_name, | 534 | .name = driver_name, |
533 | .suspend = mrst_suspend, | 535 | .pm = MRST_PM_OPS, |
534 | .resume = mrst_resume, | ||
535 | } | 536 | } |
536 | }; | 537 | }; |
537 | 538 | ||
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 4241eeab3386..f4cf6851fae9 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c | |||
@@ -849,6 +849,7 @@ static struct s3c_rtc_data const s3c2443_rtc_data = { | |||
849 | 849 | ||
850 | static struct s3c_rtc_data const s3c6410_rtc_data = { | 850 | static struct s3c_rtc_data const s3c6410_rtc_data = { |
851 | .max_user_freq = 32768, | 851 | .max_user_freq = 32768, |
852 | .needs_src_clk = true, | ||
852 | .irq_handler = s3c6410_rtc_irq, | 853 | .irq_handler = s3c6410_rtc_irq, |
853 | .set_freq = s3c6410_rtc_setfreq, | 854 | .set_freq = s3c6410_rtc_setfreq, |
854 | .enable_tick = s3c6410_rtc_enable_tick, | 855 | .enable_tick = s3c6410_rtc_enable_tick, |