From b4f711ee03d28f776fd2324fd0bd999cc428e4d2 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Wed, 24 Apr 2013 11:32:56 -0700 Subject: time: Revert ALWAYS_USE_PERSISTENT_CLOCK compile time optimizaitons Kay Sievers noted that the ALWAYS_USE_PERSISTENT_CLOCK config, which enables some minor compile time optimization to avoid uncessary code in mostly the suspend/resume path could cause problems for userland. In particular, the dependency for RTC_HCTOSYS on !ALWAYS_USE_PERSISTENT_CLOCK, which avoids setting the time twice and simplifies suspend/resume, has the side effect of causing the /sys/class/rtc/rtcN/hctosys flag to always be zero, and this flag is commonly used by udev to setup the /dev/rtc symlink to /dev/rtcN, which can cause pain for older applications. While the udev rules could use some work to be less fragile, breaking userland should strongly be avoided. Additionally the compile time optimizations are fairly minor, and the code being optimized is likely to be reworked in the future, so lets revert this change. Reported-by: Kay Sievers Signed-off-by: John Stultz Cc: stable #3.9 Cc: Feng Tang Cc: Jason Gunthorpe Link: http://lkml.kernel.org/r/1366828376-18124-1-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner --- drivers/rtc/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 0c81915b1997..b9838130a7b0 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -20,7 +20,6 @@ if RTC_CLASS config RTC_HCTOSYS bool "Set system time from RTC on startup and resume" default y - depends on !ALWAYS_USE_PERSISTENT_CLOCK help If you say yes here, the system time (wall clock) will be set using the value read from a specified RTC device. This is useful to avoid @@ -29,7 +28,6 @@ config RTC_HCTOSYS config RTC_SYSTOHC bool "Set the RTC time based on NTP synchronization" default y - depends on !ALWAYS_USE_PERSISTENT_CLOCK help If you say yes here, the system time (wall clock) will be stored in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11 -- cgit v1.2.2 From a177c3ac25df166dbdde03e09ba8cb3065742807 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 12 May 2013 15:19:50 +0200 Subject: drivers/rtc: don't check resource with devm_ioremap_resource devm_ioremap_resource does sanity checks on the given resource. No need to duplicate this in the driver. Signed-off-by: Wolfram Sang Acked-by: Stephen Warren --- drivers/rtc/rtc-nuc900.c | 5 ----- drivers/rtc/rtc-omap.c | 5 ----- drivers/rtc/rtc-s3c.c | 5 ----- drivers/rtc/rtc-tegra.c | 6 ------ 4 files changed, 21 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index f5dfb6e5e7d9..d592e2fe43f7 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c @@ -234,11 +234,6 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev) return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "platform_get_resource failed\n"); - return -ENXIO; - } - nuc900_rtc->rtc_reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(nuc900_rtc->rtc_reg)) return PTR_ERR(nuc900_rtc->rtc_reg); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 4e1bdb832e37..b0ba3fc991ea 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -347,11 +347,6 @@ static int __init omap_rtc_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - pr_debug("%s: RTC resource data missing\n", pdev->name); - return -ENOENT; - } - rtc_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(rtc_base)) return PTR_ERR(rtc_base); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 14040b22888d..0b495e8b8e66 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -477,11 +477,6 @@ static int s3c_rtc_probe(struct platform_device *pdev) /* get the memory region */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "failed to get memory region resource\n"); - return -ENOENT; - } - s3c_rtc_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(s3c_rtc_base)) return PTR_ERR(s3c_rtc_base); diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index a34315d25478..76af92ad5a8a 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -322,12 +322,6 @@ static int __init tegra_rtc_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Unable to allocate resources for device.\n"); - return -EBUSY; - } - info->rtc_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(info->rtc_base)) return PTR_ERR(info->rtc_base); -- cgit v1.2.2 From cac29af6bd6bc5c53499f39ef1eade193295b2f1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 24 May 2013 15:55:26 -0700 Subject: drivers/rtc/rtc-pl031.c: pass correct pointer to free_irq() free_irq() expects the same pointer that was passed to request_irq(), otherwise the IRQ is not freed. The issue was found using the following coccinelle script: @r1@ type T; T devid; @@ request_irq(..., devid) @r2@ type r1.T; T devid; position p; @@ free_irq@p(..., devid) @@ position p != r2.p; @@ *free_irq@p(...) Signed-off-by: Lars-Peter Clausen Cc: Srinidhi Kasagar Cc: Linus Walleij Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pl031.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 8900ea784817..0f0609b1aa2c 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -306,7 +306,7 @@ static int pl031_remove(struct amba_device *adev) struct pl031_local *ldata = dev_get_drvdata(&adev->dev); amba_set_drvdata(adev, NULL); - free_irq(adev->irq[0], ldata->rtc); + free_irq(adev->irq[0], ldata); rtc_device_unregister(ldata->rtc); iounmap(ldata->base); kfree(ldata); -- cgit v1.2.2 From 43c523bff7c3b47506d536c10637be8399dfd85f Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Fri, 24 May 2013 15:55:35 -0700 Subject: drivers/rtc/rtc-max8998.c: check for pdata presence before dereferencing Currently the driver can crash with a NULL pointer dereference if no pdata is provided, despite of successful registration of the MFD part. This patch fixes the problem by adding a NULL check before dereferencing the pdata pointer. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Cc: Sachin Kamat Reviewed-by: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-max8998.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index 48b6612fae7f..d5af7baa48b5 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -285,7 +285,7 @@ static int max8998_rtc_probe(struct platform_device *pdev) info->irq, ret); dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name); - if (pdata->rtc_delay) { + if (pdata && pdata->rtc_delay) { info->lp3974_bug_workaround = true; dev_warn(&pdev->dev, "LP3974 with RTC REGERR option." " RTC updates will be extremely slow.\n"); -- cgit v1.2.2 From 5a280844bb3bcd79076cac6ad002f71d25c798e5 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 12 Jun 2013 14:04:44 -0700 Subject: drivers/rtc/rtc-tps6586x.c: device wakeup flags correction Use device_init_wakeup() instead of device_set_wakeup_capable() and move it before rtc dev registering. This fixes alarmtimer not registered when tps6586x rtc is the only wakeup compatible rtc in the system. Signed-off-by: Dmitry Osipenko Cc: Laxman Dewangan Cc: Jingoo Han Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps6586x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 459c2ffc95a6..426901cef14f 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -273,6 +273,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) return ret; } + device_init_wakeup(&pdev->dev, 1); + platform_set_drvdata(pdev, rtc); rtc->rtc = devm_rtc_device_register(&pdev->dev, dev_name(&pdev->dev), &tps6586x_rtc_ops, THIS_MODULE); @@ -292,7 +294,6 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) goto fail_rtc_register; } disable_irq(rtc->irq); - device_set_wakeup_capable(&pdev->dev, 1); return 0; fail_rtc_register: -- cgit v1.2.2 From ebf8d6c8630bfd3e24683306599cb953c9a2842c Mon Sep 17 00:00:00 2001 From: Derek Basehore Date: Wed, 12 Jun 2013 14:04:45 -0700 Subject: drivers/rtc/rtc-cmos.c: fix accidentally enabling rtc channel During resume, we call hpet_rtc_timer_init after masking an irq bit in hpet. This will cause the call to hpet_disable_rtc_channel to be undone if RTC_AIE is the only bit not masked. Allowing the cmos interrupt handler to run before resuming caused some issues where the timer for the alarm was not removed. This would cause other, later timers to not be cleared, so utilities such as hwclock would time out when waiting for the update interrupt. [akpm@linux-foundation.org: coding-style tweak] Signed-off-by: Derek Basehore Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-cmos.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index cc5bea9c4b1c..f1cb706445c7 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -854,6 +854,9 @@ static int cmos_resume(struct device *dev) } spin_lock_irq(&rtc_lock); + if (device_may_wakeup(dev)) + hpet_rtc_timer_init(); + do { CMOS_WRITE(tmp, RTC_CONTROL); hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK); @@ -869,7 +872,6 @@ static int cmos_resume(struct device *dev) rtc_update_irq(cmos->rtc, 1, mask); tmp &= ~RTC_AIE; hpet_mask_rtc_irq_bit(RTC_AIE); - hpet_rtc_timer_init(); } while (mask & RTC_AIE); spin_unlock_irq(&rtc_lock); } -- cgit v1.2.2 From 24b8256a1fb28d357bc6fa09184ba29b4255ba5c Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 12 Jun 2013 14:04:48 -0700 Subject: drivers/rtc/rtc-twl.c: fix missing device_init_wakeup() when booted with device tree When booted in legacy mode device_init_wakeup() gets called by drivers/mfd/twl-core.c when the children are initialized. However, when booted using device tree, the children are created with of_platform_populate() instead add_children(). This means that the RTC driver will not have device_init_wakeup() set, and we need to call it from the driver probe like RTC drivers typically do. Without this we cannot test PM wake-up events on omaps for cases where there may not be any physical wake-up event. Signed-off-by: Tony Lindgren Reported-by: Kevin Hilman Cc: Alessandro Zummo Cc: Jingoo Han Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-twl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 8751a5240c99..b2eab34f38d9 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -524,6 +524,7 @@ static int twl_rtc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, rtc); + device_init_wakeup(&pdev->dev, 1); return 0; out2: -- cgit v1.2.2 From 558c61e5579a81551c0d6c2deaed1da3c7bf714a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 12 Jun 2013 14:04:52 -0700 Subject: rtc-at91rm9200: add match-table compile guard The members of Atmel's at91sam9x5 family (9x5) have a broken RTC interrupt mask register (AT91_RTC_IMR). It does not reflect enabled interrupts but instead always returns zero. The kernel's rtc-at91rm9200 driver handles the RTC for the 9x5 family. Currently when the date/time is set, an interrupt is generated and this driver neglects to handle the interrupt. The kernel complains about the un-handled interrupt and disables it henceforth. This not only breaks the RTC function, but since that interrupt is shared (Atmel's SYS interrupt) then other things break as well (e.g. the debug port no longer accepts characters). Tested on the at91sam9g25. Bug confirmed by Atmel. This patch (of 5): Add missing match-table compile guard. Signed-off-by: Johan Hovold Acked-by: Nicolas Ferre Cc: Douglas Gilbert Cc: Jean-Christophe PLAGNIOL-VILLARD Cc: Ludovic Desroches Cc: Robert Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-at91rm9200.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 0eab77b22340..eeeb73f1fc3b 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -383,11 +383,13 @@ static int at91_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); +#ifdef CONFIG_OF static const struct of_device_id at91_rtc_dt_ids[] = { { .compatible = "atmel,at91rm9200-rtc" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); +#endif static struct platform_driver at91_rtc_driver = { .remove = __exit_p(at91_rtc_remove), -- cgit v1.2.2 From de645475913f677eb024b3d2bd52e264e8106497 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 12 Jun 2013 14:04:53 -0700 Subject: rtc-at91rm9200: add configuration support Add configuration support which can be used to implement SoC-specific workarounds for broken hardware. Signed-off-by: Johan Hovold Acked-by: Nicolas Ferre Cc: Douglas Gilbert Cc: Jean-Christophe PLAGNIOL-VILLARD Cc: Ludovic Desroches Cc: Robert Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-at91rm9200.c | 46 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index eeeb73f1fc3b..ab2024b159fa 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -42,6 +42,10 @@ #define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */ +struct at91_rtc_config { +}; + +static const struct at91_rtc_config *at91_rtc_config; static DECLARE_COMPLETION(at91_rtc_updated); static unsigned int at91_alarm_year = AT91_RTC_EPOCH; static void __iomem *at91_rtc_regs; @@ -250,6 +254,36 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) return IRQ_NONE; /* not handled */ } +static const struct at91_rtc_config at91rm9200_config = { +}; + +#ifdef CONFIG_OF +static const struct of_device_id at91_rtc_dt_ids[] = { + { + .compatible = "atmel,at91rm9200-rtc", + .data = &at91rm9200_config, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); +#endif + +static const struct at91_rtc_config * +at91_rtc_get_config(struct platform_device *pdev) +{ + const struct of_device_id *match; + + if (pdev->dev.of_node) { + match = of_match_node(at91_rtc_dt_ids, pdev->dev.of_node); + if (!match) + return NULL; + return (const struct at91_rtc_config *)match->data; + } + + return &at91rm9200_config; +} + static const struct rtc_class_ops at91_rtc_ops = { .read_time = at91_rtc_readtime, .set_time = at91_rtc_settime, @@ -268,6 +302,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev) struct resource *regs; int ret = 0; + at91_rtc_config = at91_rtc_get_config(pdev); + if (!at91_rtc_config) + return -ENODEV; + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { dev_err(&pdev->dev, "no mmio resource defined\n"); @@ -383,14 +421,6 @@ static int at91_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); -#ifdef CONFIG_OF -static const struct of_device_id at91_rtc_dt_ids[] = { - { .compatible = "atmel,at91rm9200-rtc" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); -#endif - static struct platform_driver at91_rtc_driver = { .remove = __exit_p(at91_rtc_remove), .driver = { -- cgit v1.2.2 From e304fcd075a0e97d0e538dd4408b95406b505f85 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 12 Jun 2013 14:04:55 -0700 Subject: rtc-at91rm9200: refactor interrupt-register handling Add accessors for the interrupt register. This will allow us to easily add a shadow interrupt-mask register to use on SoCs where the interrupt-mask register cannot be used. Signed-off-by: Johan Hovold Acked-by: Nicolas Ferre Cc: Douglas Gilbert Cc: Jean-Christophe PLAGNIOL-VILLARD Cc: Ludovic Desroches Cc: Robert Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-at91rm9200.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index ab2024b159fa..9592d08f3b11 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -51,6 +51,21 @@ static unsigned int at91_alarm_year = AT91_RTC_EPOCH; static void __iomem *at91_rtc_regs; static int irq; +static void at91_rtc_write_ier(u32 mask) +{ + at91_rtc_write(AT91_RTC_IER, mask); +} + +static void at91_rtc_write_idr(u32 mask) +{ + at91_rtc_write(AT91_RTC_IDR, mask); +} + +static u32 at91_rtc_read_imr(void) +{ + return at91_rtc_read(AT91_RTC_IMR); +} + /* * Decode time/date into rtc_time structure */ @@ -114,9 +129,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) cr = at91_rtc_read(AT91_RTC_CR); at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM); - at91_rtc_write(AT91_RTC_IER, AT91_RTC_ACKUPD); + at91_rtc_write_ier(AT91_RTC_ACKUPD); wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */ - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD); + at91_rtc_write_idr(AT91_RTC_ACKUPD); at91_rtc_write(AT91_RTC_TIMR, bin2bcd(tm->tm_sec) << 0 @@ -148,7 +163,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_year = at91_alarm_year - 1900; - alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM) + alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM) ? 1 : 0; dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, @@ -173,7 +188,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) tm.tm_min = alrm->time.tm_min; tm.tm_sec = alrm->time.tm_sec; - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM); + at91_rtc_write_idr(AT91_RTC_ALARM); at91_rtc_write(AT91_RTC_TIMALR, bin2bcd(tm.tm_sec) << 0 | bin2bcd(tm.tm_min) << 8 @@ -186,7 +201,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alrm->enabled) { at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM); - at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM); + at91_rtc_write_ier(AT91_RTC_ALARM); } dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, @@ -202,9 +217,9 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) if (enabled) { at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM); - at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM); + at91_rtc_write_ier(AT91_RTC_ALARM); } else - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM); + at91_rtc_write_idr(AT91_RTC_ALARM); return 0; } @@ -213,7 +228,7 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) */ static int at91_rtc_proc(struct device *dev, struct seq_file *seq) { - unsigned long imr = at91_rtc_read(AT91_RTC_IMR); + unsigned long imr = at91_rtc_read_imr(); seq_printf(seq, "update_IRQ\t: %s\n", (imr & AT91_RTC_ACKUPD) ? "yes" : "no"); @@ -233,7 +248,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) unsigned int rtsr; unsigned long events = 0; - rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read(AT91_RTC_IMR); + rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read_imr(); if (rtsr) { /* this interrupt is shared! Is it ours? */ if (rtsr & AT91_RTC_ALARM) events |= (RTC_AF | RTC_IRQF); @@ -328,7 +343,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) at91_rtc_write(AT91_RTC_MR, 0); /* 24 hour mode */ /* Disable all interrupts */ - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM | + at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM | AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); @@ -373,7 +388,7 @@ static int __exit at91_rtc_remove(struct platform_device *pdev) struct rtc_device *rtc = platform_get_drvdata(pdev); /* Disable all interrupts */ - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM | + at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM | AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); free_irq(irq, pdev); @@ -396,13 +411,13 @@ static int at91_rtc_suspend(struct device *dev) /* this IRQ is shared with DBGU and other hardware which isn't * necessarily doing PM like we are... */ - at91_rtc_imr = at91_rtc_read(AT91_RTC_IMR) + at91_rtc_imr = at91_rtc_read_imr() & (AT91_RTC_ALARM|AT91_RTC_SECEV); if (at91_rtc_imr) { if (device_may_wakeup(dev)) enable_irq_wake(irq); else - at91_rtc_write(AT91_RTC_IDR, at91_rtc_imr); + at91_rtc_write_idr(at91_rtc_imr); } return 0; } @@ -413,7 +428,7 @@ static int at91_rtc_resume(struct device *dev) if (device_may_wakeup(dev)) disable_irq_wake(irq); else - at91_rtc_write(AT91_RTC_IER, at91_rtc_imr); + at91_rtc_write_ier(at91_rtc_imr); } return 0; } -- cgit v1.2.2 From e9f08bbe3f97829975d2b59091ef557101c83f61 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 12 Jun 2013 14:04:56 -0700 Subject: rtc-at91rm9200: add shadow interrupt mask Add shadow interrupt-mask register which can be used on SoCs where the actual hardware register is broken. Note that some care needs to be taken to make sure the shadow mask corresponds to the actual hardware state. The added overhead is not an issue for the non-broken SoCs due to the relatively infrequent interrupt-mask updates. We do, however, only use the shadow mask value as a fall-back when it actually needed as there is still a theoretical possibility that the mask is incorrect (see the code for details). Signed-off-by: Johan Hovold Acked-by: Nicolas Ferre Cc: Douglas Gilbert Cc: Jean-Christophe PLAGNIOL-VILLARD Cc: Ludovic Desroches Cc: Robert Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-at91rm9200.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 9592d08f3b11..811a102092d4 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */ struct at91_rtc_config { + bool use_shadow_imr; }; static const struct at91_rtc_config *at91_rtc_config; @@ -50,20 +52,55 @@ static DECLARE_COMPLETION(at91_rtc_updated); static unsigned int at91_alarm_year = AT91_RTC_EPOCH; static void __iomem *at91_rtc_regs; static int irq; +static DEFINE_SPINLOCK(at91_rtc_lock); +static u32 at91_rtc_shadow_imr; static void at91_rtc_write_ier(u32 mask) { + unsigned long flags; + + spin_lock_irqsave(&at91_rtc_lock, flags); + at91_rtc_shadow_imr |= mask; at91_rtc_write(AT91_RTC_IER, mask); + spin_unlock_irqrestore(&at91_rtc_lock, flags); } static void at91_rtc_write_idr(u32 mask) { + unsigned long flags; + + spin_lock_irqsave(&at91_rtc_lock, flags); at91_rtc_write(AT91_RTC_IDR, mask); + /* + * Register read back (of any RTC-register) needed to make sure + * IDR-register write has reached the peripheral before updating + * shadow mask. + * + * Note that there is still a possibility that the mask is updated + * before interrupts have actually been disabled in hardware. The only + * way to be certain would be to poll the IMR-register, which is is + * the very register we are trying to emulate. The register read back + * is a reasonable heuristic. + */ + at91_rtc_read(AT91_RTC_SR); + at91_rtc_shadow_imr &= ~mask; + spin_unlock_irqrestore(&at91_rtc_lock, flags); } static u32 at91_rtc_read_imr(void) { - return at91_rtc_read(AT91_RTC_IMR); + unsigned long flags; + u32 mask; + + if (at91_rtc_config->use_shadow_imr) { + spin_lock_irqsave(&at91_rtc_lock, flags); + mask = at91_rtc_shadow_imr; + spin_unlock_irqrestore(&at91_rtc_lock, flags); + } else { + mask = at91_rtc_read(AT91_RTC_IMR); + } + + return mask; } /* -- cgit v1.2.2 From bba00e59107275faa615573c44eb0a513a1220a6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 12 Jun 2013 14:04:57 -0700 Subject: rtc-at91rm9200: use shadow IMR on at91sam9x5 Add support for the at91sam9x5-family which must use the shadow interrupt mask due to a hardware issue (causing RTC_IMR to always be zero). Signed-off-by: Johan Hovold Acked-by: Nicolas Ferre Cc: Douglas Gilbert Cc: Jean-Christophe PLAGNIOL-VILLARD Cc: Ludovic Desroches Cc: Robert Nelson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-at91rm9200.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 811a102092d4..f296f3f7db9b 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -309,11 +309,18 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) static const struct at91_rtc_config at91rm9200_config = { }; +static const struct at91_rtc_config at91sam9x5_config = { + .use_shadow_imr = true, +}; + #ifdef CONFIG_OF static const struct of_device_id at91_rtc_dt_ids[] = { { .compatible = "atmel,at91rm9200-rtc", .data = &at91rm9200_config, + }, { + .compatible = "atmel,at91sam9x5-rtc", + .data = &at91sam9x5_config, }, { /* sentinel */ } -- cgit v1.2.2