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

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>

authored by

Hebbar Gururaja and committed by
Linus Torvalds
8af750e3 453b4c6d

+57 -9
+5 -1
Documentation/devicetree/bindings/rtc/rtc-omap.txt
··· 1 1 TI Real Time Clock 2 2 3 3 Required properties: 4 - - compatible: "ti,da830-rtc" 4 + - compatible: 5 + - "ti,da830-rtc" - for RTC IP used similar to that on DA8xx SoC family. 6 + - "ti,am3352-rtc" - for RTC IP used similar to that on AM335x SoC family. 7 + This RTC IP has special WAKE-EN Register to enable 8 + Wakeup generation for event Alarm. 5 9 - reg: Address range of rtc register set 6 10 - interrupts: rtc timer, alarm interrupts in order 7 11 - interrupt-parent: phandle for the interrupt controller
+52 -8
drivers/rtc/rtc-omap.c
··· 70 70 #define OMAP_RTC_KICK0_REG 0x6c 71 71 #define OMAP_RTC_KICK1_REG 0x70 72 72 73 + #define OMAP_RTC_IRQWAKEEN 0x7c 74 + 73 75 /* OMAP_RTC_CTRL_REG bit fields: */ 74 76 #define OMAP_RTC_CTRL_SPLIT (1<<7) 75 77 #define OMAP_RTC_CTRL_DISABLE (1<<6) ··· 96 94 #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) 97 95 #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) 98 96 97 + /* OMAP_RTC_IRQWAKEEN bit fields: */ 98 + #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN (1<<1) 99 + 99 100 /* OMAP_RTC_KICKER values */ 100 101 #define KICK0_VALUE 0x83e70b13 101 102 #define KICK1_VALUE 0x95a4f1e0 102 103 103 104 #define OMAP_RTC_HAS_KICKER 0x1 105 + 106 + /* 107 + * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup 108 + * generation for event Alarm. 109 + */ 110 + #define OMAP_RTC_HAS_IRQWAKEEN 0x2 104 111 105 112 static void __iomem *rtc_base; 106 113 ··· 310 299 static int omap_rtc_alarm; 311 300 static int omap_rtc_timer; 312 301 313 - #define OMAP_RTC_DATA_DA830_IDX 1 302 + #define OMAP_RTC_DATA_AM3352_IDX 1 303 + #define OMAP_RTC_DATA_DA830_IDX 2 314 304 315 305 static struct platform_device_id omap_rtc_devtype[] = { 316 306 { 317 307 .name = DRIVER_NAME, 318 - }, { 308 + }, 309 + [OMAP_RTC_DATA_AM3352_IDX] = { 310 + .name = "am3352-rtc", 311 + .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN, 312 + }, 313 + [OMAP_RTC_DATA_DA830_IDX] = { 319 314 .name = "da830-rtc", 320 315 .driver_data = OMAP_RTC_HAS_KICKER, 321 316 }, ··· 332 315 static const struct of_device_id omap_rtc_of_match[] = { 333 316 { .compatible = "ti,da830-rtc", 334 317 .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], 318 + }, 319 + { .compatible = "ti,am3352-rtc", 320 + .data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX], 335 321 }, 336 322 {}, 337 323 }; ··· 484 464 485 465 static int omap_rtc_suspend(struct device *dev) 486 466 { 467 + u8 irqwake_stat; 468 + struct platform_device *pdev = to_platform_device(dev); 469 + const struct platform_device_id *id_entry = 470 + platform_get_device_id(pdev); 471 + 487 472 irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG); 488 473 489 474 /* FIXME the RTC alarm is not currently acting as a wakeup event 490 - * source, and in fact this enable() call is just saving a flag 491 - * that's never used... 475 + * source on some platforms, and in fact this enable() call is just 476 + * saving a flag that's never used... 492 477 */ 493 - if (device_may_wakeup(dev)) 478 + if (device_may_wakeup(dev)) { 494 479 enable_irq_wake(omap_rtc_alarm); 495 - else 480 + 481 + if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { 482 + irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); 483 + irqwake_stat |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; 484 + rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); 485 + } 486 + } else { 496 487 rtc_write(0, OMAP_RTC_INTERRUPTS_REG); 488 + } 497 489 498 490 /* Disable the clock/module */ 499 491 pm_runtime_put_sync(dev); ··· 515 483 516 484 static int omap_rtc_resume(struct device *dev) 517 485 { 486 + u8 irqwake_stat; 487 + struct platform_device *pdev = to_platform_device(dev); 488 + const struct platform_device_id *id_entry = 489 + platform_get_device_id(pdev); 490 + 518 491 /* Enable the clock/module so that we can access the registers */ 519 492 pm_runtime_get_sync(dev); 520 493 521 - if (device_may_wakeup(dev)) 494 + if (device_may_wakeup(dev)) { 522 495 disable_irq_wake(omap_rtc_alarm); 523 - else 496 + 497 + if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { 498 + irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); 499 + irqwake_stat &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; 500 + rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); 501 + } 502 + } else { 524 503 rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG); 504 + } 525 505 return 0; 526 506 } 527 507 #endif