diff options
Diffstat (limited to 'drivers/rtc/rtc-omap.c')
-rw-r--r-- | drivers/rtc/rtc-omap.c | 138 |
1 files changed, 78 insertions, 60 deletions
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 26de5f8c2ae4..21142e6574a9 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 |