diff options
author | Jett.Zhou <jtzhou@marvell.com> | 2011-11-29 23:26:23 -0500 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2011-12-28 05:42:38 -0500 |
commit | 7cea00657dd4daef66ad95e976d5d67ed94cb97e (patch) | |
tree | aac948c4fbc5e12c53e7c7eeb1cb11e2e9afb199 | |
parent | 42874759d7494648e42e6e0465fc9c4f3752bba4 (diff) |
RTC: sa1100: support sa1100, pxa and mmp soc families
Since the regmap of rtc on sa1100, pxa and mmp Marvell soc families are
almost the same, so re-arch the rtc-sa1100 to support them.
Signed-off-by: Jett.Zhou <jtzhou@marvell.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com>
Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r-- | arch/arm/mach-pxa/devices.c | 20 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/generic.c | 20 | ||||
-rw-r--r-- | drivers/rtc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-sa1100.c | 256 |
4 files changed, 218 insertions, 80 deletions
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index 2e0425404de5..8b134c3b457f 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c | |||
@@ -415,9 +415,29 @@ static struct resource pxa_rtc_resources[] = { | |||
415 | }, | 415 | }, |
416 | }; | 416 | }; |
417 | 417 | ||
418 | static struct resource sa1100_rtc_resources[] = { | ||
419 | [0] = { | ||
420 | .start = 0x40900000, | ||
421 | .end = 0x409000ff, | ||
422 | .flags = IORESOURCE_MEM, | ||
423 | }, | ||
424 | [1] = { | ||
425 | .start = IRQ_RTC1Hz, | ||
426 | .end = IRQ_RTC1Hz, | ||
427 | .flags = IORESOURCE_IRQ, | ||
428 | }, | ||
429 | [2] = { | ||
430 | .start = IRQ_RTCAlrm, | ||
431 | .end = IRQ_RTCAlrm, | ||
432 | .flags = IORESOURCE_IRQ, | ||
433 | }, | ||
434 | }; | ||
435 | |||
418 | struct platform_device sa1100_device_rtc = { | 436 | struct platform_device sa1100_device_rtc = { |
419 | .name = "sa1100-rtc", | 437 | .name = "sa1100-rtc", |
420 | .id = -1, | 438 | .id = -1, |
439 | .num_resources = ARRAY_SIZE(sa1100_rtc_resources), | ||
440 | .resource = sa1100_rtc_resources, | ||
421 | }; | 441 | }; |
422 | 442 | ||
423 | struct platform_device pxa_device_rtc = { | 443 | struct platform_device pxa_device_rtc = { |
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 5fa5ae1f39e1..3eff179d4fd7 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c | |||
@@ -334,9 +334,29 @@ void sa11x0_register_irda(struct irda_platform_data *irda) | |||
334 | sa11x0_register_device(&sa11x0ir_device, irda); | 334 | sa11x0_register_device(&sa11x0ir_device, irda); |
335 | } | 335 | } |
336 | 336 | ||
337 | static struct resource sa11x0rtc_resources[] = { | ||
338 | [0] = { | ||
339 | .start = 0x90010000, | ||
340 | .end = 0x900100ff, | ||
341 | .flags = IORESOURCE_MEM, | ||
342 | }, | ||
343 | [1] = { | ||
344 | .start = IRQ_RTC1Hz, | ||
345 | .end = IRQ_RTC1Hz, | ||
346 | .flags = IORESOURCE_IRQ, | ||
347 | }, | ||
348 | [2] = { | ||
349 | .start = IRQ_RTCAlrm, | ||
350 | .end = IRQ_RTCAlrm, | ||
351 | .flags = IORESOURCE_IRQ, | ||
352 | }, | ||
353 | }; | ||
354 | |||
337 | static struct platform_device sa11x0rtc_device = { | 355 | static struct platform_device sa11x0rtc_device = { |
338 | .name = "sa1100-rtc", | 356 | .name = "sa1100-rtc", |
339 | .id = -1, | 357 | .id = -1, |
358 | .resource = sa11x0rtc_resources, | ||
359 | .num_resources = ARRAY_SIZE(sa11x0rtc_resources), | ||
340 | }; | 360 | }; |
341 | 361 | ||
342 | static struct platform_device *sa11x0_devices[] __initdata = { | 362 | static struct platform_device *sa11x0_devices[] __initdata = { |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 53eb4e55b289..877cf6fdcf24 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -774,7 +774,7 @@ config RTC_DRV_EP93XX | |||
774 | 774 | ||
775 | config RTC_DRV_SA1100 | 775 | config RTC_DRV_SA1100 |
776 | tristate "SA11x0/PXA2xx" | 776 | tristate "SA11x0/PXA2xx" |
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-sa1100.c b/drivers/rtc/rtc-sa1100.c index d268cf11b367..fc1ffe97fca1 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c | |||
@@ -27,24 +27,42 @@ | |||
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/string.h> | ||
31 | #include <linux/pm.h> | 30 | #include <linux/pm.h> |
32 | #include <linux/bitops.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/clk.h> | ||
33 | #include <linux/io.h> | ||
33 | 34 | ||
34 | #include <mach/hardware.h> | 35 | #include <mach/hardware.h> |
35 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
36 | 37 | ||
37 | #ifdef CONFIG_ARCH_PXA | ||
38 | #include <mach/regs-rtc.h> | ||
39 | #endif | ||
40 | |||
41 | #define RTC_DEF_DIVIDER (32768 - 1) | 38 | #define RTC_DEF_DIVIDER (32768 - 1) |
42 | #define RTC_DEF_TRIM 0 | 39 | #define RTC_DEF_TRIM 0 |
43 | 40 | #define RTC_FREQ 1024 | |
44 | static const unsigned long RTC_FREQ = 1024; | 41 | |
45 | static struct rtc_time rtc_alarm; | 42 | #define RCNR 0x00 /* RTC Count Register */ |
46 | static DEFINE_SPINLOCK(sa1100_rtc_lock); | 43 | #define RTAR 0x04 /* RTC Alarm Register */ |
47 | 44 | #define RTSR 0x08 /* RTC Status Register */ | |
45 | #define RTTR 0x0c /* RTC Timer Trim Register */ | ||
46 | |||
47 | #define RTSR_HZE (1 << 3) /* HZ interrupt enable */ | ||
48 | #define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */ | ||
49 | #define RTSR_HZ (1 << 1) /* HZ rising-edge detected */ | ||
50 | #define RTSR_AL (1 << 0) /* RTC alarm detected */ | ||
51 | |||
52 | #define rtc_readl(sa1100_rtc, reg) \ | ||
53 | readl_relaxed((sa1100_rtc)->base + (reg)) | ||
54 | #define rtc_writel(sa1100_rtc, reg, value) \ | ||
55 | writel_relaxed((value), (sa1100_rtc)->base + (reg)) | ||
56 | |||
57 | struct sa1100_rtc { | ||
58 | struct resource *ress; | ||
59 | void __iomem *base; | ||
60 | struct clk *clk; | ||
61 | int irq_1Hz; | ||
62 | int irq_Alrm; | ||
63 | struct rtc_device *rtc; | ||
64 | spinlock_t lock; /* Protects this structure */ | ||
65 | }; | ||
48 | /* | 66 | /* |
49 | * Calculate the next alarm time given the requested alarm time mask | 67 | * Calculate the next alarm time given the requested alarm time mask |
50 | * and the current time. | 68 | * and the current time. |
@@ -75,22 +93,23 @@ static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, | |||
75 | static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | 93 | static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) |
76 | { | 94 | { |
77 | struct platform_device *pdev = to_platform_device(dev_id); | 95 | struct platform_device *pdev = to_platform_device(dev_id); |
78 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 96 | struct sa1100_rtc *sa1100_rtc = platform_get_drvdata(pdev); |
79 | unsigned int rtsr; | 97 | unsigned int rtsr; |
80 | unsigned long events = 0; | 98 | unsigned long events = 0; |
81 | 99 | ||
82 | spin_lock(&sa1100_rtc_lock); | 100 | spin_lock(&sa1100_rtc->lock); |
83 | 101 | ||
84 | rtsr = RTSR; | ||
85 | /* clear interrupt sources */ | 102 | /* clear interrupt sources */ |
86 | RTSR = 0; | 103 | rtsr = rtc_readl(sa1100_rtc, RTSR); |
104 | rtc_writel(sa1100_rtc, RTSR, 0); | ||
105 | |||
87 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. | 106 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. |
88 | * See also the comments in sa1100_rtc_probe(). */ | 107 | * See also the comments in sa1100_rtc_probe(). */ |
89 | if (rtsr & (RTSR_ALE | RTSR_HZE)) { | 108 | if (rtsr & (RTSR_ALE | RTSR_HZE)) { |
90 | /* This is the original code, before there was the if test | 109 | /* This is the original code, before there was the if test |
91 | * above. This code does not clear interrupts that were not | 110 | * above. This code does not clear interrupts that were not |
92 | * enabled. */ | 111 | * enabled. */ |
93 | RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); | 112 | rtc_writel(sa1100_rtc, RTSR, (RTSR_AL | RTSR_HZ) & (rtsr >> 2)); |
94 | } else { | 113 | } else { |
95 | /* For some reason, it is possible to enter this routine | 114 | /* For some reason, it is possible to enter this routine |
96 | * without interruptions enabled, it has been tested with | 115 | * without interruptions enabled, it has been tested with |
@@ -99,13 +118,13 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | |||
99 | * This situation leads to an infinite "loop" of interrupt | 118 | * This situation leads to an infinite "loop" of interrupt |
100 | * routine calling and as a result the processor seems to | 119 | * routine calling and as a result the processor seems to |
101 | * lock on its first call to open(). */ | 120 | * lock on its first call to open(). */ |
102 | RTSR = RTSR_AL | RTSR_HZ; | 121 | rtc_writel(sa1100_rtc, RTSR, (RTSR_AL | RTSR_HZ)); |
103 | } | 122 | } |
104 | 123 | ||
105 | /* clear alarm interrupt if it has occurred */ | 124 | /* clear alarm interrupt if it has occurred */ |
106 | if (rtsr & RTSR_AL) | 125 | if (rtsr & RTSR_AL) |
107 | rtsr &= ~RTSR_ALE; | 126 | rtsr &= ~RTSR_ALE; |
108 | RTSR = rtsr & (RTSR_ALE | RTSR_HZE); | 127 | rtc_writel(sa1100_rtc, RTSR, rtsr & (RTSR_ALE | RTSR_HZE)); |
109 | 128 | ||
110 | /* update irq data & counter */ | 129 | /* update irq data & counter */ |
111 | if (rtsr & RTSR_AL) | 130 | if (rtsr & RTSR_AL) |
@@ -113,86 +132,100 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | |||
113 | if (rtsr & RTSR_HZ) | 132 | if (rtsr & RTSR_HZ) |
114 | events |= RTC_UF | RTC_IRQF; | 133 | events |= RTC_UF | RTC_IRQF; |
115 | 134 | ||
116 | rtc_update_irq(rtc, 1, events); | 135 | rtc_update_irq(sa1100_rtc->rtc, 1, events); |
117 | 136 | ||
118 | spin_unlock(&sa1100_rtc_lock); | 137 | spin_unlock(&sa1100_rtc->lock); |
119 | 138 | ||
120 | return IRQ_HANDLED; | 139 | return IRQ_HANDLED; |
121 | } | 140 | } |
122 | 141 | ||
123 | static int sa1100_rtc_open(struct device *dev) | 142 | static int sa1100_rtc_open(struct device *dev) |
124 | { | 143 | { |
144 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); | ||
125 | int ret; | 145 | int ret; |
126 | struct platform_device *plat_dev = to_platform_device(dev); | ||
127 | struct rtc_device *rtc = platform_get_drvdata(plat_dev); | ||
128 | 146 | ||
129 | ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, | 147 | ret = request_irq(sa1100_rtc->irq_1Hz, sa1100_rtc_interrupt, |
130 | "rtc 1Hz", dev); | 148 | IRQF_DISABLED, "rtc 1Hz", dev); |
131 | if (ret) { | 149 | if (ret) { |
132 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); | 150 | dev_err(dev, "IRQ %d already in use.\n", sa1100_rtc->irq_1Hz); |
133 | goto fail_ui; | 151 | goto fail_ui; |
134 | } | 152 | } |
135 | ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, | 153 | ret = request_irq(sa1100_rtc->irq_Alrm, sa1100_rtc_interrupt, |
136 | "rtc Alrm", dev); | 154 | IRQF_DISABLED, "rtc Alrm", dev); |
137 | if (ret) { | 155 | if (ret) { |
138 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); | 156 | dev_err(dev, "IRQ %d already in use.\n", sa1100_rtc->irq_Alrm); |
139 | goto fail_ai; | 157 | goto fail_ai; |
140 | } | 158 | } |
141 | rtc->max_user_freq = RTC_FREQ; | 159 | sa1100_rtc->rtc->max_user_freq = RTC_FREQ; |
142 | rtc_irq_set_freq(rtc, NULL, RTC_FREQ); | 160 | rtc_irq_set_freq(sa1100_rtc->rtc, NULL, RTC_FREQ); |
143 | 161 | ||
144 | return 0; | 162 | return 0; |
145 | 163 | ||
146 | fail_ai: | 164 | fail_ai: |
147 | free_irq(IRQ_RTC1Hz, dev); | 165 | free_irq(sa1100_rtc->irq_1Hz, dev); |
148 | fail_ui: | 166 | fail_ui: |
149 | return ret; | 167 | return ret; |
150 | } | 168 | } |
151 | 169 | ||
152 | static void sa1100_rtc_release(struct device *dev) | 170 | static void sa1100_rtc_release(struct device *dev) |
153 | { | 171 | { |
154 | spin_lock_irq(&sa1100_rtc_lock); | 172 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); |
155 | RTSR = 0; | ||
156 | spin_unlock_irq(&sa1100_rtc_lock); | ||
157 | 173 | ||
158 | free_irq(IRQ_RTCAlrm, dev); | 174 | spin_lock_irq(&sa1100_rtc->lock); |
159 | free_irq(IRQ_RTC1Hz, dev); | 175 | rtc_writel(sa1100_rtc, RTSR, 0); |
176 | spin_unlock_irq(&sa1100_rtc->lock); | ||
177 | |||
178 | free_irq(sa1100_rtc->irq_Alrm, dev); | ||
179 | free_irq(sa1100_rtc->irq_1Hz, dev); | ||
160 | } | 180 | } |
161 | 181 | ||
162 | static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | 182 | static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
163 | { | 183 | { |
164 | spin_lock_irq(&sa1100_rtc_lock); | 184 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); |
185 | unsigned int rtsr; | ||
186 | |||
187 | spin_lock_irq(&sa1100_rtc->lock); | ||
188 | |||
189 | rtsr = rtc_readl(sa1100_rtc, RTSR); | ||
165 | if (enabled) | 190 | if (enabled) |
166 | RTSR |= RTSR_ALE; | 191 | rtsr |= RTSR_ALE; |
167 | else | 192 | else |
168 | RTSR &= ~RTSR_ALE; | 193 | rtsr &= ~RTSR_ALE; |
169 | spin_unlock_irq(&sa1100_rtc_lock); | 194 | rtc_writel(sa1100_rtc, RTSR, rtsr); |
195 | |||
196 | spin_unlock_irq(&sa1100_rtc->lock); | ||
170 | return 0; | 197 | return 0; |
171 | } | 198 | } |
172 | 199 | ||
173 | static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) | 200 | static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) |
174 | { | 201 | { |
175 | rtc_time_to_tm(RCNR, tm); | 202 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); |
203 | |||
204 | rtc_time_to_tm(rtc_readl(sa1100_rtc, RCNR), tm); | ||
176 | return 0; | 205 | return 0; |
177 | } | 206 | } |
178 | 207 | ||
179 | static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) | 208 | static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) |
180 | { | 209 | { |
210 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); | ||
181 | unsigned long time; | 211 | unsigned long time; |
182 | int ret; | 212 | int ret; |
183 | 213 | ||
184 | ret = rtc_tm_to_time(tm, &time); | 214 | ret = rtc_tm_to_time(tm, &time); |
185 | if (ret == 0) | 215 | if (ret == 0) |
186 | RCNR = time; | 216 | rtc_writel(sa1100_rtc, RCNR, time); |
187 | return ret; | 217 | return ret; |
188 | } | 218 | } |
189 | 219 | ||
190 | static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 220 | static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
191 | { | 221 | { |
192 | u32 rtsr; | 222 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); |
223 | unsigned long time; | ||
224 | unsigned int rtsr; | ||
193 | 225 | ||
194 | memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time)); | 226 | time = rtc_readl(sa1100_rtc, RCNR); |
195 | rtsr = RTSR; | 227 | rtc_time_to_tm(time, &alrm->time); |
228 | rtsr = rtc_readl(sa1100_rtc, RTSR); | ||
196 | alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; | 229 | alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; |
197 | alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; | 230 | alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; |
198 | return 0; | 231 | return 0; |
@@ -200,31 +233,39 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
200 | 233 | ||
201 | static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 234 | static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
202 | { | 235 | { |
236 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); | ||
203 | struct rtc_time now_tm, alarm_tm; | 237 | struct rtc_time now_tm, alarm_tm; |
204 | int ret; | 238 | unsigned long time, alarm; |
239 | unsigned int rtsr; | ||
240 | |||
241 | spin_lock_irq(&sa1100_rtc->lock); | ||
205 | 242 | ||
206 | spin_lock_irq(&sa1100_rtc_lock); | 243 | time = rtc_readl(sa1100_rtc, RCNR); |
244 | rtc_time_to_tm(time, &now_tm); | ||
245 | rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time); | ||
246 | rtc_tm_to_time(&alarm_tm, &alarm); | ||
247 | rtc_writel(sa1100_rtc, RTAR, alarm); | ||
207 | 248 | ||
208 | now = RCNR; | 249 | rtsr = rtc_readl(sa1100_rtc, RTSR); |
209 | rtc_time_to_tm(now, &now_tm); | ||
210 | rtc_next_alarm_time(&alarm_tm, &now_tm, alrm->time); | ||
211 | rtc_tm_to_time(&alarm_tm, &time); | ||
212 | RTAR = time; | ||
213 | if (alrm->enabled) | 250 | if (alrm->enabled) |
214 | RTSR |= RTSR_ALE; | 251 | rtsr |= RTSR_ALE; |
215 | else | 252 | else |
216 | RTSR &= ~RTSR_ALE; | 253 | rtsr &= ~RTSR_ALE; |
254 | rtc_writel(sa1100_rtc, RTSR, rtsr); | ||
217 | 255 | ||
218 | spin_unlock_irq(&sa1100_rtc_lock); | 256 | spin_unlock_irq(&sa1100_rtc->lock); |
219 | 257 | ||
220 | return ret; | 258 | return 0; |
221 | } | 259 | } |
222 | 260 | ||
223 | static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) | 261 | static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) |
224 | { | 262 | { |
225 | seq_printf(seq, "trim/divider\t\t: 0x%08x\n", (u32) RTTR); | 263 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); |
226 | seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", (u32)RTSR); | ||
227 | 264 | ||
265 | seq_printf(seq, "trim/divider\t\t: 0x%08x\n", | ||
266 | rtc_readl(sa1100_rtc, RTTR)); | ||
267 | seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", | ||
268 | rtc_readl(sa1100_rtc, RTSR)); | ||
228 | return 0; | 269 | return 0; |
229 | } | 270 | } |
230 | 271 | ||
@@ -241,7 +282,51 @@ static const struct rtc_class_ops sa1100_rtc_ops = { | |||
241 | 282 | ||
242 | static int sa1100_rtc_probe(struct platform_device *pdev) | 283 | static int sa1100_rtc_probe(struct platform_device *pdev) |
243 | { | 284 | { |
244 | struct rtc_device *rtc; | 285 | struct sa1100_rtc *sa1100_rtc; |
286 | unsigned int rttr; | ||
287 | int ret; | ||
288 | |||
289 | sa1100_rtc = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL); | ||
290 | if (!sa1100_rtc) | ||
291 | return -ENOMEM; | ||
292 | |||
293 | spin_lock_init(&sa1100_rtc->lock); | ||
294 | platform_set_drvdata(pdev, sa1100_rtc); | ||
295 | |||
296 | ret = -ENXIO; | ||
297 | sa1100_rtc->ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
298 | if (!sa1100_rtc->ress) { | ||
299 | dev_err(&pdev->dev, "No I/O memory resource defined\n"); | ||
300 | goto err_ress; | ||
301 | } | ||
302 | |||
303 | sa1100_rtc->irq_1Hz = platform_get_irq(pdev, 0); | ||
304 | if (sa1100_rtc->irq_1Hz < 0) { | ||
305 | dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n"); | ||
306 | goto err_ress; | ||
307 | } | ||
308 | sa1100_rtc->irq_Alrm = platform_get_irq(pdev, 1); | ||
309 | if (sa1100_rtc->irq_Alrm < 0) { | ||
310 | dev_err(&pdev->dev, "No alarm IRQ resource defined\n"); | ||
311 | goto err_ress; | ||
312 | } | ||
313 | |||
314 | ret = -ENOMEM; | ||
315 | sa1100_rtc->base = ioremap(sa1100_rtc->ress->start, | ||
316 | resource_size(sa1100_rtc->ress)); | ||
317 | if (!sa1100_rtc->base) { | ||
318 | dev_err(&pdev->dev, "Unable to map pxa RTC I/O memory\n"); | ||
319 | goto err_map; | ||
320 | } | ||
321 | |||
322 | sa1100_rtc->clk = clk_get(&pdev->dev, NULL); | ||
323 | if (IS_ERR(sa1100_rtc->clk)) { | ||
324 | dev_err(&pdev->dev, "failed to find rtc clock source\n"); | ||
325 | ret = PTR_ERR(sa1100_rtc->clk); | ||
326 | goto err_clk; | ||
327 | } | ||
328 | clk_prepare(sa1100_rtc->clk); | ||
329 | clk_enable(sa1100_rtc->clk); | ||
245 | 330 | ||
246 | /* | 331 | /* |
247 | * According to the manual we should be able to let RTTR be zero | 332 | * According to the manual we should be able to let RTTR be zero |
@@ -250,24 +335,24 @@ static int sa1100_rtc_probe(struct platform_device *pdev) | |||
250 | * If the clock divider is uninitialized then reset it to the | 335 | * If the clock divider is uninitialized then reset it to the |
251 | * default value to get the 1Hz clock. | 336 | * default value to get the 1Hz clock. |
252 | */ | 337 | */ |
253 | if (RTTR == 0) { | 338 | if (rtc_readl(sa1100_rtc, RTTR) == 0) { |
254 | RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); | 339 | rttr = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); |
255 | dev_warn(&pdev->dev, "warning: " | 340 | rtc_writel(sa1100_rtc, RTTR, rttr); |
256 | "initializing default clock divider/trim value\n"); | 341 | dev_warn(&pdev->dev, "warning: initializing default clock" |
342 | " divider/trim value\n"); | ||
257 | /* The current RTC value probably doesn't make sense either */ | 343 | /* The current RTC value probably doesn't make sense either */ |
258 | RCNR = 0; | 344 | rtc_writel(sa1100_rtc, RCNR, 0); |
259 | } | 345 | } |
260 | 346 | ||
261 | device_init_wakeup(&pdev->dev, 1); | 347 | device_init_wakeup(&pdev->dev, 1); |
262 | 348 | ||
263 | rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, | 349 | sa1100_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, |
264 | THIS_MODULE); | 350 | &sa1100_rtc_ops, THIS_MODULE); |
265 | 351 | if (IS_ERR(sa1100_rtc->rtc)) { | |
266 | if (IS_ERR(rtc)) | 352 | dev_err(&pdev->dev, "Failed to register RTC device -> %d\n", |
267 | return PTR_ERR(rtc); | 353 | ret); |
268 | 354 | goto err_rtc_reg; | |
269 | platform_set_drvdata(pdev, rtc); | 355 | } |
270 | |||
271 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. | 356 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. |
272 | * See also the comments in sa1100_rtc_interrupt(). | 357 | * See also the comments in sa1100_rtc_interrupt(). |
273 | * | 358 | * |
@@ -290,33 +375,46 @@ static int sa1100_rtc_probe(struct platform_device *pdev) | |||
290 | * | 375 | * |
291 | * Notice that clearing bit 1 and 0 is accomplished by writting ONES to | 376 | * Notice that clearing bit 1 and 0 is accomplished by writting ONES to |
292 | * the corresponding bits in RTSR. */ | 377 | * the corresponding bits in RTSR. */ |
293 | RTSR = RTSR_AL | RTSR_HZ; | 378 | rtc_writel(sa1100_rtc, RTSR, (RTSR_AL | RTSR_HZ)); |
294 | 379 | ||
295 | return 0; | 380 | return 0; |
381 | |||
382 | err_rtc_reg: | ||
383 | err_clk: | ||
384 | iounmap(sa1100_rtc->base); | ||
385 | err_ress: | ||
386 | err_map: | ||
387 | kfree(sa1100_rtc); | ||
388 | return ret; | ||
296 | } | 389 | } |
297 | 390 | ||
298 | static int sa1100_rtc_remove(struct platform_device *pdev) | 391 | static int sa1100_rtc_remove(struct platform_device *pdev) |
299 | { | 392 | { |
300 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 393 | struct sa1100_rtc *sa1100_rtc = platform_get_drvdata(pdev); |
301 | |||
302 | if (rtc) | ||
303 | rtc_device_unregister(rtc); | ||
304 | 394 | ||
395 | rtc_device_unregister(sa1100_rtc->rtc); | ||
396 | clk_disable(sa1100_rtc->clk); | ||
397 | clk_unprepare(sa1100_rtc->clk); | ||
398 | iounmap(sa1100_rtc->base); | ||
305 | return 0; | 399 | return 0; |
306 | } | 400 | } |
307 | 401 | ||
308 | #ifdef CONFIG_PM | 402 | #ifdef CONFIG_PM |
309 | static int sa1100_rtc_suspend(struct device *dev) | 403 | static int sa1100_rtc_suspend(struct device *dev) |
310 | { | 404 | { |
405 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); | ||
406 | |||
311 | if (device_may_wakeup(dev)) | 407 | if (device_may_wakeup(dev)) |
312 | enable_irq_wake(IRQ_RTCAlrm); | 408 | enable_irq_wake(sa1100_rtc->irq_Alrm); |
313 | return 0; | 409 | return 0; |
314 | } | 410 | } |
315 | 411 | ||
316 | static int sa1100_rtc_resume(struct device *dev) | 412 | static int sa1100_rtc_resume(struct device *dev) |
317 | { | 413 | { |
414 | struct sa1100_rtc *sa1100_rtc = dev_get_drvdata(dev); | ||
415 | |||
318 | if (device_may_wakeup(dev)) | 416 | if (device_may_wakeup(dev)) |
319 | disable_irq_wake(IRQ_RTCAlrm); | 417 | disable_irq_wake(sa1100_rtc->irq_Alrm); |
320 | return 0; | 418 | return 0; |
321 | } | 419 | } |
322 | 420 | ||