Commit 8af750e3 authored by Hebbar Gururaja's avatar Hebbar Gururaja Committed by Linus Torvalds

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: default avatarHebbar Gururaja <gururaja.hebbar@ti.com>
Acked-by: default avatarKevin Hilman <khilman@linaro.org>
Acked-by: default avatarSekhar 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 453b4c6d
TI Real Time Clock TI Real Time Clock
Required properties: Required properties:
- compatible: "ti,da830-rtc" - compatible:
- "ti,da830-rtc" - for RTC IP used similar to that on DA8xx SoC family.
- "ti,am3352-rtc" - for RTC IP used similar to that on AM335x SoC family.
This RTC IP has special WAKE-EN Register to enable
Wakeup generation for event Alarm.
- reg: Address range of rtc register set - reg: Address range of rtc register set
- interrupts: rtc timer, alarm interrupts in order - interrupts: rtc timer, alarm interrupts in order
- interrupt-parent: phandle for the interrupt controller - interrupt-parent: phandle for the interrupt controller
......
...@@ -70,6 +70,8 @@ ...@@ -70,6 +70,8 @@
#define OMAP_RTC_KICK0_REG 0x6c #define OMAP_RTC_KICK0_REG 0x6c
#define OMAP_RTC_KICK1_REG 0x70 #define OMAP_RTC_KICK1_REG 0x70
#define OMAP_RTC_IRQWAKEEN 0x7c
/* OMAP_RTC_CTRL_REG bit fields: */ /* OMAP_RTC_CTRL_REG bit fields: */
#define OMAP_RTC_CTRL_SPLIT (1<<7) #define OMAP_RTC_CTRL_SPLIT (1<<7)
#define OMAP_RTC_CTRL_DISABLE (1<<6) #define OMAP_RTC_CTRL_DISABLE (1<<6)
...@@ -94,12 +96,21 @@ ...@@ -94,12 +96,21 @@
#define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3)
#define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2)
/* OMAP_RTC_IRQWAKEEN bit fields: */
#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN (1<<1)
/* OMAP_RTC_KICKER values */ /* OMAP_RTC_KICKER values */
#define KICK0_VALUE 0x83e70b13 #define KICK0_VALUE 0x83e70b13
#define KICK1_VALUE 0x95a4f1e0 #define KICK1_VALUE 0x95a4f1e0
#define OMAP_RTC_HAS_KICKER 0x1 #define OMAP_RTC_HAS_KICKER 0x1
/*
* Few RTC IP revisions has special WAKE-EN Register to enable Wakeup
* generation for event Alarm.
*/
#define OMAP_RTC_HAS_IRQWAKEEN 0x2
static void __iomem *rtc_base; static void __iomem *rtc_base;
#define rtc_read(addr) readb(rtc_base + (addr)) #define rtc_read(addr) readb(rtc_base + (addr))
...@@ -299,12 +310,18 @@ static struct rtc_class_ops omap_rtc_ops = { ...@@ -299,12 +310,18 @@ static struct rtc_class_ops omap_rtc_ops = {
static int omap_rtc_alarm; static int omap_rtc_alarm;
static int omap_rtc_timer; static int omap_rtc_timer;
#define OMAP_RTC_DATA_DA830_IDX 1 #define OMAP_RTC_DATA_AM3352_IDX 1
#define OMAP_RTC_DATA_DA830_IDX 2
static struct platform_device_id omap_rtc_devtype[] = { static struct platform_device_id omap_rtc_devtype[] = {
{ {
.name = DRIVER_NAME, .name = DRIVER_NAME,
}, { },
[OMAP_RTC_DATA_AM3352_IDX] = {
.name = "am3352-rtc",
.driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN,
},
[OMAP_RTC_DATA_DA830_IDX] = {
.name = "da830-rtc", .name = "da830-rtc",
.driver_data = OMAP_RTC_HAS_KICKER, .driver_data = OMAP_RTC_HAS_KICKER,
}, },
...@@ -316,6 +333,9 @@ static const struct of_device_id omap_rtc_of_match[] = { ...@@ -316,6 +333,9 @@ static const struct of_device_id omap_rtc_of_match[] = {
{ .compatible = "ti,da830-rtc", { .compatible = "ti,da830-rtc",
.data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX],
}, },
{ .compatible = "ti,am3352-rtc",
.data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX],
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, omap_rtc_of_match); MODULE_DEVICE_TABLE(of, omap_rtc_of_match);
...@@ -464,16 +484,28 @@ static u8 irqstat; ...@@ -464,16 +484,28 @@ static u8 irqstat;
static int omap_rtc_suspend(struct device *dev) static int omap_rtc_suspend(struct device *dev)
{ {
u8 irqwake_stat;
struct platform_device *pdev = to_platform_device(dev);
const struct platform_device_id *id_entry =
platform_get_device_id(pdev);
irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG); irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
/* FIXME the RTC alarm is not currently acting as a wakeup event /* FIXME the RTC alarm is not currently acting as a wakeup event
* source, and in fact this enable() call is just saving a flag * source on some platforms, and in fact this enable() call is just
* that's never used... * saving a flag that's never used...
*/ */
if (device_may_wakeup(dev)) if (device_may_wakeup(dev)) {
enable_irq_wake(omap_rtc_alarm); enable_irq_wake(omap_rtc_alarm);
else
if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) {
irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN);
irqwake_stat |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN);
}
} else {
rtc_write(0, OMAP_RTC_INTERRUPTS_REG); rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
}
/* Disable the clock/module */ /* Disable the clock/module */
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
...@@ -483,13 +515,25 @@ static int omap_rtc_suspend(struct device *dev) ...@@ -483,13 +515,25 @@ static int omap_rtc_suspend(struct device *dev)
static int omap_rtc_resume(struct device *dev) static int omap_rtc_resume(struct device *dev)
{ {
u8 irqwake_stat;
struct platform_device *pdev = to_platform_device(dev);
const struct platform_device_id *id_entry =
platform_get_device_id(pdev);
/* Enable the clock/module so that we can access the registers */ /* Enable the clock/module so that we can access the registers */
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
if (device_may_wakeup(dev)) if (device_may_wakeup(dev)) {
disable_irq_wake(omap_rtc_alarm); disable_irq_wake(omap_rtc_alarm);
else
if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) {
irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN);
irqwake_stat &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN);
}
} else {
rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG); rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
}
return 0; return 0;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment