1 Index: linux-2.6.15gum/drivers/char/sa1100-rtc.c
2 ===================================================================
4 +++ linux-2.6.15gum/drivers/char/sa1100-rtc.c
7 + * Real Time Clock interface for Linux on StrongARM SA1100
9 + * Copyright (c) 2000 Nils Faerber
11 + * Based on rtc.c by Paul Gortmaker
12 + * Date/time conversion routines taken from arch/arm/kernel/time.c
13 + * by Linus Torvalds and Russel King
14 + * and the GNU C Library
15 + * ( ... I love the GPL ... just take what you need! ;)
17 + * This program is free software; you can redistribute it and/or
18 + * modify it under the terms of the GNU General Public License
19 + * as published by the Free Software Foundation; either version
20 + * 2 of the License, or (at your option) any later version.
22 + * 1.00 2001-06-08 Nicolas Pitre <nico@cam.org>
23 + * - added periodic timer capability using OSMR1
24 + * - flag compatibility with other RTC chips
25 + * - permission checks for ioctls
26 + * - major cleanup, partial rewrite
28 + * 0.03 2001-03-07 CIH <cih@coventive.com>
29 + * - Modify the bug setups RTC clock.
31 + * 0.02 2001-02-27 Nils Faerber <nils@@kernelconcepts.de>
32 + * - removed mktime(), added alarm irq clear
34 + * 0.01 2000-10-01 Nils Faerber <nils@@kernelconcepts.de>
38 +#include <linux/module.h>
39 +#include <linux/fs.h>
40 +#include <linux/miscdevice.h>
41 +#include <linux/string.h>
42 +#include <linux/init.h>
43 +#include <linux/poll.h>
44 +#include <linux/proc_fs.h>
45 +#include <linux/interrupt.h>
46 +#include <linux/rtc.h>
48 +#ifdef CONFIG_ARCH_PXA
49 +#include <asm/arch/pxa-regs.h>
52 +#include <asm/bitops.h>
53 +#include <asm/hardware.h>
57 +#define TIMER_FREQ 3686400
59 +#define RTC_DEF_DIVIDER 32768 - 1
60 +#define RTC_DEF_TRIM 0
62 +/* Those are the bits from a classic RTC we want to mimic */
63 +#define RTC_IRQF 0x80 /* any of the following 3 is active */
68 +static unsigned long rtc_freq = 1024;
69 +static struct rtc_time rtc_alarm = {
78 +extern spinlock_t rtc_lock;
80 +static int rtc_update_alarm(struct rtc_time *alrm)
82 + struct rtc_time alarm_tm, now_tm;
83 + unsigned long now, time;
86 + printk("Updating alarm\n");
89 + rtc_time_to_tm(now, &now_tm);
90 + rtc_next_alarm_time(&alarm_tm, &now_tm, alrm);
91 + ret = rtc_tm_to_time(&alarm_tm, &time);
95 + RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
97 + } while (now != RCNR);
98 + printk("set RTAR to %lx, now is %lx\n", time, now);
103 +static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
106 + unsigned long events = 0;
108 + spin_lock(&rtc_lock);
111 + /* clear interrupt sources */
113 + RTSR = (RTSR_AL|RTSR_HZ) & (rtsr >> 2);
115 + printk(KERN_CRIT "rtc_interrupt: rtsr = %x\n", rtsr);
117 + /* clear alarm interrupt if it has occurred */
118 + if (rtsr & RTSR_AL) {
119 + printk(KERN_CRIT "ALARM INTRRUPT\n");
122 + RTSR = rtsr & (RTSR_ALE|RTSR_HZE);
124 + /* update irq data & counter */
125 + if (rtsr & RTSR_AL)
126 + events |= (RTC_AF|RTC_IRQF);
127 + if (rtsr & RTSR_HZ)
128 + events |= (RTC_UF|RTC_IRQF);
130 + rtc_update(1, events);
132 + if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
133 + rtc_update_alarm(&rtc_alarm);
135 + spin_unlock(&rtc_lock);
137 + return IRQ_HANDLED;
141 +static int sa1100_rtc_open(void)
145 + ret = request_irq(IRQ_RTC1Hz, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL);
147 + printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz);
150 + ret = request_irq(IRQ_RTCAlrm, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL);
152 + printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm);
158 + free_irq(IRQ_RTC1Hz, NULL);
163 +static void sa1100_rtc_release(void)
165 + spin_lock_irq (&rtc_lock);
169 + spin_unlock_irq (&rtc_lock);
171 + free_irq(IRQ_RTCAlrm, NULL);
172 + free_irq(IRQ_RTC1Hz, NULL);
175 +static int sa1100_rtc_ioctl(unsigned int cmd, unsigned long arg)
179 + spin_lock_irq(&rtc_lock);
181 + spin_unlock_irq(&rtc_lock);
184 + spin_lock_irq(&rtc_lock);
186 + spin_unlock_irq(&rtc_lock);
189 + spin_lock_irq(&rtc_lock);
191 + spin_unlock_irq(&rtc_lock);
194 + spin_lock_irq(&rtc_lock);
196 + spin_unlock_irq(&rtc_lock);
202 +static void sa1100_rtc_read_time(struct rtc_time *tm)
204 + rtc_time_to_tm(RCNR, tm);
207 +static int sa1100_rtc_set_time(struct rtc_time *tm)
209 + unsigned long time;
212 + ret = rtc_tm_to_time(tm, &time);
218 +static void sa1100_rtc_read_alarm(struct rtc_wkalrm *alrm)
220 + memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
221 + alrm->pending = RTSR & RTSR_AL ? 1 : 0;
224 +static int sa1100_rtc_set_alarm(struct rtc_wkalrm *alrm)
228 + printk("sa1100_rtc_set_alarm\n");
230 + spin_lock_irq(&rtc_lock);
231 + ret = rtc_update_alarm(&alrm->time);
233 + memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
236 + enable_irq_wake(IRQ_RTCAlrm);
238 + disable_irq_wake(IRQ_RTCAlrm);
240 + spin_unlock_irq(&rtc_lock);
245 +static int sa1100_rtc_proc(char *buf)
249 + p += sprintf(p, "trim/divider\t: 0x%08x\n", RTTR);
250 + p += sprintf(p, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" );
251 + p += sprintf(p, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no");
252 + p += sprintf(p, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no");
253 + p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq);
258 +static struct rtc_ops sa1100_rtc_ops = {
259 + .owner = THIS_MODULE,
260 + .open = sa1100_rtc_open,
261 + .release = sa1100_rtc_release,
262 + .ioctl = sa1100_rtc_ioctl,
264 + .read_time = sa1100_rtc_read_time,
265 + .set_time = sa1100_rtc_set_time,
266 + .read_alarm = sa1100_rtc_read_alarm,
267 + .set_alarm = sa1100_rtc_set_alarm,
268 + .proc = sa1100_rtc_proc,
271 +static int __init rtc_init(void)
274 + * According to the manual we should be able to let RTTR be zero
275 + * and then a default diviser for a 32.768KHz clock is used.
276 + * Apparently this doesn't work, at least for my SA1110 rev 5.
277 + * If the clock divider is uninitialized then reset it to the
278 + * default value to get the 1Hz clock.
281 + RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
282 + printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n");
283 + /* The current RTC value probably doesn't make sense either */
287 + register_rtc(&sa1100_rtc_ops);
292 +static void __exit rtc_exit(void)
294 + unregister_rtc(&sa1100_rtc_ops);
297 +module_init(rtc_init);
298 +module_exit(rtc_exit);
300 +MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>");
301 +MODULE_DESCRIPTION("SA1100 Realtime Clock Driver (RTC)");
302 +MODULE_LICENSE("GPL"); /* so says the header */
303 Index: linux-2.6.15gum/drivers/char/Makefile
304 ===================================================================
305 --- linux-2.6.15gum.orig/drivers/char/Makefile
306 +++ linux-2.6.15gum/drivers/char/Makefile
307 @@ -60,6 +60,7 @@ obj-$(CONFIG_RTC) += rtc.o
308 obj-$(CONFIG_HPET) += hpet.o
309 obj-$(CONFIG_GEN_RTC) += genrtc.o
310 obj-$(CONFIG_EFI_RTC) += efirtc.o
311 +obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o
312 obj-$(CONFIG_SGI_DS1286) += ds1286.o
313 obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
314 obj-$(CONFIG_DS1302) += ds1302.o
315 Index: linux-2.6.15gum/drivers/char/Kconfig
316 ===================================================================
317 --- linux-2.6.15gum.orig/drivers/char/Kconfig
318 +++ linux-2.6.15gum/drivers/char/Kconfig
319 @@ -790,6 +790,10 @@ config COBALT_LCD
320 This option enables support for the LCD display and buttons found
321 on Cobalt systems through a misc device.
324 + tristate "SA1100/PXA2xx Real Time Clock"
325 + depends on ARCH_SA1100 || ARCH_PXA
328 tristate "Double Talk PC internal speech card support"