diff options
Diffstat (limited to 'drivers/rtc/rtc-omap.c')
-rw-r--r-- | drivers/rtc/rtc-omap.c | 80 |
1 files changed, 77 insertions, 3 deletions
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 0b614e32653d..600971407aac 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
@@ -20,6 +20,9 @@ | |||
20 | #include <linux/rtc.h> | 20 | #include <linux/rtc.h> |
21 | #include <linux/bcd.h> | 21 | #include <linux/bcd.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/of.h> | ||
24 | #include <linux/of_device.h> | ||
25 | #include <linux/pm_runtime.h> | ||
23 | 26 | ||
24 | #include <asm/io.h> | 27 | #include <asm/io.h> |
25 | 28 | ||
@@ -38,6 +41,8 @@ | |||
38 | * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment. | 41 | * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment. |
39 | */ | 42 | */ |
40 | 43 | ||
44 | #define DRIVER_NAME "omap_rtc" | ||
45 | |||
41 | #define OMAP_RTC_BASE 0xfffb4800 | 46 | #define OMAP_RTC_BASE 0xfffb4800 |
42 | 47 | ||
43 | /* RTC registers */ | 48 | /* RTC registers */ |
@@ -64,6 +69,9 @@ | |||
64 | #define OMAP_RTC_COMP_MSB_REG 0x50 | 69 | #define OMAP_RTC_COMP_MSB_REG 0x50 |
65 | #define OMAP_RTC_OSC_REG 0x54 | 70 | #define OMAP_RTC_OSC_REG 0x54 |
66 | 71 | ||
72 | #define OMAP_RTC_KICK0_REG 0x6c | ||
73 | #define OMAP_RTC_KICK1_REG 0x70 | ||
74 | |||
67 | /* OMAP_RTC_CTRL_REG bit fields: */ | 75 | /* OMAP_RTC_CTRL_REG bit fields: */ |
68 | #define OMAP_RTC_CTRL_SPLIT (1<<7) | 76 | #define OMAP_RTC_CTRL_SPLIT (1<<7) |
69 | #define OMAP_RTC_CTRL_DISABLE (1<<6) | 77 | #define OMAP_RTC_CTRL_DISABLE (1<<6) |
@@ -88,10 +96,18 @@ | |||
88 | #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) | 96 | #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) |
89 | #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) | 97 | #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) |
90 | 98 | ||
99 | /* OMAP_RTC_KICKER values */ | ||
100 | #define KICK0_VALUE 0x83e70b13 | ||
101 | #define KICK1_VALUE 0x95a4f1e0 | ||
102 | |||
103 | #define OMAP_RTC_HAS_KICKER 0x1 | ||
104 | |||
91 | static void __iomem *rtc_base; | 105 | static void __iomem *rtc_base; |
92 | 106 | ||
93 | #define rtc_read(addr) __raw_readb(rtc_base + (addr)) | 107 | #define rtc_read(addr) readb(rtc_base + (addr)) |
94 | #define rtc_write(val, addr) __raw_writeb(val, rtc_base + (addr)) | 108 | #define rtc_write(val, addr) writeb(val, rtc_base + (addr)) |
109 | |||
110 | #define rtc_writel(val, addr) writel(val, rtc_base + (addr)) | ||
95 | 111 | ||
96 | 112 | ||
97 | /* we rely on the rtc framework to handle locking (rtc->ops_lock), | 113 | /* we rely on the rtc framework to handle locking (rtc->ops_lock), |
@@ -285,11 +301,38 @@ static struct rtc_class_ops omap_rtc_ops = { | |||
285 | static int omap_rtc_alarm; | 301 | static int omap_rtc_alarm; |
286 | static int omap_rtc_timer; | 302 | static int omap_rtc_timer; |
287 | 303 | ||
304 | #define OMAP_RTC_DATA_DA830_IDX 1 | ||
305 | |||
306 | static struct platform_device_id omap_rtc_devtype[] = { | ||
307 | { | ||
308 | .name = DRIVER_NAME, | ||
309 | }, { | ||
310 | .name = "da830-rtc", | ||
311 | .driver_data = OMAP_RTC_HAS_KICKER, | ||
312 | }, | ||
313 | {}, | ||
314 | }; | ||
315 | MODULE_DEVICE_TABLE(platform, omap_rtc_devtype); | ||
316 | |||
317 | static const struct of_device_id omap_rtc_of_match[] = { | ||
318 | { .compatible = "ti,da830-rtc", | ||
319 | .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], | ||
320 | }, | ||
321 | {}, | ||
322 | }; | ||
323 | MODULE_DEVICE_TABLE(of, omap_rtc_of_match); | ||
324 | |||
288 | static int __init omap_rtc_probe(struct platform_device *pdev) | 325 | static int __init omap_rtc_probe(struct platform_device *pdev) |
289 | { | 326 | { |
290 | struct resource *res, *mem; | 327 | struct resource *res, *mem; |
291 | struct rtc_device *rtc; | 328 | struct rtc_device *rtc; |
292 | u8 reg, new_ctrl; | 329 | u8 reg, new_ctrl; |
330 | const struct platform_device_id *id_entry; | ||
331 | const struct of_device_id *of_id; | ||
332 | |||
333 | of_id = of_match_device(omap_rtc_of_match, &pdev->dev); | ||
334 | if (of_id) | ||
335 | pdev->id_entry = of_id->data; | ||
293 | 336 | ||
294 | omap_rtc_timer = platform_get_irq(pdev, 0); | 337 | omap_rtc_timer = platform_get_irq(pdev, 0); |
295 | if (omap_rtc_timer <= 0) { | 338 | if (omap_rtc_timer <= 0) { |
@@ -322,6 +365,16 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
322 | goto fail; | 365 | goto fail; |
323 | } | 366 | } |
324 | 367 | ||
368 | /* Enable the clock/module so that we can access the registers */ | ||
369 | pm_runtime_enable(&pdev->dev); | ||
370 | pm_runtime_get_sync(&pdev->dev); | ||
371 | |||
372 | id_entry = platform_get_device_id(pdev); | ||
373 | if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) { | ||
374 | rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG); | ||
375 | rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG); | ||
376 | } | ||
377 | |||
325 | rtc = rtc_device_register(pdev->name, &pdev->dev, | 378 | rtc = rtc_device_register(pdev->name, &pdev->dev, |
326 | &omap_rtc_ops, THIS_MODULE); | 379 | &omap_rtc_ops, THIS_MODULE); |
327 | if (IS_ERR(rtc)) { | 380 | if (IS_ERR(rtc)) { |
@@ -398,6 +451,10 @@ fail2: | |||
398 | fail1: | 451 | fail1: |
399 | rtc_device_unregister(rtc); | 452 | rtc_device_unregister(rtc); |
400 | fail0: | 453 | fail0: |
454 | if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) | ||
455 | rtc_writel(0, OMAP_RTC_KICK0_REG); | ||
456 | pm_runtime_put_sync(&pdev->dev); | ||
457 | pm_runtime_disable(&pdev->dev); | ||
401 | iounmap(rtc_base); | 458 | iounmap(rtc_base); |
402 | fail: | 459 | fail: |
403 | release_mem_region(mem->start, resource_size(mem)); | 460 | release_mem_region(mem->start, resource_size(mem)); |
@@ -408,6 +465,8 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) | |||
408 | { | 465 | { |
409 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 466 | struct rtc_device *rtc = platform_get_drvdata(pdev); |
410 | struct resource *mem = dev_get_drvdata(&rtc->dev); | 467 | struct resource *mem = dev_get_drvdata(&rtc->dev); |
468 | const struct platform_device_id *id_entry = | ||
469 | platform_get_device_id(pdev); | ||
411 | 470 | ||
412 | device_init_wakeup(&pdev->dev, 0); | 471 | device_init_wakeup(&pdev->dev, 0); |
413 | 472 | ||
@@ -420,6 +479,13 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) | |||
420 | free_irq(omap_rtc_alarm, rtc); | 479 | free_irq(omap_rtc_alarm, rtc); |
421 | 480 | ||
422 | rtc_device_unregister(rtc); | 481 | rtc_device_unregister(rtc); |
482 | if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) | ||
483 | rtc_writel(0, OMAP_RTC_KICK0_REG); | ||
484 | |||
485 | /* Disable the clock/module */ | ||
486 | pm_runtime_put_sync(&pdev->dev); | ||
487 | pm_runtime_disable(&pdev->dev); | ||
488 | |||
423 | iounmap(rtc_base); | 489 | iounmap(rtc_base); |
424 | release_mem_region(mem->start, resource_size(mem)); | 490 | release_mem_region(mem->start, resource_size(mem)); |
425 | return 0; | 491 | return 0; |
@@ -442,11 +508,17 @@ static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state) | |||
442 | else | 508 | else |
443 | rtc_write(0, OMAP_RTC_INTERRUPTS_REG); | 509 | rtc_write(0, OMAP_RTC_INTERRUPTS_REG); |
444 | 510 | ||
511 | /* Disable the clock/module */ | ||
512 | pm_runtime_put_sync(&pdev->dev); | ||
513 | |||
445 | return 0; | 514 | return 0; |
446 | } | 515 | } |
447 | 516 | ||
448 | static int omap_rtc_resume(struct platform_device *pdev) | 517 | static int omap_rtc_resume(struct platform_device *pdev) |
449 | { | 518 | { |
519 | /* Enable the clock/module so that we can access the registers */ | ||
520 | pm_runtime_get_sync(&pdev->dev); | ||
521 | |||
450 | if (device_may_wakeup(&pdev->dev)) | 522 | if (device_may_wakeup(&pdev->dev)) |
451 | disable_irq_wake(omap_rtc_alarm); | 523 | disable_irq_wake(omap_rtc_alarm); |
452 | else | 524 | else |
@@ -471,9 +543,11 @@ static struct platform_driver omap_rtc_driver = { | |||
471 | .resume = omap_rtc_resume, | 543 | .resume = omap_rtc_resume, |
472 | .shutdown = omap_rtc_shutdown, | 544 | .shutdown = omap_rtc_shutdown, |
473 | .driver = { | 545 | .driver = { |
474 | .name = "omap_rtc", | 546 | .name = DRIVER_NAME, |
475 | .owner = THIS_MODULE, | 547 | .owner = THIS_MODULE, |
548 | .of_match_table = of_match_ptr(omap_rtc_of_match), | ||
476 | }, | 549 | }, |
550 | .id_table = omap_rtc_devtype, | ||
477 | }; | 551 | }; |
478 | 552 | ||
479 | static int __init rtc_init(void) | 553 | static int __init rtc_init(void) |