diff options
Diffstat (limited to 'drivers/rtc/rtc-omap.c')
| -rw-r--r-- | drivers/rtc/rtc-omap.c | 68 |
1 files changed, 55 insertions, 13 deletions
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 8e5851aa4369..8b6355ffaff9 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
| @@ -118,12 +118,15 @@ | |||
| 118 | #define KICK0_VALUE 0x83e70b13 | 118 | #define KICK0_VALUE 0x83e70b13 |
| 119 | #define KICK1_VALUE 0x95a4f1e0 | 119 | #define KICK1_VALUE 0x95a4f1e0 |
| 120 | 120 | ||
| 121 | struct omap_rtc; | ||
| 122 | |||
| 121 | struct omap_rtc_device_type { | 123 | struct omap_rtc_device_type { |
| 122 | bool has_32kclk_en; | 124 | bool has_32kclk_en; |
| 123 | bool has_kicker; | ||
| 124 | bool has_irqwakeen; | 125 | bool has_irqwakeen; |
| 125 | bool has_pmic_mode; | 126 | bool has_pmic_mode; |
| 126 | bool has_power_up_reset; | 127 | bool has_power_up_reset; |
| 128 | void (*lock)(struct omap_rtc *rtc); | ||
| 129 | void (*unlock)(struct omap_rtc *rtc); | ||
| 127 | }; | 130 | }; |
| 128 | 131 | ||
| 129 | struct omap_rtc { | 132 | struct omap_rtc { |
| @@ -156,6 +159,26 @@ static inline void rtc_writel(struct omap_rtc *rtc, unsigned int reg, u32 val) | |||
| 156 | writel(val, rtc->base + reg); | 159 | writel(val, rtc->base + reg); |
| 157 | } | 160 | } |
| 158 | 161 | ||
| 162 | static void am3352_rtc_unlock(struct omap_rtc *rtc) | ||
| 163 | { | ||
| 164 | rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE); | ||
| 165 | rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE); | ||
| 166 | } | ||
| 167 | |||
| 168 | static void am3352_rtc_lock(struct omap_rtc *rtc) | ||
| 169 | { | ||
| 170 | rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0); | ||
| 171 | rtc_writel(rtc, OMAP_RTC_KICK1_REG, 0); | ||
| 172 | } | ||
| 173 | |||
| 174 | static void default_rtc_unlock(struct omap_rtc *rtc) | ||
| 175 | { | ||
| 176 | } | ||
| 177 | |||
| 178 | static void default_rtc_lock(struct omap_rtc *rtc) | ||
| 179 | { | ||
| 180 | } | ||
| 181 | |||
| 159 | /* | 182 | /* |
| 160 | * We rely on the rtc framework to handle locking (rtc->ops_lock), | 183 | * We rely on the rtc framework to handle locking (rtc->ops_lock), |
| 161 | * so the only other requirement is that register accesses which | 184 | * so the only other requirement is that register accesses which |
| @@ -186,7 +209,9 @@ static irqreturn_t rtc_irq(int irq, void *dev_id) | |||
| 186 | 209 | ||
| 187 | /* alarm irq? */ | 210 | /* alarm irq? */ |
| 188 | if (irq_data & OMAP_RTC_STATUS_ALARM) { | 211 | if (irq_data & OMAP_RTC_STATUS_ALARM) { |
| 212 | rtc->type->unlock(rtc); | ||
| 189 | rtc_write(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM); | 213 | rtc_write(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM); |
| 214 | rtc->type->lock(rtc); | ||
| 190 | events |= RTC_IRQF | RTC_AF; | 215 | events |= RTC_IRQF | RTC_AF; |
| 191 | } | 216 | } |
| 192 | 217 | ||
| @@ -218,9 +243,11 @@ static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | |||
| 218 | irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; | 243 | irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; |
| 219 | } | 244 | } |
| 220 | rtc_wait_not_busy(rtc); | 245 | rtc_wait_not_busy(rtc); |
| 246 | rtc->type->unlock(rtc); | ||
| 221 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg); | 247 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg); |
| 222 | if (rtc->type->has_irqwakeen) | 248 | if (rtc->type->has_irqwakeen) |
| 223 | rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg); | 249 | rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg); |
| 250 | rtc->type->lock(rtc); | ||
| 224 | local_irq_enable(); | 251 | local_irq_enable(); |
| 225 | 252 | ||
| 226 | return 0; | 253 | return 0; |
| @@ -293,12 +320,14 @@ static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
| 293 | local_irq_disable(); | 320 | local_irq_disable(); |
| 294 | rtc_wait_not_busy(rtc); | 321 | rtc_wait_not_busy(rtc); |
| 295 | 322 | ||
| 323 | rtc->type->unlock(rtc); | ||
| 296 | rtc_write(rtc, OMAP_RTC_YEARS_REG, tm->tm_year); | 324 | rtc_write(rtc, OMAP_RTC_YEARS_REG, tm->tm_year); |
| 297 | rtc_write(rtc, OMAP_RTC_MONTHS_REG, tm->tm_mon); | 325 | rtc_write(rtc, OMAP_RTC_MONTHS_REG, tm->tm_mon); |
| 298 | rtc_write(rtc, OMAP_RTC_DAYS_REG, tm->tm_mday); | 326 | rtc_write(rtc, OMAP_RTC_DAYS_REG, tm->tm_mday); |
| 299 | rtc_write(rtc, OMAP_RTC_HOURS_REG, tm->tm_hour); | 327 | rtc_write(rtc, OMAP_RTC_HOURS_REG, tm->tm_hour); |
| 300 | rtc_write(rtc, OMAP_RTC_MINUTES_REG, tm->tm_min); | 328 | rtc_write(rtc, OMAP_RTC_MINUTES_REG, tm->tm_min); |
| 301 | rtc_write(rtc, OMAP_RTC_SECONDS_REG, tm->tm_sec); | 329 | rtc_write(rtc, OMAP_RTC_SECONDS_REG, tm->tm_sec); |
| 330 | rtc->type->lock(rtc); | ||
| 302 | 331 | ||
| 303 | local_irq_enable(); | 332 | local_irq_enable(); |
| 304 | 333 | ||
| @@ -341,6 +370,7 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
| 341 | local_irq_disable(); | 370 | local_irq_disable(); |
| 342 | rtc_wait_not_busy(rtc); | 371 | rtc_wait_not_busy(rtc); |
| 343 | 372 | ||
| 373 | rtc->type->unlock(rtc); | ||
| 344 | rtc_write(rtc, OMAP_RTC_ALARM_YEARS_REG, alm->time.tm_year); | 374 | rtc_write(rtc, OMAP_RTC_ALARM_YEARS_REG, alm->time.tm_year); |
| 345 | rtc_write(rtc, OMAP_RTC_ALARM_MONTHS_REG, alm->time.tm_mon); | 375 | rtc_write(rtc, OMAP_RTC_ALARM_MONTHS_REG, alm->time.tm_mon); |
| 346 | rtc_write(rtc, OMAP_RTC_ALARM_DAYS_REG, alm->time.tm_mday); | 376 | rtc_write(rtc, OMAP_RTC_ALARM_DAYS_REG, alm->time.tm_mday); |
| @@ -362,6 +392,7 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
| 362 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg); | 392 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg); |
| 363 | if (rtc->type->has_irqwakeen) | 393 | if (rtc->type->has_irqwakeen) |
| 364 | rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg); | 394 | rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg); |
| 395 | rtc->type->lock(rtc); | ||
| 365 | 396 | ||
| 366 | local_irq_enable(); | 397 | local_irq_enable(); |
| 367 | 398 | ||
| @@ -391,6 +422,7 @@ static void omap_rtc_power_off(void) | |||
| 391 | unsigned long now; | 422 | unsigned long now; |
| 392 | u32 val; | 423 | u32 val; |
| 393 | 424 | ||
| 425 | rtc->type->unlock(rtc); | ||
| 394 | /* enable pmic_power_en control */ | 426 | /* enable pmic_power_en control */ |
| 395 | val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); | 427 | val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); |
| 396 | rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); | 428 | rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); |
| @@ -423,6 +455,7 @@ static void omap_rtc_power_off(void) | |||
| 423 | val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); | 455 | val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); |
| 424 | rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, | 456 | rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, |
| 425 | val | OMAP_RTC_INTERRUPTS_IT_ALARM2); | 457 | val | OMAP_RTC_INTERRUPTS_IT_ALARM2); |
| 458 | rtc->type->lock(rtc); | ||
| 426 | 459 | ||
| 427 | /* | 460 | /* |
| 428 | * Wait for alarm to trigger (within two seconds) and external PMIC to | 461 | * Wait for alarm to trigger (within two seconds) and external PMIC to |
| @@ -442,17 +475,21 @@ static struct rtc_class_ops omap_rtc_ops = { | |||
| 442 | 475 | ||
| 443 | static const struct omap_rtc_device_type omap_rtc_default_type = { | 476 | static const struct omap_rtc_device_type omap_rtc_default_type = { |
| 444 | .has_power_up_reset = true, | 477 | .has_power_up_reset = true, |
| 478 | .lock = default_rtc_lock, | ||
| 479 | .unlock = default_rtc_unlock, | ||
| 445 | }; | 480 | }; |
| 446 | 481 | ||
| 447 | static const struct omap_rtc_device_type omap_rtc_am3352_type = { | 482 | static const struct omap_rtc_device_type omap_rtc_am3352_type = { |
| 448 | .has_32kclk_en = true, | 483 | .has_32kclk_en = true, |
| 449 | .has_kicker = true, | ||
| 450 | .has_irqwakeen = true, | 484 | .has_irqwakeen = true, |
| 451 | .has_pmic_mode = true, | 485 | .has_pmic_mode = true, |
| 486 | .lock = am3352_rtc_lock, | ||
| 487 | .unlock = am3352_rtc_unlock, | ||
| 452 | }; | 488 | }; |
| 453 | 489 | ||
| 454 | static const struct omap_rtc_device_type omap_rtc_da830_type = { | 490 | static const struct omap_rtc_device_type omap_rtc_da830_type = { |
| 455 | .has_kicker = true, | 491 | .lock = am3352_rtc_lock, |
| 492 | .unlock = am3352_rtc_unlock, | ||
| 456 | }; | 493 | }; |
| 457 | 494 | ||
| 458 | static const struct platform_device_id omap_rtc_id_table[] = { | 495 | static const struct platform_device_id omap_rtc_id_table[] = { |
| @@ -484,7 +521,7 @@ static const struct of_device_id omap_rtc_of_match[] = { | |||
| 484 | }; | 521 | }; |
| 485 | MODULE_DEVICE_TABLE(of, omap_rtc_of_match); | 522 | MODULE_DEVICE_TABLE(of, omap_rtc_of_match); |
| 486 | 523 | ||
| 487 | static int __init omap_rtc_probe(struct platform_device *pdev) | 524 | static int omap_rtc_probe(struct platform_device *pdev) |
| 488 | { | 525 | { |
| 489 | struct omap_rtc *rtc; | 526 | struct omap_rtc *rtc; |
| 490 | struct resource *res; | 527 | struct resource *res; |
| @@ -527,10 +564,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
| 527 | pm_runtime_enable(&pdev->dev); | 564 | pm_runtime_enable(&pdev->dev); |
| 528 | pm_runtime_get_sync(&pdev->dev); | 565 | pm_runtime_get_sync(&pdev->dev); |
| 529 | 566 | ||
| 530 | if (rtc->type->has_kicker) { | 567 | rtc->type->unlock(rtc); |
| 531 | rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE); | ||
| 532 | rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE); | ||
| 533 | } | ||
| 534 | 568 | ||
| 535 | /* | 569 | /* |
| 536 | * disable interrupts | 570 | * disable interrupts |
| @@ -593,6 +627,8 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
| 593 | if (reg != new_ctrl) | 627 | if (reg != new_ctrl) |
| 594 | rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl); | 628 | rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl); |
| 595 | 629 | ||
| 630 | rtc->type->lock(rtc); | ||
| 631 | |||
| 596 | device_init_wakeup(&pdev->dev, true); | 632 | device_init_wakeup(&pdev->dev, true); |
| 597 | 633 | ||
| 598 | rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, | 634 | rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, |
| @@ -626,8 +662,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) | |||
| 626 | 662 | ||
| 627 | err: | 663 | err: |
| 628 | device_init_wakeup(&pdev->dev, false); | 664 | device_init_wakeup(&pdev->dev, false); |
| 629 | if (rtc->type->has_kicker) | 665 | rtc->type->lock(rtc); |
| 630 | rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0); | ||
| 631 | pm_runtime_put_sync(&pdev->dev); | 666 | pm_runtime_put_sync(&pdev->dev); |
| 632 | pm_runtime_disable(&pdev->dev); | 667 | pm_runtime_disable(&pdev->dev); |
| 633 | 668 | ||
| @@ -646,11 +681,11 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) | |||
| 646 | 681 | ||
| 647 | device_init_wakeup(&pdev->dev, 0); | 682 | device_init_wakeup(&pdev->dev, 0); |
| 648 | 683 | ||
| 684 | rtc->type->unlock(rtc); | ||
| 649 | /* leave rtc running, but disable irqs */ | 685 | /* leave rtc running, but disable irqs */ |
| 650 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); | 686 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); |
| 651 | 687 | ||
| 652 | if (rtc->type->has_kicker) | 688 | rtc->type->lock(rtc); |
| 653 | rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0); | ||
| 654 | 689 | ||
| 655 | /* Disable the clock/module */ | 690 | /* Disable the clock/module */ |
| 656 | pm_runtime_put_sync(&pdev->dev); | 691 | pm_runtime_put_sync(&pdev->dev); |
| @@ -666,6 +701,7 @@ static int omap_rtc_suspend(struct device *dev) | |||
| 666 | 701 | ||
| 667 | rtc->interrupts_reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); | 702 | rtc->interrupts_reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); |
| 668 | 703 | ||
| 704 | rtc->type->unlock(rtc); | ||
| 669 | /* | 705 | /* |
| 670 | * FIXME: the RTC alarm is not currently acting as a wakeup event | 706 | * FIXME: the RTC alarm is not currently acting as a wakeup event |
| 671 | * source on some platforms, and in fact this enable() call is just | 707 | * source on some platforms, and in fact this enable() call is just |
| @@ -675,6 +711,7 @@ static int omap_rtc_suspend(struct device *dev) | |||
| 675 | enable_irq_wake(rtc->irq_alarm); | 711 | enable_irq_wake(rtc->irq_alarm); |
| 676 | else | 712 | else |
| 677 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); | 713 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); |
| 714 | rtc->type->lock(rtc); | ||
| 678 | 715 | ||
| 679 | /* Disable the clock/module */ | 716 | /* Disable the clock/module */ |
| 680 | pm_runtime_put_sync(dev); | 717 | pm_runtime_put_sync(dev); |
| @@ -689,10 +726,12 @@ static int omap_rtc_resume(struct device *dev) | |||
| 689 | /* Enable the clock/module so that we can access the registers */ | 726 | /* Enable the clock/module so that we can access the registers */ |
| 690 | pm_runtime_get_sync(dev); | 727 | pm_runtime_get_sync(dev); |
| 691 | 728 | ||
| 729 | rtc->type->unlock(rtc); | ||
| 692 | if (device_may_wakeup(dev)) | 730 | if (device_may_wakeup(dev)) |
| 693 | disable_irq_wake(rtc->irq_alarm); | 731 | disable_irq_wake(rtc->irq_alarm); |
| 694 | else | 732 | else |
| 695 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, rtc->interrupts_reg); | 733 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, rtc->interrupts_reg); |
| 734 | rtc->type->lock(rtc); | ||
| 696 | 735 | ||
| 697 | return 0; | 736 | return 0; |
| 698 | } | 737 | } |
| @@ -709,12 +748,15 @@ static void omap_rtc_shutdown(struct platform_device *pdev) | |||
| 709 | * Keep the ALARM interrupt enabled to allow the system to power up on | 748 | * Keep the ALARM interrupt enabled to allow the system to power up on |
| 710 | * alarm events. | 749 | * alarm events. |
| 711 | */ | 750 | */ |
| 751 | rtc->type->unlock(rtc); | ||
| 712 | mask = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); | 752 | mask = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); |
| 713 | mask &= OMAP_RTC_INTERRUPTS_IT_ALARM; | 753 | mask &= OMAP_RTC_INTERRUPTS_IT_ALARM; |
| 714 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, mask); | 754 | rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, mask); |
| 755 | rtc->type->lock(rtc); | ||
| 715 | } | 756 | } |
| 716 | 757 | ||
| 717 | static struct platform_driver omap_rtc_driver = { | 758 | static struct platform_driver omap_rtc_driver = { |
| 759 | .probe = omap_rtc_probe, | ||
| 718 | .remove = __exit_p(omap_rtc_remove), | 760 | .remove = __exit_p(omap_rtc_remove), |
| 719 | .shutdown = omap_rtc_shutdown, | 761 | .shutdown = omap_rtc_shutdown, |
| 720 | .driver = { | 762 | .driver = { |
| @@ -725,7 +767,7 @@ static struct platform_driver omap_rtc_driver = { | |||
| 725 | .id_table = omap_rtc_id_table, | 767 | .id_table = omap_rtc_id_table, |
| 726 | }; | 768 | }; |
| 727 | 769 | ||
| 728 | module_platform_driver_probe(omap_rtc_driver, omap_rtc_probe); | 770 | module_platform_driver(omap_rtc_driver); |
| 729 | 771 | ||
| 730 | MODULE_ALIAS("platform:omap_rtc"); | 772 | MODULE_ALIAS("platform:omap_rtc"); |
| 731 | MODULE_AUTHOR("George G. Davis (and others)"); | 773 | MODULE_AUTHOR("George G. Davis (and others)"); |
