diff options
author | Haojian Zhuang <haojian.zhuang@marvell.com> | 2012-02-20 22:51:13 -0500 |
---|---|---|
committer | Haojian Zhuang <haojian.zhuang@marvell.com> | 2012-02-27 21:07:50 -0500 |
commit | 3888c09074db2ca561c74571dcbd777949a856b8 (patch) | |
tree | 5aa1919517a274176dd13b4030141eba9df68a3c /drivers/rtc | |
parent | 1d8c38c3d1b48eeb9cfaa42a8be13a1423569eb2 (diff) |
rtc: sa1100: declare irq in resource
Avoid to hard coded irq in rtc-sa1100 driver since we could share
it among arch-sa1100/arch-pxa/arch-mmp.
We still keep hard coded register address since the requirement is
enabling both rtc-sa1100 and rtc-pxa driver. The register addresses
are conflict since they're only two wrappers on the same rtc device.
Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 4 | ||||
-rw-r--r-- | drivers/rtc/rtc-sa1100.c | 98 |
2 files changed, 69 insertions, 33 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-sa1100.c b/drivers/rtc/rtc-sa1100.c index 91d58bdc7f88..0a36c7ee3b40 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c | |||
@@ -27,6 +27,7 @@ | |||
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/slab.h> | ||
30 | #include <linux/string.h> | 31 | #include <linux/string.h> |
31 | #include <linux/pm.h> | 32 | #include <linux/pm.h> |
32 | #include <linux/bitops.h> | 33 | #include <linux/bitops.h> |
@@ -34,24 +35,29 @@ | |||
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 | #if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) |
38 | #include <mach/regs-rtc.h> | 39 | #include <mach/regs-rtc.h> |
39 | #endif | 40 | #endif |
40 | 41 | ||
41 | #define RTC_DEF_DIVIDER (32768 - 1) | 42 | #define RTC_DEF_DIVIDER (32768 - 1) |
42 | #define RTC_DEF_TRIM 0 | 43 | #define RTC_DEF_TRIM 0 |
44 | #define RTC_FREQ 1024 | ||
43 | 45 | ||
44 | static const unsigned long RTC_FREQ = 1024; | 46 | struct sa1100_rtc { |
45 | static DEFINE_SPINLOCK(sa1100_rtc_lock); | 47 | spinlock_t lock; |
48 | int irq_1hz; | ||
49 | int irq_alarm; | ||
50 | struct rtc_device *rtc; | ||
51 | }; | ||
46 | 52 | ||
47 | static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | 53 | static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) |
48 | { | 54 | { |
49 | struct platform_device *pdev = to_platform_device(dev_id); | 55 | struct sa1100_rtc *info = dev_get_drvdata(dev_id); |
50 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 56 | struct rtc_device *rtc = info->rtc; |
51 | unsigned int rtsr; | 57 | unsigned int rtsr; |
52 | unsigned long events = 0; | 58 | unsigned long events = 0; |
53 | 59 | ||
54 | spin_lock(&sa1100_rtc_lock); | 60 | spin_lock(&info->lock); |
55 | 61 | ||
56 | rtsr = RTSR; | 62 | rtsr = RTSR; |
57 | /* clear interrupt sources */ | 63 | /* clear interrupt sources */ |
@@ -87,27 +93,27 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) | |||
87 | 93 | ||
88 | rtc_update_irq(rtc, 1, events); | 94 | rtc_update_irq(rtc, 1, events); |
89 | 95 | ||
90 | spin_unlock(&sa1100_rtc_lock); | 96 | spin_unlock(&info->lock); |
91 | 97 | ||
92 | return IRQ_HANDLED; | 98 | return IRQ_HANDLED; |
93 | } | 99 | } |
94 | 100 | ||
95 | static int sa1100_rtc_open(struct device *dev) | 101 | static int sa1100_rtc_open(struct device *dev) |
96 | { | 102 | { |
103 | struct sa1100_rtc *info = dev_get_drvdata(dev); | ||
104 | struct rtc_device *rtc = info->rtc; | ||
97 | int ret; | 105 | int ret; |
98 | struct platform_device *plat_dev = to_platform_device(dev); | ||
99 | struct rtc_device *rtc = platform_get_drvdata(plat_dev); | ||
100 | 106 | ||
101 | ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, | 107 | ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, IRQF_DISABLED, |
102 | "rtc 1Hz", dev); | 108 | "rtc 1Hz", dev); |
103 | if (ret) { | 109 | if (ret) { |
104 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); | 110 | dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz); |
105 | goto fail_ui; | 111 | goto fail_ui; |
106 | } | 112 | } |
107 | ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, | 113 | ret = request_irq(info->irq_alarm, sa1100_rtc_interrupt, IRQF_DISABLED, |
108 | "rtc Alrm", dev); | 114 | "rtc Alrm", dev); |
109 | if (ret) { | 115 | if (ret) { |
110 | dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); | 116 | dev_err(dev, "IRQ %d already in use.\n", info->irq_alarm); |
111 | goto fail_ai; | 117 | goto fail_ai; |
112 | } | 118 | } |
113 | rtc->max_user_freq = RTC_FREQ; | 119 | rtc->max_user_freq = RTC_FREQ; |
@@ -116,29 +122,33 @@ static int sa1100_rtc_open(struct device *dev) | |||
116 | return 0; | 122 | return 0; |
117 | 123 | ||
118 | fail_ai: | 124 | fail_ai: |
119 | free_irq(IRQ_RTC1Hz, dev); | 125 | free_irq(info->irq_1hz, dev); |
120 | fail_ui: | 126 | fail_ui: |
121 | return ret; | 127 | return ret; |
122 | } | 128 | } |
123 | 129 | ||
124 | static void sa1100_rtc_release(struct device *dev) | 130 | static void sa1100_rtc_release(struct device *dev) |
125 | { | 131 | { |
126 | spin_lock_irq(&sa1100_rtc_lock); | 132 | struct sa1100_rtc *info = dev_get_drvdata(dev); |
133 | |||
134 | spin_lock_irq(&info->lock); | ||
127 | RTSR = 0; | 135 | RTSR = 0; |
128 | spin_unlock_irq(&sa1100_rtc_lock); | 136 | spin_unlock_irq(&info->lock); |
129 | 137 | ||
130 | free_irq(IRQ_RTCAlrm, dev); | 138 | free_irq(info->irq_alarm, dev); |
131 | free_irq(IRQ_RTC1Hz, dev); | 139 | free_irq(info->irq_1hz, dev); |
132 | } | 140 | } |
133 | 141 | ||
134 | static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) | 142 | static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
135 | { | 143 | { |
136 | spin_lock_irq(&sa1100_rtc_lock); | 144 | struct sa1100_rtc *info = dev_get_drvdata(dev); |
145 | |||
146 | spin_lock_irq(&info->lock); | ||
137 | if (enabled) | 147 | if (enabled) |
138 | RTSR |= RTSR_ALE; | 148 | RTSR |= RTSR_ALE; |
139 | else | 149 | else |
140 | RTSR &= ~RTSR_ALE; | 150 | RTSR &= ~RTSR_ALE; |
141 | spin_unlock_irq(&sa1100_rtc_lock); | 151 | spin_unlock_irq(&info->lock); |
142 | return 0; | 152 | return 0; |
143 | } | 153 | } |
144 | 154 | ||
@@ -171,10 +181,11 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
171 | 181 | ||
172 | static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 182 | static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
173 | { | 183 | { |
184 | struct sa1100_rtc *info = dev_get_drvdata(dev); | ||
174 | unsigned long time; | 185 | unsigned long time; |
175 | int ret; | 186 | int ret; |
176 | 187 | ||
177 | spin_lock_irq(&sa1100_rtc_lock); | 188 | spin_lock_irq(&info->lock); |
178 | ret = rtc_tm_to_time(&alrm->time, &time); | 189 | ret = rtc_tm_to_time(&alrm->time, &time); |
179 | if (ret != 0) | 190 | if (ret != 0) |
180 | goto out; | 191 | goto out; |
@@ -185,7 +196,7 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
185 | else | 196 | else |
186 | RTSR &= ~RTSR_ALE; | 197 | RTSR &= ~RTSR_ALE; |
187 | out: | 198 | out: |
188 | spin_unlock_irq(&sa1100_rtc_lock); | 199 | spin_unlock_irq(&info->lock); |
189 | 200 | ||
190 | return ret; | 201 | return ret; |
191 | } | 202 | } |
@@ -212,6 +223,21 @@ static const struct rtc_class_ops sa1100_rtc_ops = { | |||
212 | static int sa1100_rtc_probe(struct platform_device *pdev) | 223 | static int sa1100_rtc_probe(struct platform_device *pdev) |
213 | { | 224 | { |
214 | struct rtc_device *rtc; | 225 | struct rtc_device *rtc; |
226 | struct sa1100_rtc *info; | ||
227 | int irq_1hz, irq_alarm, ret = 0; | ||
228 | |||
229 | irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); | ||
230 | irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); | ||
231 | if (irq_1hz < 0 || irq_alarm < 0) | ||
232 | return -ENODEV; | ||
233 | |||
234 | info = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL); | ||
235 | if (!info) | ||
236 | return -ENOMEM; | ||
237 | info->irq_1hz = irq_1hz; | ||
238 | info->irq_alarm = irq_alarm; | ||
239 | spin_lock_init(&info->lock); | ||
240 | platform_set_drvdata(pdev, info); | ||
215 | 241 | ||
216 | /* | 242 | /* |
217 | * According to the manual we should be able to let RTTR be zero | 243 | * According to the manual we should be able to let RTTR be zero |
@@ -233,10 +259,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev) | |||
233 | rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, | 259 | rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, |
234 | THIS_MODULE); | 260 | THIS_MODULE); |
235 | 261 | ||
236 | if (IS_ERR(rtc)) | 262 | if (IS_ERR(rtc)) { |
237 | return PTR_ERR(rtc); | 263 | ret = PTR_ERR(rtc); |
238 | 264 | goto err_dev; | |
239 | platform_set_drvdata(pdev, rtc); | 265 | } |
266 | info->rtc = rtc; | ||
240 | 267 | ||
241 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. | 268 | /* Fix for a nasty initialization problem the in SA11xx RTSR register. |
242 | * See also the comments in sa1100_rtc_interrupt(). | 269 | * See also the comments in sa1100_rtc_interrupt(). |
@@ -263,14 +290,21 @@ static int sa1100_rtc_probe(struct platform_device *pdev) | |||
263 | RTSR = RTSR_AL | RTSR_HZ; | 290 | RTSR = RTSR_AL | RTSR_HZ; |
264 | 291 | ||
265 | return 0; | 292 | return 0; |
293 | err_dev: | ||
294 | platform_set_drvdata(pdev, NULL); | ||
295 | kfree(info); | ||
296 | return ret; | ||
266 | } | 297 | } |
267 | 298 | ||
268 | static int sa1100_rtc_remove(struct platform_device *pdev) | 299 | static int sa1100_rtc_remove(struct platform_device *pdev) |
269 | { | 300 | { |
270 | struct rtc_device *rtc = platform_get_drvdata(pdev); | 301 | struct sa1100_rtc *info = platform_get_drvdata(pdev); |
271 | 302 | ||
272 | if (rtc) | 303 | if (info) { |
273 | rtc_device_unregister(rtc); | 304 | rtc_device_unregister(info->rtc); |
305 | platform_set_drvdata(pdev, NULL); | ||
306 | kfree(info); | ||
307 | } | ||
274 | 308 | ||
275 | return 0; | 309 | return 0; |
276 | } | 310 | } |
@@ -278,15 +312,17 @@ static int sa1100_rtc_remove(struct platform_device *pdev) | |||
278 | #ifdef CONFIG_PM | 312 | #ifdef CONFIG_PM |
279 | static int sa1100_rtc_suspend(struct device *dev) | 313 | static int sa1100_rtc_suspend(struct device *dev) |
280 | { | 314 | { |
315 | struct sa1100_rtc *info = dev_get_drvdata(dev); | ||
281 | if (device_may_wakeup(dev)) | 316 | if (device_may_wakeup(dev)) |
282 | enable_irq_wake(IRQ_RTCAlrm); | 317 | enable_irq_wake(info->irq_alarm); |
283 | return 0; | 318 | return 0; |
284 | } | 319 | } |
285 | 320 | ||
286 | static int sa1100_rtc_resume(struct device *dev) | 321 | static int sa1100_rtc_resume(struct device *dev) |
287 | { | 322 | { |
323 | struct sa1100_rtc *info = dev_get_drvdata(dev); | ||
288 | if (device_may_wakeup(dev)) | 324 | if (device_may_wakeup(dev)) |
289 | disable_irq_wake(IRQ_RTCAlrm); | 325 | disable_irq_wake(info->irq_alarm); |
290 | return 0; | 326 | return 0; |
291 | } | 327 | } |
292 | 328 | ||