diff options
Diffstat (limited to 'drivers/rtc/rtc-at91sam9.c')
-rw-r--r-- | drivers/rtc/rtc-at91sam9.c | 85 |
1 files changed, 28 insertions, 57 deletions
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 274a0aafe42b..831868904e02 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c | |||
@@ -57,6 +57,7 @@ struct sam9_rtc { | |||
57 | void __iomem *rtt; | 57 | void __iomem *rtt; |
58 | struct rtc_device *rtcdev; | 58 | struct rtc_device *rtcdev; |
59 | u32 imr; | 59 | u32 imr; |
60 | void __iomem *gpbr; | ||
60 | }; | 61 | }; |
61 | 62 | ||
62 | #define rtt_readl(rtc, field) \ | 63 | #define rtt_readl(rtc, field) \ |
@@ -65,9 +66,9 @@ struct sam9_rtc { | |||
65 | __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field) | 66 | __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field) |
66 | 67 | ||
67 | #define gpbr_readl(rtc) \ | 68 | #define gpbr_readl(rtc) \ |
68 | at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR) | 69 | __raw_readl((rtc)->gpbr) |
69 | #define gpbr_writel(rtc, val) \ | 70 | #define gpbr_writel(rtc, val) \ |
70 | at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val)) | 71 | __raw_writel((val), (rtc)->gpbr) |
71 | 72 | ||
72 | /* | 73 | /* |
73 | * Read current time and date in RTC | 74 | * Read current time and date in RTC |
@@ -287,16 +288,19 @@ static const struct rtc_class_ops at91_rtc_ops = { | |||
287 | /* | 288 | /* |
288 | * Initialize and install RTC driver | 289 | * Initialize and install RTC driver |
289 | */ | 290 | */ |
290 | static int __init at91_rtc_probe(struct platform_device *pdev) | 291 | static int __devinit at91_rtc_probe(struct platform_device *pdev) |
291 | { | 292 | { |
292 | struct resource *r; | 293 | struct resource *r, *r_gpbr; |
293 | struct sam9_rtc *rtc; | 294 | struct sam9_rtc *rtc; |
294 | int ret; | 295 | int ret; |
295 | u32 mr; | 296 | u32 mr; |
296 | 297 | ||
297 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 298 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
298 | if (!r) | 299 | r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
300 | if (!r || !r_gpbr) { | ||
301 | dev_err(&pdev->dev, "need 2 ressources\n"); | ||
299 | return -ENODEV; | 302 | return -ENODEV; |
303 | } | ||
300 | 304 | ||
301 | rtc = kzalloc(sizeof *rtc, GFP_KERNEL); | 305 | rtc = kzalloc(sizeof *rtc, GFP_KERNEL); |
302 | if (!rtc) | 306 | if (!rtc) |
@@ -314,6 +318,13 @@ static int __init at91_rtc_probe(struct platform_device *pdev) | |||
314 | goto fail; | 318 | goto fail; |
315 | } | 319 | } |
316 | 320 | ||
321 | rtc->gpbr = ioremap(r_gpbr->start, resource_size(r_gpbr)); | ||
322 | if (!rtc->gpbr) { | ||
323 | dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n"); | ||
324 | ret = -ENOMEM; | ||
325 | goto fail_gpbr; | ||
326 | } | ||
327 | |||
317 | mr = rtt_readl(rtc, MR); | 328 | mr = rtt_readl(rtc, MR); |
318 | 329 | ||
319 | /* unless RTT is counting at 1 Hz, re-initialize it */ | 330 | /* unless RTT is counting at 1 Hz, re-initialize it */ |
@@ -340,7 +351,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) | |||
340 | if (ret) { | 351 | if (ret) { |
341 | dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS); | 352 | dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS); |
342 | rtc_device_unregister(rtc->rtcdev); | 353 | rtc_device_unregister(rtc->rtcdev); |
343 | goto fail; | 354 | goto fail_register; |
344 | } | 355 | } |
345 | 356 | ||
346 | /* NOTE: sam9260 rev A silicon has a ROM bug which resets the | 357 | /* NOTE: sam9260 rev A silicon has a ROM bug which resets the |
@@ -356,6 +367,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev) | |||
356 | return 0; | 367 | return 0; |
357 | 368 | ||
358 | fail_register: | 369 | fail_register: |
370 | iounmap(rtc->gpbr); | ||
371 | fail_gpbr: | ||
359 | iounmap(rtc->rtt); | 372 | iounmap(rtc->rtt); |
360 | fail: | 373 | fail: |
361 | platform_set_drvdata(pdev, NULL); | 374 | platform_set_drvdata(pdev, NULL); |
@@ -366,7 +379,7 @@ fail: | |||
366 | /* | 379 | /* |
367 | * Disable and remove the RTC driver | 380 | * Disable and remove the RTC driver |
368 | */ | 381 | */ |
369 | static int __exit at91_rtc_remove(struct platform_device *pdev) | 382 | static int __devexit at91_rtc_remove(struct platform_device *pdev) |
370 | { | 383 | { |
371 | struct sam9_rtc *rtc = platform_get_drvdata(pdev); | 384 | struct sam9_rtc *rtc = platform_get_drvdata(pdev); |
372 | u32 mr = rtt_readl(rtc, MR); | 385 | u32 mr = rtt_readl(rtc, MR); |
@@ -377,6 +390,7 @@ static int __exit at91_rtc_remove(struct platform_device *pdev) | |||
377 | 390 | ||
378 | rtc_device_unregister(rtc->rtcdev); | 391 | rtc_device_unregister(rtc->rtcdev); |
379 | 392 | ||
393 | iounmap(rtc->gpbr); | ||
380 | iounmap(rtc->rtt); | 394 | iounmap(rtc->rtt); |
381 | platform_set_drvdata(pdev, NULL); | 395 | platform_set_drvdata(pdev, NULL); |
382 | kfree(rtc); | 396 | kfree(rtc); |
@@ -440,63 +454,20 @@ static int at91_rtc_resume(struct platform_device *pdev) | |||
440 | #endif | 454 | #endif |
441 | 455 | ||
442 | static struct platform_driver at91_rtc_driver = { | 456 | static struct platform_driver at91_rtc_driver = { |
443 | .driver.name = "rtc-at91sam9", | 457 | .probe = at91_rtc_probe, |
444 | .driver.owner = THIS_MODULE, | 458 | .remove = __devexit_p(at91_rtc_remove), |
445 | .remove = __exit_p(at91_rtc_remove), | ||
446 | .shutdown = at91_rtc_shutdown, | 459 | .shutdown = at91_rtc_shutdown, |
447 | .suspend = at91_rtc_suspend, | 460 | .suspend = at91_rtc_suspend, |
448 | .resume = at91_rtc_resume, | 461 | .resume = at91_rtc_resume, |
462 | .driver = { | ||
463 | .name = "rtc-at91sam9", | ||
464 | .owner = THIS_MODULE, | ||
465 | }, | ||
449 | }; | 466 | }; |
450 | 467 | ||
451 | /* Chips can have more than one RTT module, and they can be used for more | ||
452 | * than just RTCs. So we can't just register as "the" RTT driver. | ||
453 | * | ||
454 | * A normal approach in such cases is to create a library to allocate and | ||
455 | * free the modules. Here we just use bus_find_device() as like such a | ||
456 | * library, binding directly ... no runtime "library" footprint is needed. | ||
457 | */ | ||
458 | static int __init at91_rtc_match(struct device *dev, void *v) | ||
459 | { | ||
460 | struct platform_device *pdev = to_platform_device(dev); | ||
461 | int ret; | ||
462 | |||
463 | /* continue searching if this isn't the RTT we need */ | ||
464 | if (strcmp("at91_rtt", pdev->name) != 0 | ||
465 | || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT) | ||
466 | goto fail; | ||
467 | |||
468 | /* else we found it ... but fail unless we can bind to the RTC driver */ | ||
469 | if (dev->driver) { | ||
470 | dev_dbg(dev, "busy, can't use as RTC!\n"); | ||
471 | goto fail; | ||
472 | } | ||
473 | dev->driver = &at91_rtc_driver.driver; | ||
474 | if (device_attach(dev) == 0) { | ||
475 | dev_dbg(dev, "can't attach RTC!\n"); | ||
476 | goto fail; | ||
477 | } | ||
478 | ret = at91_rtc_probe(pdev); | ||
479 | if (ret == 0) | ||
480 | return true; | ||
481 | |||
482 | dev_dbg(dev, "RTC probe err %d!\n", ret); | ||
483 | fail: | ||
484 | return false; | ||
485 | } | ||
486 | |||
487 | static int __init at91_rtc_init(void) | 468 | static int __init at91_rtc_init(void) |
488 | { | 469 | { |
489 | int status; | 470 | return platform_driver_register(&at91_rtc_driver); |
490 | struct device *rtc; | ||
491 | |||
492 | status = platform_driver_register(&at91_rtc_driver); | ||
493 | if (status) | ||
494 | return status; | ||
495 | rtc = bus_find_device(&platform_bus_type, NULL, | ||
496 | NULL, at91_rtc_match); | ||
497 | if (!rtc) | ||
498 | platform_driver_unregister(&at91_rtc_driver); | ||
499 | return rtc ? 0 : -ENODEV; | ||
500 | } | 471 | } |
501 | module_init(at91_rtc_init); | 472 | module_init(at91_rtc_init); |
502 | 473 | ||