summaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-omap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc/rtc-omap.c')
-rw-r--r--drivers/rtc/rtc-omap.c138
1 files changed, 78 insertions, 60 deletions
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 26de5f8c2ae..21142e6574a 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -73,43 +73,52 @@
#define OMAP_RTC_IRQWAKEEN 0x7c
/* OMAP_RTC_CTRL_REG bit fields: */
-#define OMAP_RTC_CTRL_SPLIT (1<<7)
-#define OMAP_RTC_CTRL_DISABLE (1<<6)
-#define OMAP_RTC_CTRL_SET_32_COUNTER (1<<5)
-#define OMAP_RTC_CTRL_TEST (1<<4)
-#define OMAP_RTC_CTRL_MODE_12_24 (1<<3)
-#define OMAP_RTC_CTRL_AUTO_COMP (1<<2)
-#define OMAP_RTC_CTRL_ROUND_30S (1<<1)
-#define OMAP_RTC_CTRL_STOP (1<<0)
+#define OMAP_RTC_CTRL_SPLIT BIT(7)
+#define OMAP_RTC_CTRL_DISABLE BIT(6)
+#define OMAP_RTC_CTRL_SET_32_COUNTER BIT(5)
+#define OMAP_RTC_CTRL_TEST BIT(4)
+#define OMAP_RTC_CTRL_MODE_12_24 BIT(3)
+#define OMAP_RTC_CTRL_AUTO_COMP BIT(2)
+#define OMAP_RTC_CTRL_ROUND_30S BIT(1)
+#define OMAP_RTC_CTRL_STOP BIT(0)
/* OMAP_RTC_STATUS_REG bit fields: */
-#define OMAP_RTC_STATUS_POWER_UP (1<<7)
-#define OMAP_RTC_STATUS_ALARM (1<<6)
-#define OMAP_RTC_STATUS_1D_EVENT (1<<5)
-#define OMAP_RTC_STATUS_1H_EVENT (1<<4)
-#define OMAP_RTC_STATUS_1M_EVENT (1<<3)
-#define OMAP_RTC_STATUS_1S_EVENT (1<<2)
-#define OMAP_RTC_STATUS_RUN (1<<1)
-#define OMAP_RTC_STATUS_BUSY (1<<0)
+#define OMAP_RTC_STATUS_POWER_UP BIT(7)
+#define OMAP_RTC_STATUS_ALARM BIT(6)
+#define OMAP_RTC_STATUS_1D_EVENT BIT(5)
+#define OMAP_RTC_STATUS_1H_EVENT BIT(4)
+#define OMAP_RTC_STATUS_1M_EVENT BIT(3)
+#define OMAP_RTC_STATUS_1S_EVENT BIT(2)
+#define OMAP_RTC_STATUS_RUN BIT(1)
+#define OMAP_RTC_STATUS_BUSY BIT(0)
/* OMAP_RTC_INTERRUPTS_REG bit fields: */
-#define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3)
-#define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2)
+#define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3)
+#define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2)
+
+/* OMAP_RTC_OSC_REG bit fields: */
+#define OMAP_RTC_OSC_32KCLK_EN BIT(6)
/* OMAP_RTC_IRQWAKEEN bit fields: */
-#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN (1<<1)
+#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1)
/* OMAP_RTC_KICKER values */
#define KICK0_VALUE 0x83e70b13
#define KICK1_VALUE 0x95a4f1e0
-#define OMAP_RTC_HAS_KICKER 0x1
+#define OMAP_RTC_HAS_KICKER BIT(0)
/*
* Few RTC IP revisions has special WAKE-EN Register to enable Wakeup
* generation for event Alarm.
*/
-#define OMAP_RTC_HAS_IRQWAKEEN 0x2
+#define OMAP_RTC_HAS_IRQWAKEEN BIT(1)
+
+/*
+ * Some RTC IP revisions (like those in AM335x and DRA7x) need
+ * the 32KHz clock to be explicitly enabled.
+ */
+#define OMAP_RTC_HAS_32KCLK_EN BIT(2)
static void __iomem *rtc_base;
@@ -162,17 +171,28 @@ static irqreturn_t rtc_irq(int irq, void *rtc)
static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
- u8 reg;
+ u8 reg, irqwake_reg = 0;
+ struct platform_device *pdev = to_platform_device(dev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(pdev);
local_irq_disable();
rtc_wait_not_busy();
reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
- if (enabled)
+ if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
+ irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN);
+
+ if (enabled) {
reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
- else
+ irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
+ } else {
reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
+ irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
+ }
rtc_wait_not_busy();
rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
+ if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
+ rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);
local_irq_enable();
return 0;
@@ -272,7 +292,10 @@ static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
- u8 reg;
+ u8 reg, irqwake_reg = 0;
+ struct platform_device *pdev = to_platform_device(dev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(pdev);
if (tm2bcd(&alm->time) < 0)
return -EINVAL;
@@ -288,11 +311,19 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);
reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
- if (alm->enabled)
+ if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
+ irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN);
+
+ if (alm->enabled) {
reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
- else
+ irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
+ } else {
reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
+ irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
+ }
rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
+ if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
+ rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);
local_irq_enable();
@@ -319,7 +350,8 @@ static struct platform_device_id omap_rtc_devtype[] = {
},
[OMAP_RTC_DATA_AM3352_IDX] = {
.name = "am3352-rtc",
- .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN,
+ .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN |
+ OMAP_RTC_HAS_32KCLK_EN,
},
[OMAP_RTC_DATA_DA830_IDX] = {
.name = "da830-rtc",
@@ -352,6 +384,12 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
if (of_id)
pdev->id_entry = of_id->data;
+ id_entry = platform_get_device_id(pdev);
+ if (!id_entry) {
+ dev_err(&pdev->dev, "no matching device entry\n");
+ return -ENODEV;
+ }
+
omap_rtc_timer = platform_get_irq(pdev, 0);
if (omap_rtc_timer <= 0) {
pr_debug("%s: no update irq?\n", pdev->name);
@@ -373,8 +411,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- id_entry = platform_get_device_id(pdev);
- if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) {
+ if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) {
rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG);
rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG);
}
@@ -393,6 +430,10 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
*/
rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+ /* enable RTC functional clock */
+ if (id_entry->driver_data & OMAP_RTC_HAS_32KCLK_EN)
+ rtc_writel(OMAP_RTC_OSC_32KCLK_EN, OMAP_RTC_OSC_REG);
+
/* clear old status */
reg = rtc_read(OMAP_RTC_STATUS_REG);
if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) {
@@ -452,7 +493,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
return 0;
fail0:
- if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER))
+ if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)
rtc_writel(0, OMAP_RTC_KICK0_REG);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -469,7 +510,7 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
/* leave rtc running, but disable irqs */
rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
- if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER))
+ if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)
rtc_writel(0, OMAP_RTC_KICK0_REG);
/* Disable the clock/module */
@@ -484,28 +525,16 @@ static u8 irqstat;
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);
/* FIXME the RTC alarm is not currently acting as a wakeup event
* source on some platforms, and in fact this enable() call is just
* saving a flag that's never used...
*/
- if (device_may_wakeup(dev)) {
+ if (device_may_wakeup(dev))
enable_irq_wake(omap_rtc_alarm);
-
- 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 {
+ else
rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
- }
/* Disable the clock/module */
pm_runtime_put_sync(dev);
@@ -515,25 +544,14 @@ static int omap_rtc_suspend(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 */
pm_runtime_get_sync(dev);
- if (device_may_wakeup(dev)) {
+ if (device_may_wakeup(dev))
disable_irq_wake(omap_rtc_alarm);
-
- 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 {
+ else
rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
- }
+
return 0;
}
#endif