Skip to content

Commit

Permalink
rtc: rtc-mv: Add support for clk to avoid lockups
Browse files Browse the repository at this point in the history
The Marvell RTC on Kirkwood makes use of the runit clock. Ensure the
driver clk_prepare_enable() this clock, otherwise there is a danger
the SoC will lockup when accessing RTC registers with the clock
disabled.

Reported-by: Simon Baatz <gmbnomis@gmail.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: Simon Baatz <gmbnomis@gmail.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
  • Loading branch information
Andrew Lunn authored and Jason Cooper committed Mar 8, 2013
1 parent de88747 commit 89c58c1
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 4 deletions.
1 change: 1 addition & 0 deletions arch/arm/boot/dts/kirkwood.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc";
reg = <0x10300 0x20>;
interrupts = <53>;
clocks = <&gate_clk 7>;
};

spi@10600 {
Expand Down
28 changes: 24 additions & 4 deletions drivers/rtc/rtc-mv.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/gfp.h>
#include <linux/module.h>

Expand Down Expand Up @@ -41,6 +42,7 @@ struct rtc_plat_data {
struct rtc_device *rtc;
void __iomem *ioaddr;
int irq;
struct clk *clk;
};

static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm)
Expand Down Expand Up @@ -221,6 +223,7 @@ static int mv_rtc_probe(struct platform_device *pdev)
struct rtc_plat_data *pdata;
resource_size_t size;
u32 rtc_time;
int ret = 0;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
Expand All @@ -239,11 +242,17 @@ static int mv_rtc_probe(struct platform_device *pdev)
if (!pdata->ioaddr)
return -ENOMEM;

pdata->clk = devm_clk_get(&pdev->dev, NULL);
/* Not all SoCs require a clock.*/
if (!IS_ERR(pdata->clk))
clk_prepare_enable(pdata->clk);

/* make sure the 24 hours mode is enabled */
rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS);
if (rtc_time & RTC_HOURS_12H_MODE) {
dev_err(&pdev->dev, "24 Hours mode not supported.\n");
return -EINVAL;
ret = -EINVAL;
goto out;
}

/* make sure it is actually functional */
Expand All @@ -252,7 +261,8 @@ static int mv_rtc_probe(struct platform_device *pdev)
rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS);
if (rtc_time == 0x01000000) {
dev_err(&pdev->dev, "internal RTC not ticking\n");
return -ENODEV;
ret = -ENODEV;
goto out;
}
}

Expand All @@ -268,8 +278,10 @@ static int mv_rtc_probe(struct platform_device *pdev)
} else
pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,
&mv_rtc_ops, THIS_MODULE);
if (IS_ERR(pdata->rtc))
return PTR_ERR(pdata->rtc);
if (IS_ERR(pdata->rtc)) {
ret = PTR_ERR(pdata->rtc);
goto out;
}

if (pdata->irq >= 0) {
writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
Expand All @@ -282,6 +294,11 @@ static int mv_rtc_probe(struct platform_device *pdev)
}

return 0;
out:
if (!IS_ERR(pdata->clk))
clk_disable_unprepare(pdata->clk);

return ret;
}

static int __exit mv_rtc_remove(struct platform_device *pdev)
Expand All @@ -292,6 +309,9 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);

rtc_device_unregister(pdata->rtc);
if (!IS_ERR(pdata->clk))
clk_disable_unprepare(pdata->clk);

return 0;
}

Expand Down

0 comments on commit 89c58c1

Please sign in to comment.