From 07187ee13f2b4ba183d4a4832ea153dbb2e030d3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 22 Jun 2011 23:20:14 +0200 Subject: [PATCH 1/8] rtc: vt8500: Use define instead of hardcoded value for status bit Fixes the vt8500 driver to use a define value for the isr is-alarm bit. Cc: Alexey Charkov Signed-off-by: Wolfram Sang Signed-off-by: John Stultz --- drivers/rtc/rtc-vt8500.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index efd6066b5cd2..f93f412423c6 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -74,6 +74,8 @@ #define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */ #define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */ +#define VT8500_RTC_IS_ALARM (1 << 0) /* Alarm interrupt status */ + struct vt8500_rtc { void __iomem *regbase; struct resource *res; @@ -96,7 +98,7 @@ static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id) spin_unlock(&vt8500_rtc->lock); - if (isr & 1) + if (isr & VT8500_RTC_IS_ALARM) events |= RTC_AF | RTC_IRQF; rtc_update_irq(vt8500_rtc->rtc, 1, events); @@ -161,8 +163,8 @@ static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK)); alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0; + alrm->pending = (isr & VT8500_RTC_IS_ALARM) ? 1 : 0; - alrm->pending = (isr & 1) ? 1 : 0; return rtc_valid_tm(&alrm->time); } From 47eac337cd87464b90d0ad2eb2a060036a95b649 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 25 May 2011 12:56:49 +0200 Subject: [PATCH 2/8] rtc: stmp3xxx: Restore register definitions The stmp3xxx driver used to include register names from a stmp-specific include. Because of consolidation, plat-stmp has now been removed and merged with the compatible mach-mxs. Restore the register names directly in the driver and rename them to be specific to this driver. Signed-off-by: Wolfram Sang Tested-by: Shawn Guo Signed-off-by: John Stultz --- drivers/rtc/rtc-stmp3xxx.c | 97 +++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 37 deletions(-) diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 572e9534b591..e54bea076067 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -26,7 +26,25 @@ #include #include -#include + +#define STMP3XXX_RTC_CTRL 0x0 +#define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 +#define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002 +#define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004 +#define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ 0x00000008 + +#define STMP3XXX_RTC_STAT 0x10 +#define STMP3XXX_RTC_STAT_STALE_SHIFT 16 +#define STMP3XXX_RTC_STAT_RTC_PRESENT 0x80000000 + +#define STMP3XXX_RTC_SECONDS 0x30 + +#define STMP3XXX_RTC_ALARM 0x40 + +#define STMP3XXX_RTC_PERSISTENT0 0x60 +#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002 +#define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004 +#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080 struct stmp3xxx_rtc_data { struct rtc_device *rtc; @@ -42,8 +60,8 @@ static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0, * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS */ - while (__raw_readl(rtc_data->io + HW_RTC_STAT) & - BF(0x80, RTC_STAT_STALE_REGS)) + while (__raw_readl(rtc_data->io + STMP3XXX_RTC_STAT) & + (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) cpu_relax(); } @@ -53,7 +71,8 @@ static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); stmp3xxx_wait_time(rtc_data); - rtc_time_to_tm(__raw_readl(rtc_data->io + HW_RTC_SECONDS), rtc_tm); + rtc_time_to_tm(__raw_readl(rtc_data->io + STMP3XXX_RTC_SECONDS), + rtc_tm); return 0; } @@ -61,7 +80,7 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - __raw_writel(t, rtc_data->io + HW_RTC_SECONDS); + __raw_writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS); stmp3xxx_wait_time(rtc_data); return 0; } @@ -73,18 +92,19 @@ static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) u32 status; u32 events = 0; - status = __raw_readl(rtc_data->io + HW_RTC_CTRL) & - (BM_RTC_CTRL_ALARM_IRQ | BM_RTC_CTRL_ONEMSEC_IRQ); + status = __raw_readl(rtc_data->io + STMP3XXX_RTC_CTRL) & + (STMP3XXX_RTC_CTRL_ALARM_IRQ | + STMP3XXX_RTC_CTRL_ONEMSEC_IRQ); - if (status & BM_RTC_CTRL_ALARM_IRQ) { - stmp3xxx_clearl(BM_RTC_CTRL_ALARM_IRQ, - rtc_data->io + HW_RTC_CTRL); + if (status & STMP3XXX_RTC_CTRL_ALARM_IRQ) { + stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ALARM_IRQ, + rtc_data->io + STMP3XXX_RTC_CTRL); events |= RTC_AF | RTC_IRQF; } - if (status & BM_RTC_CTRL_ONEMSEC_IRQ) { - stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ, - rtc_data->io + HW_RTC_CTRL); + if (status & STMP3XXX_RTC_CTRL_ONEMSEC_IRQ) { + stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ, + rtc_data->io + STMP3XXX_RTC_CTRL); if (++rtc_data->irq_count % 1000 == 0) { events |= RTC_UF | RTC_IRQF; rtc_data->irq_count = 0; @@ -100,17 +120,17 @@ static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - void __iomem *p = rtc_data->io + HW_RTC_PERSISTENT0, - *ctl = rtc_data->io + HW_RTC_CTRL; + void __iomem *p = rtc_data->io + STMP3XXX_RTC_PERSISTENT0, + *ctl = rtc_data->io + STMP3XXX_RTC_CTRL; if (enabled) { - stmp3xxx_setl(BM_RTC_PERSISTENT0_ALARM_EN | - BM_RTC_PERSISTENT0_ALARM_WAKE_EN, p); - stmp3xxx_setl(BM_RTC_CTRL_ALARM_IRQ_EN, ctl); + stmp3xxx_setl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, p); + stmp3xxx_setl(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, ctl); } else { - stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN | - BM_RTC_PERSISTENT0_ALARM_WAKE_EN, p); - stmp3xxx_clearl(BM_RTC_CTRL_ALARM_IRQ_EN, ctl); + stmp3xxx_clearl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, p); + stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, ctl); } return 0; } @@ -119,7 +139,8 @@ static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - rtc_time_to_tm(__raw_readl(rtc_data->io + HW_RTC_ALARM), &alm->time); + rtc_time_to_tm(__raw_readl(rtc_data->io + STMP3XXX_RTC_ALARM), + &alm->time); return 0; } @@ -129,7 +150,7 @@ static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); rtc_tm_to_time(&alm->time, &t); - __raw_writel(t, rtc_data->io + HW_RTC_ALARM); + __raw_writel(t, rtc_data->io + STMP3XXX_RTC_ALARM); return 0; } @@ -149,8 +170,9 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev) if (!rtc_data) return 0; - stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN | BM_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + HW_RTC_CTRL); + stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | + STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, + rtc_data->io + STMP3XXX_RTC_CTRL); free_irq(rtc_data->irq_alarm, &pdev->dev); free_irq(rtc_data->irq_1msec, &pdev->dev); rtc_device_unregister(rtc_data->rtc); @@ -187,18 +209,18 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) rtc_data->irq_alarm = platform_get_irq(pdev, 0); rtc_data->irq_1msec = platform_get_irq(pdev, 1); - if (!(__raw_readl(HW_RTC_STAT + rtc_data->io) & - BM_RTC_STAT_RTC_PRESENT)) { + if (!(__raw_readl(STMP3XXX_RTC_STAT + rtc_data->io) & + STMP3XXX_RTC_STAT_RTC_PRESENT)) { dev_err(&pdev->dev, "no device onboard\n"); err = -ENODEV; goto out_remap; } stmp3xxx_reset_block(rtc_data->io, true); - stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN | - BM_RTC_PERSISTENT0_ALARM_WAKE_EN | - BM_RTC_PERSISTENT0_ALARM_WAKE, - rtc_data->io + HW_RTC_PERSISTENT0); + stmp3xxx_clearl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, + rtc_data->io + STMP3XXX_RTC_PERSISTENT0); rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev, &stmp3xxx_rtc_ops, THIS_MODULE); if (IS_ERR(rtc_data->rtc)) { @@ -229,8 +251,9 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) out_irq1: free_irq(rtc_data->irq_alarm, &pdev->dev); out_irq_alarm: - stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN | BM_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + HW_RTC_CTRL); + stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | + STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, + rtc_data->io + STMP3XXX_RTC_CTRL); rtc_device_unregister(rtc_data->rtc); out_remap: iounmap(rtc_data->io); @@ -250,10 +273,10 @@ static int stmp3xxx_rtc_resume(struct platform_device *dev) struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(dev); stmp3xxx_reset_block(rtc_data->io, true); - stmp3xxx_clearl(BM_RTC_PERSISTENT0_ALARM_EN | - BM_RTC_PERSISTENT0_ALARM_WAKE_EN | - BM_RTC_PERSISTENT0_ALARM_WAKE, - rtc_data->io + HW_RTC_PERSISTENT0); + stmp3xxx_clearl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, + rtc_data->io + STMP3XXX_RTC_PERSISTENT0); return 0; } #else From 46b21218145ecef0936eb4338a9e0ffef84f00cf Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 25 May 2011 12:56:50 +0200 Subject: [PATCH 3/8] rtc: stmp3xxx: Port stmp-functions to mxs-equivalents The stmp3xxx driver used to include functions from a stmp-specific include. Because of consolidation, plat-stmp has now been removed and merged with the compatible mach-mxs. Use the apropriate mxs-functions for transition. The accessors will be converted to readl/writel in a later patch. Signed-off-by: Wolfram Sang Tested-by: Shawn Guo Signed-off-by: John Stultz --- drivers/rtc/Kconfig | 6 +++--- drivers/rtc/rtc-stmp3xxx.c | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index ce2aabf5c550..dcb61e23b985 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -981,11 +981,11 @@ config RTC_DRV_COH901331 config RTC_DRV_STMP - tristate "Freescale STMP3xxx RTC" - depends on ARCH_STMP3XXX + tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC" + depends on ARCH_MXS help If you say yes here you will get support for the onboard - STMP3xxx RTC. + STMP3xxx/i.MX23/i.MX28 RTC. This driver can also be built as a module. If so, the module will be called rtc-stmp3xxx. diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index e54bea076067..ac40f971a40e 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -24,8 +24,8 @@ #include #include -#include -#include +#include +#include #define STMP3XXX_RTC_CTRL 0x0 #define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 @@ -97,13 +97,13 @@ static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) STMP3XXX_RTC_CTRL_ONEMSEC_IRQ); if (status & STMP3XXX_RTC_CTRL_ALARM_IRQ) { - stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ALARM_IRQ, + __mxs_clrl(STMP3XXX_RTC_CTRL_ALARM_IRQ, rtc_data->io + STMP3XXX_RTC_CTRL); events |= RTC_AF | RTC_IRQF; } if (status & STMP3XXX_RTC_CTRL_ONEMSEC_IRQ) { - stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ, + __mxs_clrl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ, rtc_data->io + STMP3XXX_RTC_CTRL); if (++rtc_data->irq_count % 1000 == 0) { events |= RTC_UF | RTC_IRQF; @@ -124,13 +124,13 @@ static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled) *ctl = rtc_data->io + STMP3XXX_RTC_CTRL; if (enabled) { - stmp3xxx_setl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + __mxs_setl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, p); - stmp3xxx_setl(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, ctl); + __mxs_setl(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, ctl); } else { - stmp3xxx_clearl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + __mxs_clrl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, p); - stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, ctl); + __mxs_clrl(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, ctl); } return 0; } @@ -170,7 +170,7 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev) if (!rtc_data) return 0; - stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | + __mxs_clrl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, rtc_data->io + STMP3XXX_RTC_CTRL); free_irq(rtc_data->irq_alarm, &pdev->dev); @@ -216,8 +216,8 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) goto out_remap; } - stmp3xxx_reset_block(rtc_data->io, true); - stmp3xxx_clearl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + mxs_reset_block(rtc_data->io); + __mxs_clrl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, rtc_data->io + STMP3XXX_RTC_PERSISTENT0); @@ -251,7 +251,7 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) out_irq1: free_irq(rtc_data->irq_alarm, &pdev->dev); out_irq_alarm: - stmp3xxx_clearl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | + __mxs_clrl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, rtc_data->io + STMP3XXX_RTC_CTRL); rtc_device_unregister(rtc_data->rtc); @@ -272,8 +272,8 @@ static int stmp3xxx_rtc_resume(struct platform_device *dev) { struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(dev); - stmp3xxx_reset_block(rtc_data->io, true); - stmp3xxx_clearl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + mxs_reset_block(rtc_data->io); + __mxs_clrl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, rtc_data->io + STMP3XXX_RTC_PERSISTENT0); From a91d2bab355f3a5caa767d7316f80422bfcd2ad6 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 25 May 2011 12:56:51 +0200 Subject: [PATCH 4/8] rtc: stmp3xxx: Initialize drvdata before registering device Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") uncovered an issue in a number of RTC drivers, where the drivers call rtc_device_register before initializing the device or platform drvdata. This frequently results in null pointer dereferences when the rtc_device_register immediately makes use of the rtc device, calling rtc_read_alarm. The solution is to ensure the drvdata is initialized prior to registering the rtc device. Signed-off-by: Wolfram Sang Tested-by: Shawn Guo Signed-off-by: John Stultz --- drivers/rtc/rtc-stmp3xxx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index ac40f971a40e..90f05fe60620 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -176,6 +176,7 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev) free_irq(rtc_data->irq_alarm, &pdev->dev); free_irq(rtc_data->irq_1msec, &pdev->dev); rtc_device_unregister(rtc_data->rtc); + platform_set_drvdata(pdev, NULL); iounmap(rtc_data->io); kfree(rtc_data); @@ -216,11 +217,14 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) goto out_remap; } + platform_set_drvdata(pdev, rtc_data); + mxs_reset_block(rtc_data->io); __mxs_clrl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, rtc_data->io + STMP3XXX_RTC_PERSISTENT0); + rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev, &stmp3xxx_rtc_ops, THIS_MODULE); if (IS_ERR(rtc_data->rtc)) { @@ -244,8 +248,6 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) goto out_irq1; } - platform_set_drvdata(pdev, rtc_data); - return 0; out_irq1: @@ -256,6 +258,7 @@ out_irq_alarm: rtc_data->io + STMP3XXX_RTC_CTRL); rtc_device_unregister(rtc_data->rtc); out_remap: + platform_set_drvdata(pdev, NULL); iounmap(rtc_data->io); out_free: kfree(rtc_data); From b5167159d4341d408ef6b941975f2fe8973b2a94 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 25 May 2011 12:56:52 +0200 Subject: [PATCH 5/8] rtc: stmp3xxx: Get rid of mach-specific accessors Replace the accessors with standard readl/writel to remove their platform-dependency. Also, drop __raw_(read|write)l-accessors while we are here. Signed-off-by: Wolfram Sang Tested-by: Shawn Guo Signed-off-by: John Stultz --- drivers/rtc/rtc-stmp3xxx.c | 64 ++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 90f05fe60620..ad1851796940 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -18,6 +18,7 @@ */ #include #include +#include #include #include #include @@ -25,9 +26,10 @@ #include #include -#include #define STMP3XXX_RTC_CTRL 0x0 +#define STMP3XXX_RTC_CTRL_SET 0x4 +#define STMP3XXX_RTC_CTRL_CLR 0x8 #define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 #define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002 #define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004 @@ -42,6 +44,8 @@ #define STMP3XXX_RTC_ALARM 0x40 #define STMP3XXX_RTC_PERSISTENT0 0x60 +#define STMP3XXX_RTC_PERSISTENT0_SET 0x64 +#define STMP3XXX_RTC_PERSISTENT0_CLR 0x68 #define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002 #define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004 #define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080 @@ -60,7 +64,7 @@ static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0, * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS */ - while (__raw_readl(rtc_data->io + STMP3XXX_RTC_STAT) & + while (readl(rtc_data->io + STMP3XXX_RTC_STAT) & (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) cpu_relax(); } @@ -71,8 +75,7 @@ static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); stmp3xxx_wait_time(rtc_data); - rtc_time_to_tm(__raw_readl(rtc_data->io + STMP3XXX_RTC_SECONDS), - rtc_tm); + rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm); return 0; } @@ -80,7 +83,7 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - __raw_writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS); + writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS); stmp3xxx_wait_time(rtc_data); return 0; } @@ -92,19 +95,19 @@ static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) u32 status; u32 events = 0; - status = __raw_readl(rtc_data->io + STMP3XXX_RTC_CTRL) & + status = readl(rtc_data->io + STMP3XXX_RTC_CTRL) & (STMP3XXX_RTC_CTRL_ALARM_IRQ | STMP3XXX_RTC_CTRL_ONEMSEC_IRQ); if (status & STMP3XXX_RTC_CTRL_ALARM_IRQ) { - __mxs_clrl(STMP3XXX_RTC_CTRL_ALARM_IRQ, - rtc_data->io + STMP3XXX_RTC_CTRL); + writel(STMP3XXX_RTC_CTRL_ALARM_IRQ, + rtc_data->io + STMP3XXX_RTC_CTRL_CLR); events |= RTC_AF | RTC_IRQF; } if (status & STMP3XXX_RTC_CTRL_ONEMSEC_IRQ) { - __mxs_clrl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ, - rtc_data->io + STMP3XXX_RTC_CTRL); + writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ, + rtc_data->io + STMP3XXX_RTC_CTRL_CLR); if (++rtc_data->irq_count % 1000 == 0) { events |= RTC_UF | RTC_IRQF; rtc_data->irq_count = 0; @@ -120,17 +123,19 @@ static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - void __iomem *p = rtc_data->io + STMP3XXX_RTC_PERSISTENT0, - *ctl = rtc_data->io + STMP3XXX_RTC_CTRL; if (enabled) { - __mxs_setl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, p); - __mxs_setl(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, ctl); + writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, + rtc_data->io + STMP3XXX_RTC_PERSISTENT0_SET); + writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, + rtc_data->io + STMP3XXX_RTC_CTRL_SET); } else { - __mxs_clrl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | - STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, p); - __mxs_clrl(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, ctl); + writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, + rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); + writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, + rtc_data->io + STMP3XXX_RTC_CTRL_CLR); } return 0; } @@ -139,8 +144,7 @@ static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - rtc_time_to_tm(__raw_readl(rtc_data->io + STMP3XXX_RTC_ALARM), - &alm->time); + rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_ALARM), &alm->time); return 0; } @@ -150,7 +154,7 @@ static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); rtc_tm_to_time(&alm->time, &t); - __raw_writel(t, rtc_data->io + STMP3XXX_RTC_ALARM); + writel(t, rtc_data->io + STMP3XXX_RTC_ALARM); return 0; } @@ -170,9 +174,9 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev) if (!rtc_data) return 0; - __mxs_clrl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | + writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL); + rtc_data->io + STMP3XXX_RTC_CTRL_CLR); free_irq(rtc_data->irq_alarm, &pdev->dev); free_irq(rtc_data->irq_1msec, &pdev->dev); rtc_device_unregister(rtc_data->rtc); @@ -210,7 +214,7 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) rtc_data->irq_alarm = platform_get_irq(pdev, 0); rtc_data->irq_1msec = platform_get_irq(pdev, 1); - if (!(__raw_readl(STMP3XXX_RTC_STAT + rtc_data->io) & + if (!(readl(STMP3XXX_RTC_STAT + rtc_data->io) & STMP3XXX_RTC_STAT_RTC_PRESENT)) { dev_err(&pdev->dev, "no device onboard\n"); err = -ENODEV; @@ -220,10 +224,10 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc_data); mxs_reset_block(rtc_data->io); - __mxs_clrl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0); + rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev, &stmp3xxx_rtc_ops, THIS_MODULE); @@ -253,9 +257,9 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) out_irq1: free_irq(rtc_data->irq_alarm, &pdev->dev); out_irq_alarm: - __mxs_clrl(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | + writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL); + rtc_data->io + STMP3XXX_RTC_CTRL_CLR); rtc_device_unregister(rtc_data->rtc); out_remap: platform_set_drvdata(pdev, NULL); @@ -276,10 +280,10 @@ static int stmp3xxx_rtc_resume(struct platform_device *dev) struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(dev); mxs_reset_block(rtc_data->io); - __mxs_clrl(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | + writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0); + rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); return 0; } #else From 7e794cb7e36ccdb8c44b8ca7738720625b7aa2da Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 25 May 2011 12:56:53 +0200 Subject: [PATCH 6/8] rtc: stmp3xxx: Remove UIE handlers The RTC core handles UIE since 6610e08 (RTC: Rework RTC code to use timerqueue for events), so remove the specific interrupt in this driver. To make it work at all, enable interrupts in set_alarm() if needed. Drop IRQF_DISABLED which is deprecated, while we are here. Finally, add my copyright after all these changes. Signed-off-by: Wolfram Sang Tested-by: Shawn Guo Signed-off-by: John Stultz --- drivers/rtc/rtc-stmp3xxx.c | 61 +++++++++++--------------------------- 1 file changed, 18 insertions(+), 43 deletions(-) diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index ad1851796940..7315068daa59 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -6,6 +6,7 @@ * * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + * Copyright 2011 Wolfram Sang, Pengutronix e.K. */ /* @@ -33,7 +34,6 @@ #define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 #define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002 #define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004 -#define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ 0x00000008 #define STMP3XXX_RTC_STAT 0x10 #define STMP3XXX_RTC_STAT_STALE_SHIFT 16 @@ -52,9 +52,8 @@ struct stmp3xxx_rtc_data { struct rtc_device *rtc; - unsigned irq_count; void __iomem *io; - int irq_alarm, irq_1msec; + int irq_alarm; }; static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) @@ -92,32 +91,16 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) { struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev_id); - u32 status; - u32 events = 0; - - status = readl(rtc_data->io + STMP3XXX_RTC_CTRL) & - (STMP3XXX_RTC_CTRL_ALARM_IRQ | - STMP3XXX_RTC_CTRL_ONEMSEC_IRQ); + u32 status = readl(rtc_data->io + STMP3XXX_RTC_CTRL); if (status & STMP3XXX_RTC_CTRL_ALARM_IRQ) { writel(STMP3XXX_RTC_CTRL_ALARM_IRQ, rtc_data->io + STMP3XXX_RTC_CTRL_CLR); - events |= RTC_AF | RTC_IRQF; + rtc_update_irq(rtc_data->rtc, 1, RTC_AF | RTC_IRQF); + return IRQ_HANDLED; } - if (status & STMP3XXX_RTC_CTRL_ONEMSEC_IRQ) { - writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); - if (++rtc_data->irq_count % 1000 == 0) { - events |= RTC_UF | RTC_IRQF; - rtc_data->irq_count = 0; - } - } - - if (events) - rtc_update_irq(rtc_data->rtc, 1, events); - - return IRQ_HANDLED; + return IRQ_NONE; } static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled) @@ -155,6 +138,9 @@ static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) rtc_tm_to_time(&alm->time, &t); writel(t, rtc_data->io + STMP3XXX_RTC_ALARM); + + stmp3xxx_alarm_irq_enable(dev, alm->enabled); + return 0; } @@ -174,11 +160,9 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev) if (!rtc_data) return 0; - writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | - STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, + writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, rtc_data->io + STMP3XXX_RTC_CTRL_CLR); free_irq(rtc_data->irq_alarm, &pdev->dev); - free_irq(rtc_data->irq_1msec, &pdev->dev); rtc_device_unregister(rtc_data->rtc); platform_set_drvdata(pdev, NULL); iounmap(rtc_data->io); @@ -212,7 +196,6 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) } rtc_data->irq_alarm = platform_get_irq(pdev, 0); - rtc_data->irq_1msec = platform_get_irq(pdev, 1); if (!(readl(STMP3XXX_RTC_STAT + rtc_data->io) & STMP3XXX_RTC_STAT_RTC_PRESENT)) { @@ -229,6 +212,10 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); + writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | + STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, + rtc_data->io + STMP3XXX_RTC_CTRL_CLR); + rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev, &stmp3xxx_rtc_ops, THIS_MODULE); if (IS_ERR(rtc_data->rtc)) { @@ -236,30 +223,17 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) goto out_remap; } - rtc_data->irq_count = 0; - err = request_irq(rtc_data->irq_alarm, stmp3xxx_rtc_interrupt, - IRQF_DISABLED, "RTC alarm", &pdev->dev); + err = request_irq(rtc_data->irq_alarm, stmp3xxx_rtc_interrupt, 0, + "RTC alarm", &pdev->dev); if (err) { dev_err(&pdev->dev, "Cannot claim IRQ%d\n", rtc_data->irq_alarm); goto out_irq_alarm; } - err = request_irq(rtc_data->irq_1msec, stmp3xxx_rtc_interrupt, - IRQF_DISABLED, "RTC tick", &pdev->dev); - if (err) { - dev_err(&pdev->dev, "Cannot claim IRQ%d\n", - rtc_data->irq_1msec); - goto out_irq1; - } return 0; -out_irq1: - free_irq(rtc_data->irq_alarm, &pdev->dev); out_irq_alarm: - writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | - STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); rtc_device_unregister(rtc_data->rtc); out_remap: platform_set_drvdata(pdev, NULL); @@ -316,5 +290,6 @@ module_init(stmp3xxx_rtc_init); module_exit(stmp3xxx_rtc_exit); MODULE_DESCRIPTION("STMP3xxx RTC Driver"); -MODULE_AUTHOR("dmitry pervushin "); +MODULE_AUTHOR("dmitry pervushin and " + "Wolfram Sang "); MODULE_LICENSE("GPL"); From ac619f4eba45da10053fc991f8a5d47b3be79fa3 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 19 Jul 2011 11:39:03 +0100 Subject: [PATCH 7/8] x86: Serialize SMP bootup CMOS accesses on rtc_lock With CPU hotplug, there is a theoretical race between other CMOS (namely RTC) accesses and those done in the SMP secondary processor bringup path. I am unware of the problem having been noticed by anyone in practice, but it would very likely be rather spurious and very hard to reproduce. So to be on the safe side, acquire rtc_lock around those accesses. Signed-off-by: Jan Beulich Cc: John Stultz Link: http://lkml.kernel.org/r/4E257AE7020000780004E2FF@nat28.tlf.novell.com Signed-off-by: Ingo Molnar --- arch/x86/include/asm/smpboot_hooks.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/include/asm/smpboot_hooks.h b/arch/x86/include/asm/smpboot_hooks.h index 725b77831993..49adfd7bb4a4 100644 --- a/arch/x86/include/asm/smpboot_hooks.h +++ b/arch/x86/include/asm/smpboot_hooks.h @@ -10,7 +10,11 @@ static inline void smpboot_clear_io_apic_irqs(void) static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) { + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(0xa, 0xf); + spin_unlock_irqrestore(&rtc_lock, flags); local_flush_tlb(); pr_debug("1.\n"); *((volatile unsigned short *)phys_to_virt(apic->trampoline_phys_high)) = @@ -23,6 +27,8 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) static inline void smpboot_restore_warm_reset_vector(void) { + unsigned long flags; + /* * Install writable page 0 entry to set BIOS data area. */ @@ -32,7 +38,9 @@ static inline void smpboot_restore_warm_reset_vector(void) * Paranoid: Set warm reset code and vector here back * to default values. */ + spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(0, 0xf); + spin_unlock_irqrestore(&rtc_lock, flags); *((volatile u32 *)phys_to_virt(apic->trampoline_phys_low)) = 0; } From ef68c8f87ed13f65df867dddf36c0e185b27b942 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 19 Jul 2011 11:53:07 +0100 Subject: [PATCH 8/8] x86: Serialize EFI time accesses on rtc_lock The EFI specification requires that callers of the time related runtime functions serialize with other CMOS accesses in the kernel, as the EFI time functions may choose to also use the legacy CMOS RTC. Besides fixing a latent bug, this is a prerequisite to safely enable the rtc-efi driver for x86, which ought to be preferred over rtc-cmos on all EFI platforms. Signed-off-by: Jan Beulich Acked-by: Matthew Garrett Cc: Link: http://lkml.kernel.org/r/4E257E33020000780004E319@nat28.tlf.novell.com Signed-off-by: Ingo Molnar Cc: Matthew Garrett --- arch/x86/platform/efi/efi.c | 39 +++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 474356b98ede..b8823d5a0117 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -79,26 +79,50 @@ early_param("add_efi_memmap", setup_add_efi_memmap); static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) { - return efi_call_virt2(get_time, tm, tc); + unsigned long flags; + efi_status_t status; + + spin_lock_irqsave(&rtc_lock, flags); + status = efi_call_virt2(get_time, tm, tc); + spin_unlock_irqrestore(&rtc_lock, flags); + return status; } static efi_status_t virt_efi_set_time(efi_time_t *tm) { - return efi_call_virt1(set_time, tm); + unsigned long flags; + efi_status_t status; + + spin_lock_irqsave(&rtc_lock, flags); + status = efi_call_virt1(set_time, tm); + spin_unlock_irqrestore(&rtc_lock, flags); + return status; } static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) { - return efi_call_virt3(get_wakeup_time, - enabled, pending, tm); + unsigned long flags; + efi_status_t status; + + spin_lock_irqsave(&rtc_lock, flags); + status = efi_call_virt3(get_wakeup_time, + enabled, pending, tm); + spin_unlock_irqrestore(&rtc_lock, flags); + return status; } static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) { - return efi_call_virt2(set_wakeup_time, - enabled, tm); + unsigned long flags; + efi_status_t status; + + spin_lock_irqsave(&rtc_lock, flags); + status = efi_call_virt2(set_wakeup_time, + enabled, tm); + spin_unlock_irqrestore(&rtc_lock, flags); + return status; } static efi_status_t virt_efi_get_variable(efi_char16_t *name, @@ -164,11 +188,14 @@ static efi_status_t __init phys_efi_set_virtual_address_map( static efi_status_t __init phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) { + unsigned long flags; efi_status_t status; + spin_lock_irqsave(&rtc_lock, flags); efi_call_phys_prelog(); status = efi_call_phys2(efi_phys.get_time, tm, tc); efi_call_phys_epilog(); + spin_unlock_irqrestore(&rtc_lock, flags); return status; }