diff options
Diffstat (limited to 'drivers/rtc/rtc-at91sam9.c')
-rw-r--r-- | drivers/rtc/rtc-at91sam9.c | 133 |
1 files changed, 79 insertions, 54 deletions
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 39cfd2ee004..a3ad957507d 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c | |||
@@ -19,8 +19,8 @@ | |||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/ioctl.h> | 20 | #include <linux/ioctl.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/platform_data/atmel.h> | ||
23 | 22 | ||
23 | #include <mach/board.h> | ||
24 | #include <mach/at91_rtt.h> | 24 | #include <mach/at91_rtt.h> |
25 | #include <mach/cpu.h> | 25 | #include <mach/cpu.h> |
26 | 26 | ||
@@ -57,8 +57,6 @@ 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; | ||
61 | int irq; | ||
62 | }; | 60 | }; |
63 | 61 | ||
64 | #define rtt_readl(rtc, field) \ | 62 | #define rtt_readl(rtc, field) \ |
@@ -67,9 +65,9 @@ struct sam9_rtc { | |||
67 | __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field) | 65 | __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field) |
68 | 66 | ||
69 | #define gpbr_readl(rtc) \ | 67 | #define gpbr_readl(rtc) \ |
70 | __raw_readl((rtc)->gpbr) | 68 | at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR) |
71 | #define gpbr_writel(rtc, val) \ | 69 | #define gpbr_writel(rtc, val) \ |
72 | __raw_writel((val), (rtc)->gpbr) | 70 | at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val)) |
73 | 71 | ||
74 | /* | 72 | /* |
75 | * Read current time and date in RTC | 73 | * Read current time and date in RTC |
@@ -289,50 +287,28 @@ static const struct rtc_class_ops at91_rtc_ops = { | |||
289 | /* | 287 | /* |
290 | * Initialize and install RTC driver | 288 | * Initialize and install RTC driver |
291 | */ | 289 | */ |
292 | static int at91_rtc_probe(struct platform_device *pdev) | 290 | static int __init at91_rtc_probe(struct platform_device *pdev) |
293 | { | 291 | { |
294 | struct resource *r, *r_gpbr; | 292 | struct resource *r; |
295 | struct sam9_rtc *rtc; | 293 | struct sam9_rtc *rtc; |
296 | int ret, irq; | 294 | int ret; |
297 | u32 mr; | 295 | u32 mr; |
298 | 296 | ||
299 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 297 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
300 | r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 298 | if (!r) |
301 | if (!r || !r_gpbr) { | ||
302 | dev_err(&pdev->dev, "need 2 ressources\n"); | ||
303 | return -ENODEV; | 299 | return -ENODEV; |
304 | } | ||
305 | |||
306 | irq = platform_get_irq(pdev, 0); | ||
307 | if (irq < 0) { | ||
308 | dev_err(&pdev->dev, "failed to get interrupt resource\n"); | ||
309 | return irq; | ||
310 | } | ||
311 | 300 | ||
312 | rtc = kzalloc(sizeof *rtc, GFP_KERNEL); | 301 | rtc = kzalloc(sizeof *rtc, GFP_KERNEL); |
313 | if (!rtc) | 302 | if (!rtc) |
314 | return -ENOMEM; | 303 | return -ENOMEM; |
315 | 304 | ||
316 | rtc->irq = irq; | ||
317 | |||
318 | /* platform setup code should have handled this; sigh */ | 305 | /* platform setup code should have handled this; sigh */ |
319 | if (!device_can_wakeup(&pdev->dev)) | 306 | if (!device_can_wakeup(&pdev->dev)) |
320 | device_init_wakeup(&pdev->dev, 1); | 307 | device_init_wakeup(&pdev->dev, 1); |
321 | 308 | ||
322 | platform_set_drvdata(pdev, rtc); | 309 | platform_set_drvdata(pdev, rtc); |
323 | rtc->rtt = ioremap(r->start, resource_size(r)); | 310 | rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS); |
324 | if (!rtc->rtt) { | 311 | rtc->rtt += r->start; |
325 | dev_err(&pdev->dev, "failed to map registers, aborting.\n"); | ||
326 | ret = -ENOMEM; | ||
327 | goto fail; | ||
328 | } | ||
329 | |||
330 | rtc->gpbr = ioremap(r_gpbr->start, resource_size(r_gpbr)); | ||
331 | if (!rtc->gpbr) { | ||
332 | dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n"); | ||
333 | ret = -ENOMEM; | ||
334 | goto fail_gpbr; | ||
335 | } | ||
336 | 312 | ||
337 | mr = rtt_readl(rtc, MR); | 313 | mr = rtt_readl(rtc, MR); |
338 | 314 | ||
@@ -350,16 +326,17 @@ static int at91_rtc_probe(struct platform_device *pdev) | |||
350 | &at91_rtc_ops, THIS_MODULE); | 326 | &at91_rtc_ops, THIS_MODULE); |
351 | if (IS_ERR(rtc->rtcdev)) { | 327 | if (IS_ERR(rtc->rtcdev)) { |
352 | ret = PTR_ERR(rtc->rtcdev); | 328 | ret = PTR_ERR(rtc->rtcdev); |
353 | goto fail_register; | 329 | goto fail; |
354 | } | 330 | } |
355 | 331 | ||
356 | /* register irq handler after we know what name we'll use */ | 332 | /* register irq handler after we know what name we'll use */ |
357 | ret = request_irq(rtc->irq, at91_rtc_interrupt, IRQF_SHARED, | 333 | ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, |
334 | IRQF_DISABLED | IRQF_SHARED, | ||
358 | dev_name(&rtc->rtcdev->dev), rtc); | 335 | dev_name(&rtc->rtcdev->dev), rtc); |
359 | if (ret) { | 336 | if (ret) { |
360 | dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq); | 337 | dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS); |
361 | rtc_device_unregister(rtc->rtcdev); | 338 | rtc_device_unregister(rtc->rtcdev); |
362 | goto fail_register; | 339 | goto fail; |
363 | } | 340 | } |
364 | 341 | ||
365 | /* NOTE: sam9260 rev A silicon has a ROM bug which resets the | 342 | /* NOTE: sam9260 rev A silicon has a ROM bug which resets the |
@@ -374,10 +351,6 @@ static int at91_rtc_probe(struct platform_device *pdev) | |||
374 | 351 | ||
375 | return 0; | 352 | return 0; |
376 | 353 | ||
377 | fail_register: | ||
378 | iounmap(rtc->gpbr); | ||
379 | fail_gpbr: | ||
380 | iounmap(rtc->rtt); | ||
381 | fail: | 354 | fail: |
382 | platform_set_drvdata(pdev, NULL); | 355 | platform_set_drvdata(pdev, NULL); |
383 | kfree(rtc); | 356 | kfree(rtc); |
@@ -387,19 +360,17 @@ fail: | |||
387 | /* | 360 | /* |
388 | * Disable and remove the RTC driver | 361 | * Disable and remove the RTC driver |
389 | */ | 362 | */ |
390 | static int at91_rtc_remove(struct platform_device *pdev) | 363 | static int __exit at91_rtc_remove(struct platform_device *pdev) |
391 | { | 364 | { |
392 | struct sam9_rtc *rtc = platform_get_drvdata(pdev); | 365 | struct sam9_rtc *rtc = platform_get_drvdata(pdev); |
393 | u32 mr = rtt_readl(rtc, MR); | 366 | u32 mr = rtt_readl(rtc, MR); |
394 | 367 | ||
395 | /* disable all interrupts */ | 368 | /* disable all interrupts */ |
396 | rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); | 369 | rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); |
397 | free_irq(rtc->irq, rtc); | 370 | free_irq(AT91_ID_SYS, rtc); |
398 | 371 | ||
399 | rtc_device_unregister(rtc->rtcdev); | 372 | rtc_device_unregister(rtc->rtcdev); |
400 | 373 | ||
401 | iounmap(rtc->gpbr); | ||
402 | iounmap(rtc->rtt); | ||
403 | platform_set_drvdata(pdev, NULL); | 374 | platform_set_drvdata(pdev, NULL); |
404 | kfree(rtc); | 375 | kfree(rtc); |
405 | return 0; | 376 | return 0; |
@@ -431,7 +402,7 @@ static int at91_rtc_suspend(struct platform_device *pdev, | |||
431 | rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); | 402 | rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); |
432 | if (rtc->imr) { | 403 | if (rtc->imr) { |
433 | if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) { | 404 | if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) { |
434 | enable_irq_wake(rtc->irq); | 405 | enable_irq_wake(AT91_ID_SYS); |
435 | /* don't let RTTINC cause wakeups */ | 406 | /* don't let RTTINC cause wakeups */ |
436 | if (mr & AT91_RTT_RTTINCIEN) | 407 | if (mr & AT91_RTT_RTTINCIEN) |
437 | rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); | 408 | rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); |
@@ -449,7 +420,7 @@ static int at91_rtc_resume(struct platform_device *pdev) | |||
449 | 420 | ||
450 | if (rtc->imr) { | 421 | if (rtc->imr) { |
451 | if (device_may_wakeup(&pdev->dev)) | 422 | if (device_may_wakeup(&pdev->dev)) |
452 | disable_irq_wake(rtc->irq); | 423 | disable_irq_wake(AT91_ID_SYS); |
453 | mr = rtt_readl(rtc, MR); | 424 | mr = rtt_readl(rtc, MR); |
454 | rtt_writel(rtc, MR, mr | rtc->imr); | 425 | rtt_writel(rtc, MR, mr | rtc->imr); |
455 | } | 426 | } |
@@ -462,18 +433,72 @@ static int at91_rtc_resume(struct platform_device *pdev) | |||
462 | #endif | 433 | #endif |
463 | 434 | ||
464 | static struct platform_driver at91_rtc_driver = { | 435 | static struct platform_driver at91_rtc_driver = { |
465 | .probe = at91_rtc_probe, | 436 | .driver.name = "rtc-at91sam9", |
466 | .remove = at91_rtc_remove, | 437 | .driver.owner = THIS_MODULE, |
438 | .remove = __exit_p(at91_rtc_remove), | ||
467 | .shutdown = at91_rtc_shutdown, | 439 | .shutdown = at91_rtc_shutdown, |
468 | .suspend = at91_rtc_suspend, | 440 | .suspend = at91_rtc_suspend, |
469 | .resume = at91_rtc_resume, | 441 | .resume = at91_rtc_resume, |
470 | .driver = { | ||
471 | .name = "rtc-at91sam9", | ||
472 | .owner = THIS_MODULE, | ||
473 | }, | ||
474 | }; | 442 | }; |
475 | 443 | ||
476 | module_platform_driver(at91_rtc_driver); | 444 | /* Chips can have more than one RTT module, and they can be used for more |
445 | * than just RTCs. So we can't just register as "the" RTT driver. | ||
446 | * | ||
447 | * A normal approach in such cases is to create a library to allocate and | ||
448 | * free the modules. Here we just use bus_find_device() as like such a | ||
449 | * library, binding directly ... no runtime "library" footprint is needed. | ||
450 | */ | ||
451 | static int __init at91_rtc_match(struct device *dev, void *v) | ||
452 | { | ||
453 | struct platform_device *pdev = to_platform_device(dev); | ||
454 | int ret; | ||
455 | |||
456 | /* continue searching if this isn't the RTT we need */ | ||
457 | if (strcmp("at91_rtt", pdev->name) != 0 | ||
458 | || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT) | ||
459 | goto fail; | ||
460 | |||
461 | /* else we found it ... but fail unless we can bind to the RTC driver */ | ||
462 | if (dev->driver) { | ||
463 | dev_dbg(dev, "busy, can't use as RTC!\n"); | ||
464 | goto fail; | ||
465 | } | ||
466 | dev->driver = &at91_rtc_driver.driver; | ||
467 | if (device_attach(dev) == 0) { | ||
468 | dev_dbg(dev, "can't attach RTC!\n"); | ||
469 | goto fail; | ||
470 | } | ||
471 | ret = at91_rtc_probe(pdev); | ||
472 | if (ret == 0) | ||
473 | return true; | ||
474 | |||
475 | dev_dbg(dev, "RTC probe err %d!\n", ret); | ||
476 | fail: | ||
477 | return false; | ||
478 | } | ||
479 | |||
480 | static int __init at91_rtc_init(void) | ||
481 | { | ||
482 | int status; | ||
483 | struct device *rtc; | ||
484 | |||
485 | status = platform_driver_register(&at91_rtc_driver); | ||
486 | if (status) | ||
487 | return status; | ||
488 | rtc = bus_find_device(&platform_bus_type, NULL, | ||
489 | NULL, at91_rtc_match); | ||
490 | if (!rtc) | ||
491 | platform_driver_unregister(&at91_rtc_driver); | ||
492 | return rtc ? 0 : -ENODEV; | ||
493 | } | ||
494 | module_init(at91_rtc_init); | ||
495 | |||
496 | static void __exit at91_rtc_exit(void) | ||
497 | { | ||
498 | platform_driver_unregister(&at91_rtc_driver); | ||
499 | } | ||
500 | module_exit(at91_rtc_exit); | ||
501 | |||
477 | 502 | ||
478 | MODULE_AUTHOR("Michel Benoit"); | 503 | MODULE_AUTHOR("Michel Benoit"); |
479 | MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x"); | 504 | MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x"); |