aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Lunn <andrew@lunn.ch>2013-02-03 06:32:06 -0500
committerJason Cooper <jason@lakedaemon.net>2013-03-08 16:34:41 -0500
commit89c58c198b252f2bc20657fdd72a2aea788c435c (patch)
tree735d8844993deb5a8d39efb171db8331241ce547
parentde88747f514a4e0cca416a8871de2302f4f77790 (diff)
rtc: rtc-mv: Add support for clk to avoid lockups
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>
-rw-r--r--arch/arm/boot/dts/kirkwood.dtsi1
-rw-r--r--drivers/rtc/rtc-mv.c28
2 files changed, 25 insertions, 4 deletions
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
index cf8e8926a034..fada7e6d24d8 100644
--- a/arch/arm/boot/dts/kirkwood.dtsi
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -75,6 +75,7 @@
75 compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc"; 75 compatible = "marvell,kirkwood-rtc", "marvell,orion-rtc";
76 reg = <0x10300 0x20>; 76 reg = <0x10300 0x20>;
77 interrupts = <53>; 77 interrupts = <53>;
78 clocks = <&gate_clk 7>;
78 }; 79 };
79 80
80 spi@10600 { 81 spi@10600 {
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index 57233c885998..8f87fec27ce7 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -14,6 +14,7 @@
14#include <linux/platform_device.h> 14#include <linux/platform_device.h>
15#include <linux/of.h> 15#include <linux/of.h>
16#include <linux/delay.h> 16#include <linux/delay.h>
17#include <linux/clk.h>
17#include <linux/gfp.h> 18#include <linux/gfp.h>
18#include <linux/module.h> 19#include <linux/module.h>
19 20
@@ -41,6 +42,7 @@ struct rtc_plat_data {
41 struct rtc_device *rtc; 42 struct rtc_device *rtc;
42 void __iomem *ioaddr; 43 void __iomem *ioaddr;
43 int irq; 44 int irq;
45 struct clk *clk;
44}; 46};
45 47
46static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) 48static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm)
@@ -221,6 +223,7 @@ static int mv_rtc_probe(struct platform_device *pdev)
221 struct rtc_plat_data *pdata; 223 struct rtc_plat_data *pdata;
222 resource_size_t size; 224 resource_size_t size;
223 u32 rtc_time; 225 u32 rtc_time;
226 int ret = 0;
224 227
225 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 228 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
226 if (!res) 229 if (!res)
@@ -239,11 +242,17 @@ static int mv_rtc_probe(struct platform_device *pdev)
239 if (!pdata->ioaddr) 242 if (!pdata->ioaddr)
240 return -ENOMEM; 243 return -ENOMEM;
241 244
245 pdata->clk = devm_clk_get(&pdev->dev, NULL);
246 /* Not all SoCs require a clock.*/
247 if (!IS_ERR(pdata->clk))
248 clk_prepare_enable(pdata->clk);
249
242 /* make sure the 24 hours mode is enabled */ 250 /* make sure the 24 hours mode is enabled */
243 rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS); 251 rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS);
244 if (rtc_time & RTC_HOURS_12H_MODE) { 252 if (rtc_time & RTC_HOURS_12H_MODE) {
245 dev_err(&pdev->dev, "24 Hours mode not supported.\n"); 253 dev_err(&pdev->dev, "24 Hours mode not supported.\n");
246 return -EINVAL; 254 ret = -EINVAL;
255 goto out;
247 } 256 }
248 257
249 /* make sure it is actually functional */ 258 /* make sure it is actually functional */
@@ -252,7 +261,8 @@ static int mv_rtc_probe(struct platform_device *pdev)
252 rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS); 261 rtc_time = readl(pdata->ioaddr + RTC_TIME_REG_OFFS);
253 if (rtc_time == 0x01000000) { 262 if (rtc_time == 0x01000000) {
254 dev_err(&pdev->dev, "internal RTC not ticking\n"); 263 dev_err(&pdev->dev, "internal RTC not ticking\n");
255 return -ENODEV; 264 ret = -ENODEV;
265 goto out;
256 } 266 }
257 } 267 }
258 268
@@ -268,8 +278,10 @@ static int mv_rtc_probe(struct platform_device *pdev)
268 } else 278 } else
269 pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, 279 pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,
270 &mv_rtc_ops, THIS_MODULE); 280 &mv_rtc_ops, THIS_MODULE);
271 if (IS_ERR(pdata->rtc)) 281 if (IS_ERR(pdata->rtc)) {
272 return PTR_ERR(pdata->rtc); 282 ret = PTR_ERR(pdata->rtc);
283 goto out;
284 }
273 285
274 if (pdata->irq >= 0) { 286 if (pdata->irq >= 0) {
275 writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); 287 writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
@@ -282,6 +294,11 @@ static int mv_rtc_probe(struct platform_device *pdev)
282 } 294 }
283 295
284 return 0; 296 return 0;
297out:
298 if (!IS_ERR(pdata->clk))
299 clk_disable_unprepare(pdata->clk);
300
301 return ret;
285} 302}
286 303
287static int __exit mv_rtc_remove(struct platform_device *pdev) 304static int __exit mv_rtc_remove(struct platform_device *pdev)
@@ -292,6 +309,9 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)
292 device_init_wakeup(&pdev->dev, 0); 309 device_init_wakeup(&pdev->dev, 0);
293 310
294 rtc_device_unregister(pdata->rtc); 311 rtc_device_unregister(pdata->rtc);
312 if (!IS_ERR(pdata->clk))
313 clk_disable_unprepare(pdata->clk);
314
295 return 0; 315 return 0;
296} 316}
297 317