aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-at91sam9.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc/rtc-at91sam9.c')
-rw-r--r--drivers/rtc/rtc-at91sam9.c138
1 files changed, 109 insertions, 29 deletions
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 596374304532..abac38abd38e 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -21,10 +21,9 @@
21#include <linux/slab.h> 21#include <linux/slab.h>
22#include <linux/platform_data/atmel.h> 22#include <linux/platform_data/atmel.h>
23#include <linux/io.h> 23#include <linux/io.h>
24 24#include <linux/mfd/syscon.h>
25#include <mach/at91_rtt.h> 25#include <linux/regmap.h>
26#include <mach/cpu.h> 26#include <linux/clk.h>
27#include <mach/hardware.h>
28 27
29/* 28/*
30 * This driver uses two configurable hardware resources that live in the 29 * This driver uses two configurable hardware resources that live in the
@@ -47,6 +46,22 @@
47 * registers available, likewise usable for more than "RTC" support. 46 * registers available, likewise usable for more than "RTC" support.
48 */ 47 */
49 48
49#define AT91_RTT_MR 0x00 /* Real-time Mode Register */
50#define AT91_RTT_RTPRES (0xffff << 0) /* Real-time Timer Prescaler Value */
51#define AT91_RTT_ALMIEN (1 << 16) /* Alarm Interrupt Enable */
52#define AT91_RTT_RTTINCIEN (1 << 17) /* Real Time Timer Increment Interrupt Enable */
53#define AT91_RTT_RTTRST (1 << 18) /* Real Time Timer Restart */
54
55#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */
56#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */
57
58#define AT91_RTT_VR 0x08 /* Real-time Value Register */
59#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */
60
61#define AT91_RTT_SR 0x0c /* Real-time Status Register */
62#define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */
63#define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */
64
50/* 65/*
51 * 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.
52 * It's also the reset value for that field. 67 * It's also the reset value for that field.
@@ -58,19 +73,30 @@ struct sam9_rtc {
58 void __iomem *rtt; 73 void __iomem *rtt;
59 struct rtc_device *rtcdev; 74 struct rtc_device *rtcdev;
60 u32 imr; 75 u32 imr;
61 void __iomem *gpbr; 76 struct regmap *gpbr;
77 unsigned int gpbr_offset;
62 int irq; 78 int irq;
79 struct clk *sclk;
63}; 80};
64 81
65#define rtt_readl(rtc, field) \ 82#define rtt_readl(rtc, field) \
66 __raw_readl((rtc)->rtt + AT91_RTT_ ## field) 83 readl((rtc)->rtt + AT91_RTT_ ## field)
67#define rtt_writel(rtc, field, val) \ 84#define rtt_writel(rtc, field, val) \
68 __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field) 85 writel((val), (rtc)->rtt + AT91_RTT_ ## field)
86
87static inline unsigned int gpbr_readl(struct sam9_rtc *rtc)
88{
89 unsigned int val;
90
91 regmap_read(rtc->gpbr, rtc->gpbr_offset, &val);
69 92
70#define gpbr_readl(rtc) \ 93 return val;
71 __raw_readl((rtc)->gpbr) 94}
72#define gpbr_writel(rtc, val) \ 95
73 __raw_writel((val), (rtc)->gpbr) 96static inline void gpbr_writel(struct sam9_rtc *rtc, unsigned int val)
97{
98 regmap_write(rtc->gpbr, rtc->gpbr_offset, val);
99}
74 100
75/* 101/*
76 * Read current time and date in RTC 102 * Read current time and date in RTC
@@ -287,22 +313,22 @@ static const struct rtc_class_ops at91_rtc_ops = {
287 .alarm_irq_enable = at91_rtc_alarm_irq_enable, 313 .alarm_irq_enable = at91_rtc_alarm_irq_enable,
288}; 314};
289 315
316static struct regmap_config gpbr_regmap_config = {
317 .reg_bits = 32,
318 .val_bits = 32,
319 .reg_stride = 4,
320};
321
290/* 322/*
291 * Initialize and install RTC driver 323 * Initialize and install RTC driver
292 */ 324 */
293static int at91_rtc_probe(struct platform_device *pdev) 325static int at91_rtc_probe(struct platform_device *pdev)
294{ 326{
295 struct resource *r, *r_gpbr; 327 struct resource *r;
296 struct sam9_rtc *rtc; 328 struct sam9_rtc *rtc;
297 int ret, irq; 329 int ret, irq;
298 u32 mr; 330 u32 mr;
299 331 unsigned int sclk_rate;
300 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
301 r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
302 if (!r || !r_gpbr) {
303 dev_err(&pdev->dev, "need 2 ressources\n");
304 return -ENODEV;
305 }
306 332
307 irq = platform_get_irq(pdev, 0); 333 irq = platform_get_irq(pdev, 0);
308 if (irq < 0) { 334 if (irq < 0) {
@@ -321,24 +347,66 @@ static int at91_rtc_probe(struct platform_device *pdev)
321 device_init_wakeup(&pdev->dev, 1); 347 device_init_wakeup(&pdev->dev, 1);
322 348
323 platform_set_drvdata(pdev, rtc); 349 platform_set_drvdata(pdev, rtc);
324 rtc->rtt = devm_ioremap(&pdev->dev, r->start, resource_size(r)); 350
325 if (!rtc->rtt) { 351 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
326 dev_err(&pdev->dev, "failed to map registers, aborting.\n"); 352 rtc->rtt = devm_ioremap_resource(&pdev->dev, r);
327 return -ENOMEM; 353 if (IS_ERR(rtc->rtt))
354 return PTR_ERR(rtc->rtt);
355
356 if (!pdev->dev.of_node) {
357 /*
358 * TODO: Remove this code chunk when removing non DT board
359 * support. Remember to remove the gpbr_regmap_config
360 * variable too.
361 */
362 void __iomem *gpbr;
363
364 r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
365 gpbr = devm_ioremap_resource(&pdev->dev, r);
366 if (IS_ERR(gpbr))
367 return PTR_ERR(gpbr);
368
369 rtc->gpbr = regmap_init_mmio(NULL, gpbr,
370 &gpbr_regmap_config);
371 } else {
372 struct of_phandle_args args;
373
374 ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
375 "atmel,rtt-rtc-time-reg", 1, 0,
376 &args);
377 if (ret)
378 return ret;
379
380 rtc->gpbr = syscon_node_to_regmap(args.np);
381 rtc->gpbr_offset = args.args[0];
328 } 382 }
329 383
330 rtc->gpbr = devm_ioremap(&pdev->dev, r_gpbr->start, 384 if (IS_ERR(rtc->gpbr)) {
331 resource_size(r_gpbr)); 385 dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n");
332 if (!rtc->gpbr) {
333 dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n");
334 return -ENOMEM; 386 return -ENOMEM;
335 } 387 }
336 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
337 mr = rtt_readl(rtc, MR); 405 mr = rtt_readl(rtc, MR);
338 406
339 /* unless RTT is counting at 1 Hz, re-initialize it */ 407 /* unless RTT is counting at 1 Hz, re-initialize it */
340 if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) { 408 if ((mr & AT91_RTT_RTPRES) != sclk_rate) {
341 mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES); 409 mr = AT91_RTT_RTTRST | (sclk_rate & AT91_RTT_RTPRES);
342 gpbr_writel(rtc, 0); 410 gpbr_writel(rtc, 0);
343 } 411 }
344 412
@@ -383,6 +451,9 @@ static int at91_rtc_remove(struct platform_device *pdev)
383 /* disable all interrupts */ 451 /* disable all interrupts */
384 rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); 452 rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
385 453
454 if (!IS_ERR(rtc->sclk))
455 clk_disable_unprepare(rtc->sclk);
456
386 return 0; 457 return 0;
387} 458}
388 459
@@ -440,6 +511,14 @@ static int at91_rtc_resume(struct device *dev)
440 511
441static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); 512static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
442 513
514#ifdef CONFIG_OF
515static const struct of_device_id at91_rtc_dt_ids[] = {
516 { .compatible = "atmel,at91sam9260-rtt" },
517 { /* sentinel */ }
518};
519MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
520#endif
521
443static struct platform_driver at91_rtc_driver = { 522static struct platform_driver at91_rtc_driver = {
444 .probe = at91_rtc_probe, 523 .probe = at91_rtc_probe,
445 .remove = at91_rtc_remove, 524 .remove = at91_rtc_remove,
@@ -448,6 +527,7 @@ static struct platform_driver at91_rtc_driver = {
448 .name = "rtc-at91sam9", 527 .name = "rtc-at91sam9",
449 .owner = THIS_MODULE, 528 .owner = THIS_MODULE,
450 .pm = &at91_rtc_pm_ops, 529 .pm = &at91_rtc_pm_ops,
530 .of_match_table = of_match_ptr(at91_rtc_dt_ids),
451 }, 531 },
452}; 532};
453 533