diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/rtc/rtc-s3c.c | 71 | ||||
| -rw-r--r-- | drivers/rtc/rtc-sa1100.c | 207 |
3 files changed, 165 insertions, 117 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 3a125b835546..59efc63c4e48 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -773,8 +773,8 @@ config RTC_DRV_EP93XX | |||
| 773 | will be called rtc-ep93xx. | 773 | will be called rtc-ep93xx. |
| 774 | 774 | ||
| 775 | config RTC_DRV_SA1100 | 775 | config RTC_DRV_SA1100 |
| 776 | tristate "SA11x0/PXA2xx" | 776 | tristate "SA11x0/PXA2xx/PXA910" |
| 777 | depends on ARCH_SA1100 || ARCH_PXA | 777 | depends on ARCH_SA1100 || ARCH_PXA || ARCH_MMP |
| 778 | help | 778 | help |
| 779 | If you say Y here you will get access to the real time clock | 779 | If you say Y here you will get access to the real time clock |
| 780 | built into your SA11x0 or PXA2xx CPU. | 780 | built into your SA11x0 or PXA2xx CPU. |
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index aef40bd2957b..78951866f8ab 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c | |||
| @@ -35,6 +35,8 @@ | |||
| 35 | 35 | ||
| 36 | enum s3c_cpu_type { | 36 | enum s3c_cpu_type { |
| 37 | TYPE_S3C2410, | 37 | TYPE_S3C2410, |
| 38 | TYPE_S3C2416, | ||
| 39 | TYPE_S3C2443, | ||
| 38 | TYPE_S3C64XX, | 40 | TYPE_S3C64XX, |
| 39 | }; | 41 | }; |
| 40 | 42 | ||
| @@ -132,6 +134,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) | |||
| 132 | struct platform_device *pdev = to_platform_device(dev); | 134 | struct platform_device *pdev = to_platform_device(dev); |
| 133 | struct rtc_device *rtc_dev = platform_get_drvdata(pdev); | 135 | struct rtc_device *rtc_dev = platform_get_drvdata(pdev); |
| 134 | unsigned int tmp = 0; | 136 | unsigned int tmp = 0; |
| 137 | int val; | ||
| 135 | 138 | ||
| 136 | if (!is_power_of_2(freq)) | 139 | if (!is_power_of_2(freq)) |
| 137 | return -EINVAL; | 140 | return -EINVAL; |
| @@ -139,12 +142,22 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) | |||
| 139 | clk_enable(rtc_clk); | 142 | clk_enable(rtc_clk); |
| 140 | spin_lock_irq(&s3c_rtc_pie_lock); | 143 | spin_lock_irq(&s3c_rtc_pie_lock); |
| 141 | 144 | ||
| 142 | if (s3c_rtc_cpu_type == TYPE_S3C2410) { | 145 | if (s3c_rtc_cpu_type != TYPE_S3C64XX) { |
| 143 | tmp = readb(s3c_rtc_base + S3C2410_TICNT); | 146 | tmp = readb(s3c_rtc_base + S3C2410_TICNT); |
| 144 | tmp &= S3C2410_TICNT_ENABLE; | 147 | tmp &= S3C2410_TICNT_ENABLE; |
| 145 | } | 148 | } |
| 146 | 149 | ||
| 147 | tmp |= (rtc_dev->max_user_freq / freq)-1; | 150 | val = (rtc_dev->max_user_freq / freq) - 1; |
| 151 | |||
| 152 | if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) { | ||
| 153 | tmp |= S3C2443_TICNT_PART(val); | ||
| 154 | writel(S3C2443_TICNT1_PART(val), s3c_rtc_base + S3C2443_TICNT1); | ||
| 155 | |||
| 156 | if (s3c_rtc_cpu_type == TYPE_S3C2416) | ||
| 157 | writel(S3C2416_TICNT2_PART(val), s3c_rtc_base + S3C2416_TICNT2); | ||
| 158 | } else { | ||
| 159 | tmp |= val; | ||
| 160 | } | ||
| 148 | 161 | ||
| 149 | writel(tmp, s3c_rtc_base + S3C2410_TICNT); | 162 | writel(tmp, s3c_rtc_base + S3C2410_TICNT); |
| 150 | spin_unlock_irq(&s3c_rtc_pie_lock); | 163 | spin_unlock_irq(&s3c_rtc_pie_lock); |
| @@ -371,7 +384,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) | |||
| 371 | tmp &= ~S3C2410_RTCCON_RTCEN; | 384 | tmp &= ~S3C2410_RTCCON_RTCEN; |
| 372 | writew(tmp, base + S3C2410_RTCCON); | 385 | writew(tmp, base + S3C2410_RTCCON); |
| 373 | 386 | ||
| 374 | if (s3c_rtc_cpu_type == TYPE_S3C2410) { | 387 | if (s3c_rtc_cpu_type != TYPE_S3C64XX) { |
| 375 | tmp = readb(base + S3C2410_TICNT); | 388 | tmp = readb(base + S3C2410_TICNT); |
| 376 | tmp &= ~S3C2410_TICNT_ENABLE; | 389 | tmp &= ~S3C2410_TICNT_ENABLE; |
| 377 | writeb(tmp, base + S3C2410_TICNT); | 390 | writeb(tmp, base + S3C2410_TICNT); |
| @@ -428,12 +441,27 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) | |||
| 428 | return 0; | 441 | return 0; |
| 429 | } | 442 | } |
| 430 | 443 | ||
| 444 | static const struct of_device_id s3c_rtc_dt_match[]; | ||
| 445 | |||
| 446 | static inline int s3c_rtc_get_driver_data(struct platform_device *pdev) | ||
| 447 | { | ||
| 448 | #ifdef CONFIG_OF | ||
| 449 | if (pdev->dev.of_node) { | ||
| 450 | const struct of_device_id *match; | ||
| 451 | match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); | ||
| 452 | return match->data; | ||
| 453 | } | ||
| 454 | #endif | ||
| 455 | return platform_get_device_id(pdev)->driver_data; | ||
| 456 | } | ||
| 457 | |||
| 431 | static int __devinit s3c_rtc_probe(struct platform_device *pdev) | 458 | static int __devinit s3c_rtc_probe(struct platform_device *pdev) |
| 432 | { | 459 | { |
| 433 | struct rtc_device *rtc; | 460 | struct rtc_device *rtc; |
| 434 | struct rtc_time rtc_tm; | 461 | struct rtc_time rtc_tm; |
| 435 | struct resource *res; | 462 | struct resource *res; |
| 436 | int ret; | 463 | int ret; |
| 464 | int tmp; | ||
| 437 | 465 | ||
| 438 | pr_debug("%s: probe=%p\n", __func__, pdev); | 466 | pr_debug("%s: probe=%p\n", __func__, pdev); |
| 439 | 467 | ||
| @@ -508,13 +536,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
| 508 | goto err_nortc; | 536 | goto err_nortc; |
| 509 | } | 537 | } |
| 510 | 538 | ||
| 511 | #ifdef CONFIG_OF | 539 | s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev); |
| 512 | if (pdev->dev.of_node) | ||
| 513 | s3c_rtc_cpu_type = of_device_is_compatible(pdev->dev.of_node, | ||
| 514 | "samsung,s3c6410-rtc") ? TYPE_S3C64XX : TYPE_S3C2410; | ||
| 515 | else | ||
| 516 | #endif | ||
| 517 | s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; | ||
| 518 | 540 | ||
| 519 | /* Check RTC Time */ | 541 | /* Check RTC Time */ |
| 520 | 542 | ||
| @@ -533,11 +555,17 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
| 533 | dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); | 555 | dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); |
| 534 | } | 556 | } |
| 535 | 557 | ||
| 536 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | 558 | if (s3c_rtc_cpu_type != TYPE_S3C2410) |
| 537 | rtc->max_user_freq = 32768; | 559 | rtc->max_user_freq = 32768; |
| 538 | else | 560 | else |
| 539 | rtc->max_user_freq = 128; | 561 | rtc->max_user_freq = 128; |
| 540 | 562 | ||
| 563 | if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) { | ||
| 564 | tmp = readw(s3c_rtc_base + S3C2410_RTCCON); | ||
| 565 | tmp |= S3C2443_RTCCON_TICSEL; | ||
| 566 | writew(tmp, s3c_rtc_base + S3C2410_RTCCON); | ||
| 567 | } | ||
| 568 | |||
| 541 | platform_set_drvdata(pdev, rtc); | 569 | platform_set_drvdata(pdev, rtc); |
| 542 | 570 | ||
| 543 | s3c_rtc_setfreq(&pdev->dev, 1); | 571 | s3c_rtc_setfreq(&pdev->dev, 1); |
| @@ -638,8 +666,19 @@ static int s3c_rtc_resume(struct platform_device *pdev) | |||
| 638 | 666 | ||
| 639 | #ifdef CONFIG_OF | 667 | #ifdef CONFIG_OF |
| 640 | static const struct of_device_id s3c_rtc_dt_match[] = { | 668 | static const struct of_device_id s3c_rtc_dt_match[] = { |
| 641 | { .compatible = "samsung,s3c2410-rtc" }, | 669 | { |
| 642 | { .compatible = "samsung,s3c6410-rtc" }, | 670 | .compatible = "samsung,s3c2410-rtc" |
| 671 | .data = TYPE_S3C2410, | ||
| 672 | }, { | ||
| 673 | .compatible = "samsung,s3c2416-rtc" | ||
| 674 | .data = TYPE_S3C2416, | ||
| 675 | }, { | ||
| 676 | .compatible = "samsung,s3c2443-rtc" | ||
| 677 | .data = TYPE_S3C2443, | ||
| 678 | }, { | ||
| 679 | .compatible = "samsung,s3c6410-rtc" | ||
| 680 | .data = TYPE_S3C64XX, | ||
| 681 | }, | ||
| 643 | {}, | 682 | {}, |
| 644 | }; | 683 | }; |
| 645 | MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); | 684 | MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); |
| @@ -652,6 +691,12 @@ static struct platform_device_id s3c_rtc_driver_ids[] = { | |||
| 652 | .name = "s3c2410-rtc", | 691 | .name = "s3c2410-rtc", |
| 653 | .driver_data = TYPE_S3C2410, | 692 | .driver_data = TYPE_S3C2410, |
| 654 | }, { | 693 | }, { |
| 694 | .name = "s3c2416-rtc", | ||
| 695 | .driver_data = TYPE_S3C2416, | ||
| 696 | }, { | ||
| 697 | .name = "s3c2443-rtc", | ||
| 698 | .driver_data = TYPE_S3C2443, | ||
| 699 | }, { | ||
| 655 | .name = "s3c64xx-rtc", | 700 | .name = "s3c64xx-rtc", |
| 656 | .driver_data = TYPE_S3C64XX, | 701 | .driver_data = TYPE_S3C64XX, |
| 657 | }, | 702 | }, |
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index cb9a585312cc..e443b7850ede 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c | |||
| @@ -23,94 +23,44 @@ | |||
| 23 | 23 | ||
| 24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 26 | #include <linux/clk.h> | ||
| 26 | #include <linux/rtc.h> | 27 | #include <linux/rtc.h> |
| 27 | #include <linux/init.h> | 28 | #include <linux/init.h> |
| 28 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
| 29 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
| 31 | #include <linux/slab.h> | ||
| 30 | #include <linux/string.h> | 32 | #include <linux/string.h> |
| 33 | #include <linux/of.h> | ||
| 31 | #include <linux/pm.h> | 34 | #include <linux/pm.h> |
| 32 | #include <linux/bitops.h> | 35 | #include <linux/bitops.h> |
| 33 | 36 | ||
| 34 | #include <mach/hardware.h> | 37 | #include <mach/hardware.h> |
| 35 | #include <asm/irq.h> | 38 | #include <asm/irq.h> |
| 36 | 39 | ||
| 37 | #ifdef CONFIG_ARCH_PXA | 40 | #if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) |
| 38 | #include <mach/regs-rtc.h> | 41 | #include <mach/regs-rtc.h> |
| 39 | #endif | 42 | #endif |
| 40 | 43 | ||
| 41 | #define RTC_DEF_DIVIDER (32768 - 1) | 44 | #define RTC_DEF_DIVIDER (32768 - 1) |
| 42 | #define RTC_DEF_TRIM 0 | 45 | #define RTC_DEF_TRIM 0 |
| 43 | 46 | #define RTC_FREQ 1024 | |
| 44 | static const unsigned long RTC_FREQ = 1024; | 47 | |
| 45 | static struct rtc_time rtc_alarm; | 48 | struct sa1100_rtc { |
| 46 | static DEFINE_SPINLOCK(sa1100_rtc_lock); | 49 | spinlock_t lock; |
| 47 | 50 | int irq_1hz; | |
| 48 | static inline int rtc_periodic_alarm(struct rtc_time *tm) | 51 | int irq_alarm; |
| 49 | { | 52 | struct rtc_device *rtc; |
| 50 | return (tm->tm_year == -1) || | 53 | struct clk *clk; |
| 51 | ((unsigned)tm->tm_mon >= 12) || | 54 | }; |
| 52 | ((unsigned)(tm->tm_mday - 1) >= 31) || | ||
| 53 | ((unsigned)tm->tm_hour > 23) || | ||
| 54 | ((unsigned)tm->tm_min > 59) || | ||
| 55 | ((unsigned)tm->tm_sec > 59); | ||
| 56 | } | ||
| 57 | |||
| 58 | /* | ||
| 59 | * Calculate the next alarm time given the requested alarm time mask | ||
| 60 | * and the current time. | ||
| 61 | */ | ||
| 62 | static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, | ||
| 63 | struct rtc_time *alrm) | ||
| 64 | { | ||
| 65 | unsigned long next_time; | ||
| 66 | unsigned long now_time; | ||
| 67 | |||
| 68 | next->tm_year = now->tm_year; | ||
| 69 | next->tm_mon = now->tm_mon; | ||
| 70 | next->tm_mday = now->tm_mday; | ||
| 71 | next->tm_hour = alrm->tm_hour; | ||
| 72 | next->tm_min = alrm->tm_min; | ||
| 73 | next->tm_sec = alrm->tm_sec; | ||
| 74 | |||
| 75 | rtc_tm_to_time(now, &now_time); | ||
| 76 | rtc_tm_to_time(next, &next_time); | ||
| 77 | |||
| 78 | if (next_time < now_time) { | ||
| 79 | /* Advance one day */ | ||
| 80 | next_time += 60 * 60 * 24; | ||
| 81 | rtc_time_to_tm(next_time, next); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | static int rtc_update_alarm(struct rtc_time *alrm) | ||
| 86 | { | ||
| 87 | struct rtc_time alarm_tm, now_tm; | ||
| 88 | unsigned long now, time; | ||
| 89 | int ret; | ||
| 90 | |||
| 91 | do { | ||
| 92 | now = RCNR; | ||
| 93 | rtc_time_to_tm(now, &now_tm); | ||
| 94 | rtc_next_alarm_time(&alarm_tm, &now_tm, alrm); | ||
| 95 | ret = rtc_tm_to_time(&alarm_tm, &time); | ||
| 96 | if (ret != 0) | ||
| 97 | break; | ||
| 98 | |||
| 99 | RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); | ||
| 100 | RTAR = time; | ||
| 101 | } while (now != RCNR); | ||
| 102 | |||
| 103 | return ret; | ||
| 104 | } | ||
| 105 | 55 | ||
| 106 | static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | 56 | static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) |
| 107 | { | 57 | { |
| 108 | struct platform_device *pdev = to_platform_device(dev_id); | 58 | struct sa1100_rtc *info = dev_get_drvdata(dev_id); |
| 109 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 59 | struct rtc_device *rtc = info->rtc; |
| 110 | unsigned int rtsr; | 60 | unsigned int rtsr; |
| 111 | unsigned long events = 0; | 61 | unsigned long events = 0; |
| 112 | 62 | ||
| 113 | spin_lock(&sa1100_rtc_lock); | 63 | spin_lock(&info->lock); |
| 114 | 64 | ||
| 115 | rtsr = RTSR; | 65 | rtsr = RTSR; |
| 116 | /* clear interrupt sources */ | 66 | /* clear interrupt sources */ |
| @@ -146,30 +96,30 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | |||
| 146 | 96 | ||
| 147 | rtc_update_irq(rtc, 1, events); | 97 | rtc_update_irq(rtc, 1, events); |
| 148 | 98 | ||
| 149 | if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm)) | 99 | spin_unlock(&info->lock); |
| 150 | rtc_update_alarm(&rtc_alarm); | ||
| 151 | |||
| 152 | spin_unlock(&sa1100_rtc_lock); | ||
| 153 | 100 | ||
| 154 | return IRQ_HANDLED; | 101 | return IRQ_HANDLED; |
| 155 | } | 102 | } |
| 156 | 103 | ||
| 157 | static int sa1100_rtc_open(struct device *dev) | 104 | static int sa1100_rtc_open(struct device *dev) |
| 158 | { | 105 | { |
| 106 | struct sa1100_rtc *info = dev_get_drvdata(dev); | ||
| 107 | struct rtc_device *rtc = info->rtc; | ||
| 159 | int ret; | 108 | int ret; |
| 160 | struct platform_device *plat_dev = to_platform_device(dev); | ||
| 161 | struct rtc_device *rtc = platform_get_drvdata(plat_dev); | ||
| 162 | 109 | ||
| 163 | ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, | 110 | ret = clk_prepare_enable(info->clk); |
| 111 | if (ret) | ||
| 112 | goto fail_clk; | ||
| 113 | ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, IRQF_DISABLED, | ||
| 164 | "rtc 1Hz", dev); | 114 | "rtc 1Hz", dev); |
| 165 | if (ret) { | 115 | if (ret) { |
| 166 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); | 116 | dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz); |
| 167 | goto fail_ui; | 117 | goto fail_ui; |
| 168 | } | 118 | } |
| 169 | ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, | 119 | ret = request_irq(info->irq_alarm, sa1100_rtc_interrupt, IRQF_DISABLED, |
| 170 | "rtc Alrm", dev); | 120 | "rtc Alrm", dev); |
| 171 | if (ret) { | 121 | if (ret) { |
| 172 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); | 122 | dev_err(dev, "IRQ %d already in use.\n", info->irq_alarm); |
| 173 | goto fail_ai; | 123 | goto fail_ai; |
| 174 | } | 124 | } |
| 175 | rtc->max_user_freq = RTC_FREQ; | 125 | rtc->max_user_freq = RTC_FREQ; |
| @@ -178,29 +128,36 @@ static int sa1100_rtc_open(struct device *dev) | |||
| 178 | return 0; | 128 | return 0; |
| 179 | 129 | ||
| 180 | fail_ai: | 130 | fail_ai: |
| 181 | free_irq(IRQ_RTC1Hz, dev); | 131 | free_irq(info->irq_1hz, dev); |
| 182 | fail_ui: | 132 | fail_ui: |
| 133 | clk_disable_unprepare(info->clk); | ||
| 134 | fail_clk: | ||
| 183 | return ret; | 135 | return ret; |
| 184 | } | 136 | } |
| 185 | 137 | ||
| 186 | static void sa1100_rtc_release(struct device *dev) | 138 | static void sa1100_rtc_release(struct device *dev) |
| 187 | { | 139 | { |
| 188 | spin_lock_irq(&sa1100_rtc_lock); | 140 | struct sa1100_rtc *info = dev_get_drvdata(dev); |
| 141 | |||
| 142 | spin_lock_irq(&info->lock); | ||
| 189 | RTSR = 0; | 143 | RTSR = 0; |
| 190 | spin_unlock_irq(&sa1100_rtc_lock); | 144 | spin_unlock_irq(&info->lock); |
| 191 | 145 | ||
| 192 | free_irq(IRQ_RTCAlrm, dev); | 146 | free_irq(info->irq_alarm, dev); |
| 193 | free_irq(IRQ_RTC1Hz, dev); | 147 | free_irq(info->irq_1hz, dev); |
| 148 | clk_disable_unprepare(info->clk); | ||
| 194 | } | 149 | } |
| 195 | 150 | ||
| 196 | static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | 151 | static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
| 197 | { | 152 | { |
| 198 | spin_lock_irq(&sa1100_rtc_lock); | 153 | struct sa1100_rtc *info = dev_get_drvdata(dev); |
| 154 | |||
| 155 | spin_lock_irq(&info->lock); | ||
| 199 | if (enabled) | 156 | if (enabled) |
| 200 | RTSR |= RTSR_ALE; | 157 | RTSR |= RTSR_ALE; |
| 201 | else | 158 | else |
| 202 | RTSR &= ~RTSR_ALE; | 159 | RTSR &= ~RTSR_ALE; |
| 203 | spin_unlock_irq(&sa1100_rtc_lock); | 160 | spin_unlock_irq(&info->lock); |
| 204 | return 0; | 161 | return 0; |
| 205 | } | 162 | } |
| 206 | 163 | ||
| @@ -225,7 +182,6 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
| 225 | { | 182 | { |
| 226 | u32 rtsr; | 183 | u32 rtsr; |
| 227 | 184 | ||
| 228 | memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time)); | ||
| 229 | rtsr = RTSR; | 185 | rtsr = RTSR; |
| 230 | alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; | 186 | alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; |
| 231 | alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; | 187 | alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; |
| @@ -234,17 +190,22 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
| 234 | 190 | ||
| 235 | static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 191 | static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
| 236 | { | 192 | { |
| 193 | struct sa1100_rtc *info = dev_get_drvdata(dev); | ||
| 194 | unsigned long time; | ||
| 237 | int ret; | 195 | int ret; |
| 238 | 196 | ||
| 239 | spin_lock_irq(&sa1100_rtc_lock); | 197 | spin_lock_irq(&info->lock); |
| 240 | ret = rtc_update_alarm(&alrm->time); | 198 | ret = rtc_tm_to_time(&alrm->time, &time); |
| 241 | if (ret == 0) { | 199 | if (ret != 0) |
| 242 | if (alrm->enabled) | 200 | goto out; |
| 243 | RTSR |= RTSR_ALE; | 201 | RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); |
| 244 | else | 202 | RTAR = time; |
| 245 | RTSR &= ~RTSR_ALE; | 203 | if (alrm->enabled) |
| 246 | } | 204 | RTSR |= RTSR_ALE; |
| 247 | spin_unlock_irq(&sa1100_rtc_lock); | 205 | else |
| 206 | RTSR &= ~RTSR_ALE; | ||
| 207 | out: | ||
| 208 | spin_unlock_irq(&info->lock); | ||
| 248 | 209 | ||
| 249 | return ret; | 210 | return ret; |
| 250 | } | 211 | } |
| @@ -271,6 +232,27 @@ static const struct rtc_class_ops sa1100_rtc_ops = { | |||
| 271 | static int sa1100_rtc_probe(struct platform_device *pdev) | 232 | static int sa1100_rtc_probe(struct platform_device *pdev) |
| 272 | { | 233 | { |
| 273 | struct rtc_device *rtc; | 234 | struct rtc_device *rtc; |
| 235 | struct sa1100_rtc *info; | ||
| 236 | int irq_1hz, irq_alarm, ret = 0; | ||
| 237 | |||
| 238 | irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); | ||
| 239 | irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); | ||
| 240 | if (irq_1hz < 0 || irq_alarm < 0) | ||
| 241 | return -ENODEV; | ||
| 242 | |||
| 243 | info = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL); | ||
| 244 | if (!info) | ||
| 245 | return -ENOMEM; | ||
| 246 | info->clk = clk_get(&pdev->dev, NULL); | ||
| 247 | if (IS_ERR(info->clk)) { | ||
| 248 | dev_err(&pdev->dev, "failed to find rtc clock source\n"); | ||
| 249 | ret = PTR_ERR(info->clk); | ||
| 250 | goto err_clk; | ||
| 251 | } | ||
| 252 | info->irq_1hz = irq_1hz; | ||
| 253 | info->irq_alarm = irq_alarm; | ||
| 254 | spin_lock_init(&info->lock); | ||
| 255 | platform_set_drvdata(pdev, info); | ||
| 274 | 256 | ||
| 275 | /* | 257 | /* |
| 276 | * According to the manual we should be able to let RTTR be zero | 258 | * According to the manual we should be able to let RTTR be zero |
| @@ -292,10 +274,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev) | |||
| 292 | rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, | 274 | rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, |
| 293 | THIS_MODULE); | 275 | THIS_MODULE); |
| 294 | 276 | ||
| 295 | if (IS_ERR(rtc)) | 277 | if (IS_ERR(rtc)) { |
| 296 | return PTR_ERR(rtc); | 278 | ret = PTR_ERR(rtc); |
| 297 | 279 | goto err_dev; | |
| 298 | platform_set_drvdata(pdev, rtc); | 280 | } |
| 281 | info->rtc = rtc; | ||
| 299 | 282 | ||
| 300 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. | 283 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. |
| 301 | * See also the comments in sa1100_rtc_interrupt(). | 284 | * See also the comments in sa1100_rtc_interrupt(). |
| @@ -322,14 +305,24 @@ static int sa1100_rtc_probe(struct platform_device *pdev) | |||
| 322 | RTSR = RTSR_AL | RTSR_HZ; | 305 | RTSR = RTSR_AL | RTSR_HZ; |
| 323 | 306 | ||
| 324 | return 0; | 307 | return 0; |
| 308 | err_dev: | ||
| 309 | platform_set_drvdata(pdev, NULL); | ||
| 310 | clk_put(info->clk); | ||
| 311 | err_clk: | ||
| 312 | kfree(info); | ||
| 313 | return ret; | ||
| 325 | } | 314 | } |
| 326 | 315 | ||
| 327 | static int sa1100_rtc_remove(struct platform_device *pdev) | 316 | static int sa1100_rtc_remove(struct platform_device *pdev) |
| 328 | { | 317 | { |
| 329 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 318 | struct sa1100_rtc *info = platform_get_drvdata(pdev); |
| 330 | 319 | ||
| 331 | if (rtc) | 320 | if (info) { |
| 332 | rtc_device_unregister(rtc); | 321 | rtc_device_unregister(info->rtc); |
| 322 | clk_put(info->clk); | ||
| 323 | platform_set_drvdata(pdev, NULL); | ||
| 324 | kfree(info); | ||
| 325 | } | ||
| 333 | 326 | ||
| 334 | return 0; | 327 | return 0; |
| 335 | } | 328 | } |
| @@ -337,15 +330,17 @@ static int sa1100_rtc_remove(struct platform_device *pdev) | |||
| 337 | #ifdef CONFIG_PM | 330 | #ifdef CONFIG_PM |
| 338 | static int sa1100_rtc_suspend(struct device *dev) | 331 | static int sa1100_rtc_suspend(struct device *dev) |
| 339 | { | 332 | { |
| 333 | struct sa1100_rtc *info = dev_get_drvdata(dev); | ||
| 340 | if (device_may_wakeup(dev)) | 334 | if (device_may_wakeup(dev)) |
| 341 | enable_irq_wake(IRQ_RTCAlrm); | 335 | enable_irq_wake(info->irq_alarm); |
| 342 | return 0; | 336 | return 0; |
| 343 | } | 337 | } |
| 344 | 338 | ||
| 345 | static int sa1100_rtc_resume(struct device *dev) | 339 | static int sa1100_rtc_resume(struct device *dev) |
| 346 | { | 340 | { |
| 341 | struct sa1100_rtc *info = dev_get_drvdata(dev); | ||
| 347 | if (device_may_wakeup(dev)) | 342 | if (device_may_wakeup(dev)) |
| 348 | disable_irq_wake(IRQ_RTCAlrm); | 343 | disable_irq_wake(info->irq_alarm); |
| 349 | return 0; | 344 | return 0; |
| 350 | } | 345 | } |
| 351 | 346 | ||
| @@ -355,6 +350,13 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = { | |||
| 355 | }; | 350 | }; |
| 356 | #endif | 351 | #endif |
| 357 | 352 | ||
| 353 | static struct of_device_id sa1100_rtc_dt_ids[] = { | ||
| 354 | { .compatible = "mrvl,sa1100-rtc", }, | ||
| 355 | { .compatible = "mrvl,mmp-rtc", }, | ||
| 356 | {} | ||
| 357 | }; | ||
| 358 | MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids); | ||
| 359 | |||
| 358 | static struct platform_driver sa1100_rtc_driver = { | 360 | static struct platform_driver sa1100_rtc_driver = { |
| 359 | .probe = sa1100_rtc_probe, | 361 | .probe = sa1100_rtc_probe, |
| 360 | .remove = sa1100_rtc_remove, | 362 | .remove = sa1100_rtc_remove, |
| @@ -363,6 +365,7 @@ static struct platform_driver sa1100_rtc_driver = { | |||
| 363 | #ifdef CONFIG_PM | 365 | #ifdef CONFIG_PM |
| 364 | .pm = &sa1100_rtc_pm_ops, | 366 | .pm = &sa1100_rtc_pm_ops, |
| 365 | #endif | 367 | #endif |
| 368 | .of_match_table = sa1100_rtc_dt_ids, | ||
| 366 | }, | 369 | }, |
| 367 | }; | 370 | }; |
| 368 | 371 | ||
