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 |
