diff options
author | Hebbar Gururaja <gururaja.hebbar@ti.com> | 2013-09-11 17:24:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-11 18:58:54 -0400 |
commit | 8af750e3f5ca21eaa5595a96a4cf5eaa996deed4 (patch) | |
tree | 7118ce404a069e098ab779a2d764de8c798c9c79 /drivers/rtc | |
parent | 453b4c6db59f7f6411a0b5eb58389a1fa129cc9a (diff) |
drivers/rtc/rtc-omap.c: add rtc wakeup support to alarm events
On some platforms (like AM33xx), a special register (RTC_IRQWAKEEN) is
available to enable Alarm Wakeup feature. This register needs to be
properly handled for the rtcwake to work properly.
Platforms using such IP should set "ti,am3352-rtc" in rtc device dt
compatibility node.
Signed-off-by: Hebbar Gururaja <gururaja.hebbar@ti.com>
Acked-by: Kevin Hilman <khilman@linaro.org>
Acked-by: Sekhar Nori <nsekhar@ti.com>
Cc: Grant Likely <grant.likely@linaro.org>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Rob Landley <rob@landley.net>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-omap.c | 60 |
1 files changed, 52 insertions, 8 deletions
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index c6ffbaec32a4..c7d97ee59327 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
@@ -70,6 +70,8 @@ | |||
70 | #define OMAP_RTC_KICK0_REG 0x6c | 70 | #define OMAP_RTC_KICK0_REG 0x6c |
71 | #define OMAP_RTC_KICK1_REG 0x70 | 71 | #define OMAP_RTC_KICK1_REG 0x70 |
72 | 72 | ||
73 | #define OMAP_RTC_IRQWAKEEN 0x7c | ||
74 | |||
73 | /* OMAP_RTC_CTRL_REG bit fields: */ | 75 | /* OMAP_RTC_CTRL_REG bit fields: */ |
74 | #define OMAP_RTC_CTRL_SPLIT (1<<7) | 76 | #define OMAP_RTC_CTRL_SPLIT (1<<7) |
75 | #define OMAP_RTC_CTRL_DISABLE (1<<6) | 77 | #define OMAP_RTC_CTRL_DISABLE (1<<6) |
@@ -94,12 +96,21 @@ | |||
94 | #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) | 96 | #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) |
95 | #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) | 97 | #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) |
96 | 98 | ||
99 | /* OMAP_RTC_IRQWAKEEN bit fields: */ | ||
100 | #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN (1<<1) | ||
101 | |||
97 | /* OMAP_RTC_KICKER values */ | 102 | /* OMAP_RTC_KICKER values */ |
98 | #define KICK0_VALUE 0x83e70b13 | 103 | #define KICK0_VALUE 0x83e70b13 |
99 | #define KICK1_VALUE 0x95a4f1e0 | 104 | #define KICK1_VALUE 0x95a4f1e0 |
100 | 105 | ||
101 | #define OMAP_RTC_HAS_KICKER 0x1 | 106 | #define OMAP_RTC_HAS_KICKER 0x1 |
102 | 107 | ||
108 | /* | ||
109 | * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup | ||
110 | * generation for event Alarm. | ||
111 | */ | ||
112 | #define OMAP_RTC_HAS_IRQWAKEEN 0x2 | ||
113 | |||
103 | static void __iomem *rtc_base; | 114 | static void __iomem *rtc_base; |
104 | 115 | ||
105 | #define rtc_read(addr) readb(rtc_base + (addr)) | 116 | #define rtc_read(addr) readb(rtc_base + (addr)) |
@@ -299,12 +310,18 @@ static struct rtc_class_ops omap_rtc_ops = { | |||
299 | static int omap_rtc_alarm; | 310 | static int omap_rtc_alarm; |
300 | static int omap_rtc_timer; | 311 | static int omap_rtc_timer; |
301 | 312 | ||
302 | #define OMAP_RTC_DATA_DA830_IDX 1 | 313 | #define OMAP_RTC_DATA_AM3352_IDX 1 |
314 | #define OMAP_RTC_DATA_DA830_IDX 2 | ||
303 | 315 | ||
304 | static struct platform_device_id omap_rtc_devtype[] = { | 316 | static struct platform_device_id omap_rtc_devtype[] = { |
305 | { | 317 | { |
306 | .name = DRIVER_NAME, | 318 | .name = DRIVER_NAME, |
307 | }, { | 319 | }, |
320 | [OMAP_RTC_DATA_AM3352_IDX] = { | ||
321 | .name = "am3352-rtc", | ||
322 | .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN, | ||
323 | }, | ||
324 | [OMAP_RTC_DATA_DA830_IDX] = { | ||
308 | .name = "da830-rtc", | 325 | .name = "da830-rtc", |
309 | .driver_data = OMAP_RTC_HAS_KICKER, | 326 | .driver_data = OMAP_RTC_HAS_KICKER, |
310 | }, | 327 | }, |
@@ -316,6 +333,9 @@ static const struct of_device_id omap_rtc_of_match[] = { | |||
316 | { .compatible = "ti,da830-rtc", | 333 | { .compatible = "ti,da830-rtc", |
317 | .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], | 334 | .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], |
318 | }, | 335 | }, |
336 | { .compatible = "ti,am3352-rtc", | ||
337 | .data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX], | ||
338 | }, | ||
319 | {}, | 339 | {}, |
320 | }; | 340 | }; |
321 | MODULE_DEVICE_TABLE(of, omap_rtc_of_match); | 341 | MODULE_DEVICE_TABLE(of, omap_rtc_of_match); |
@@ -464,16 +484,28 @@ static u8 irqstat; | |||
464 | 484 | ||
465 | static int omap_rtc_suspend(struct device *dev) | 485 | static int omap_rtc_suspend(struct device *dev) |
466 | { | 486 | { |
487 | u8 irqwake_stat; | ||
488 | struct platform_device *pdev = to_platform_device(dev); | ||
489 | const struct platform_device_id *id_entry = | ||
490 | platform_get_device_id(pdev); | ||
491 | |||
467 | irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG); | 492 | irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG); |
468 | 493 | ||
469 | /* FIXME the RTC alarm is not currently acting as a wakeup event | 494 | /* FIXME the RTC alarm is not currently acting as a wakeup event |
470 | * source, and in fact this enable() call is just saving a flag | 495 | * source on some platforms, and in fact this enable() call is just |
471 | * that's never used... | 496 | * saving a flag that's never used... |
472 | */ | 497 | */ |
473 | if (device_may_wakeup(dev)) | 498 | if (device_may_wakeup(dev)) { |
474 | enable_irq_wake(omap_rtc_alarm); | 499 | enable_irq_wake(omap_rtc_alarm); |
475 | else | 500 | |
501 | if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { | ||
502 | irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); | ||
503 | irqwake_stat |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; | ||
504 | rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); | ||
505 | } | ||
506 | } else { | ||
476 | rtc_write(0, OMAP_RTC_INTERRUPTS_REG); | 507 | rtc_write(0, OMAP_RTC_INTERRUPTS_REG); |
508 | } | ||
477 | 509 | ||
478 | /* Disable the clock/module */ | 510 | /* Disable the clock/module */ |
479 | pm_runtime_put_sync(dev); | 511 | pm_runtime_put_sync(dev); |
@@ -483,13 +515,25 @@ static int omap_rtc_suspend(struct device *dev) | |||
483 | 515 | ||
484 | static int omap_rtc_resume(struct device *dev) | 516 | static int omap_rtc_resume(struct device *dev) |
485 | { | 517 | { |
518 | u8 irqwake_stat; | ||
519 | struct platform_device *pdev = to_platform_device(dev); | ||
520 | const struct platform_device_id *id_entry = | ||
521 | platform_get_device_id(pdev); | ||
522 | |||
486 | /* Enable the clock/module so that we can access the registers */ | 523 | /* Enable the clock/module so that we can access the registers */ |
487 | pm_runtime_get_sync(dev); | 524 | pm_runtime_get_sync(dev); |
488 | 525 | ||
489 | if (device_may_wakeup(dev)) | 526 | if (device_may_wakeup(dev)) { |
490 | disable_irq_wake(omap_rtc_alarm); | 527 | disable_irq_wake(omap_rtc_alarm); |
491 | else | 528 | |
529 | if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { | ||
530 | irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); | ||
531 | irqwake_stat &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; | ||
532 | rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); | ||
533 | } | ||
534 | } else { | ||
492 | rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG); | 535 | rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG); |
536 | } | ||
493 | return 0; | 537 | return 0; |
494 | } | 538 | } |
495 | #endif | 539 | #endif |