diff options
Diffstat (limited to 'drivers/rtc/rtc-at91sam9.c')
-rw-r--r-- | drivers/rtc/rtc-at91sam9.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index be9c28b9d057..abac38abd38e 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/mfd/syscon.h> | 24 | #include <linux/mfd/syscon.h> |
25 | #include <linux/regmap.h> | 25 | #include <linux/regmap.h> |
26 | #include <linux/clk.h> | ||
26 | 27 | ||
27 | /* | 28 | /* |
28 | * This driver uses two configurable hardware resources that live in the | 29 | * This driver uses two configurable hardware resources that live in the |
@@ -61,8 +62,6 @@ | |||
61 | #define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */ | 62 | #define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */ |
62 | #define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */ | 63 | #define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */ |
63 | 64 | ||
64 | #define AT91_SLOW_CLOCK 32768 | ||
65 | |||
66 | /* | 65 | /* |
67 | * We store ALARM_DISABLED in ALMV to record that no alarm is set. | 66 | * We store ALARM_DISABLED in ALMV to record that no alarm is set. |
68 | * It's also the reset value for that field. | 67 | * It's also the reset value for that field. |
@@ -77,6 +76,7 @@ struct sam9_rtc { | |||
77 | struct regmap *gpbr; | 76 | struct regmap *gpbr; |
78 | unsigned int gpbr_offset; | 77 | unsigned int gpbr_offset; |
79 | int irq; | 78 | int irq; |
79 | struct clk *sclk; | ||
80 | }; | 80 | }; |
81 | 81 | ||
82 | #define rtt_readl(rtc, field) \ | 82 | #define rtt_readl(rtc, field) \ |
@@ -328,6 +328,7 @@ static int at91_rtc_probe(struct platform_device *pdev) | |||
328 | struct sam9_rtc *rtc; | 328 | struct sam9_rtc *rtc; |
329 | int ret, irq; | 329 | int ret, irq; |
330 | u32 mr; | 330 | u32 mr; |
331 | unsigned int sclk_rate; | ||
331 | 332 | ||
332 | irq = platform_get_irq(pdev, 0); | 333 | irq = platform_get_irq(pdev, 0); |
333 | if (irq < 0) { | 334 | if (irq < 0) { |
@@ -385,11 +386,27 @@ static int at91_rtc_probe(struct platform_device *pdev) | |||
385 | return -ENOMEM; | 386 | return -ENOMEM; |
386 | } | 387 | } |
387 | 388 | ||
389 | rtc->sclk = devm_clk_get(&pdev->dev, NULL); | ||
390 | if (IS_ERR(rtc->sclk)) | ||
391 | return PTR_ERR(rtc->sclk); | ||
392 | |||
393 | sclk_rate = clk_get_rate(rtc->sclk); | ||
394 | if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) { | ||
395 | dev_err(&pdev->dev, "Invalid slow clock rate\n"); | ||
396 | return -EINVAL; | ||
397 | } | ||
398 | |||
399 | ret = clk_prepare_enable(rtc->sclk); | ||
400 | if (ret) { | ||
401 | dev_err(&pdev->dev, "Could not enable slow clock\n"); | ||
402 | return ret; | ||
403 | } | ||
404 | |||
388 | mr = rtt_readl(rtc, MR); | 405 | mr = rtt_readl(rtc, MR); |
389 | 406 | ||
390 | /* unless RTT is counting at 1 Hz, re-initialize it */ | 407 | /* unless RTT is counting at 1 Hz, re-initialize it */ |
391 | if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) { | 408 | if ((mr & AT91_RTT_RTPRES) != sclk_rate) { |
392 | mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES); | 409 | mr = AT91_RTT_RTTRST | (sclk_rate & AT91_RTT_RTPRES); |
393 | gpbr_writel(rtc, 0); | 410 | gpbr_writel(rtc, 0); |
394 | } | 411 | } |
395 | 412 | ||
@@ -434,6 +451,9 @@ static int at91_rtc_remove(struct platform_device *pdev) | |||
434 | /* disable all interrupts */ | 451 | /* disable all interrupts */ |
435 | rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); | 452 | rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); |
436 | 453 | ||
454 | if (!IS_ERR(rtc->sclk)) | ||
455 | clk_disable_unprepare(rtc->sclk); | ||
456 | |||
437 | return 0; | 457 | return 0; |
438 | } | 458 | } |
439 | 459 | ||