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 | ||