aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300/kernel/rtc.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-02-08 07:19:31 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:30 -0500
commitb920de1b77b72ca9432ac3f97edb26541e65e5dd (patch)
tree40fa9be1470e929c47927dea7eddf184c0204229 /arch/mn10300/kernel/rtc.c
parentef3d534754f31fed9c3b976fee1ece1b3bc38282 (diff)
mn10300: add the MN10300/AM33 architecture to the kernel
Add architecture support for the MN10300/AM33 CPUs produced by MEI to the kernel. This patch also adds board support for the ASB2303 with the ASB2308 daughter board, and the ASB2305. The only processor supported is the MN103E010, which is an AM33v2 core plus on-chip devices. [akpm@linux-foundation.org: nuke cvs control strings] Signed-off-by: Masakazu Urade <urade.masakazu@jp.panasonic.com> Signed-off-by: Koichi Yasutake <yasutake.koichi@jp.panasonic.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/mn10300/kernel/rtc.c')
-rw-r--r--arch/mn10300/kernel/rtc.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/arch/mn10300/kernel/rtc.c b/arch/mn10300/kernel/rtc.c
new file mode 100644
index 000000000000..042f792d8430
--- /dev/null
+++ b/arch/mn10300/kernel/rtc.c
@@ -0,0 +1,173 @@
1/* MN10300 RTC management
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/mc146818rtc.h>
15#include <linux/bcd.h>
16#include <linux/timex.h>
17#include <asm/rtc-regs.h>
18#include <asm/rtc.h>
19
20DEFINE_SPINLOCK(rtc_lock);
21EXPORT_SYMBOL(rtc_lock);
22
23/* last time the RTC got updated */
24static long last_rtc_update;
25
26/* time for RTC to update itself in ioclks */
27static unsigned long mn10300_rtc_update_period;
28
29/*
30 * read the current RTC time
31 */
32unsigned long __init get_initial_rtc_time(void)
33{
34 struct rtc_time tm;
35
36 get_rtc_time(&tm);
37
38 return mktime(tm.tm_year, tm.tm_mon, tm.tm_mday,
39 tm.tm_hour, tm.tm_min, tm.tm_sec);
40}
41
42/*
43 * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500
44 * ms after the second nowtime has started, because when nowtime is written
45 * into the registers of the CMOS clock, it will jump to the next second
46 * precisely 500 ms later. Check the Motorola MC146818A or Dallas DS12887 data
47 * sheet for details.
48 *
49 * BUG: This routine does not handle hour overflow properly; it just
50 * sets the minutes. Usually you'll only notice that after reboot!
51 */
52static int set_rtc_mmss(unsigned long nowtime)
53{
54 unsigned char save_control, save_freq_select;
55 int retval = 0;
56 int real_seconds, real_minutes, cmos_minutes;
57
58 /* gets recalled with irq locally disabled */
59 spin_lock(&rtc_lock);
60 save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being
61 * set */
62 CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);
63
64 save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset
65 * prescaler */
66 CMOS_WRITE(save_freq_select | RTC_DIV_RESET2, RTC_FREQ_SELECT);
67
68 cmos_minutes = CMOS_READ(RTC_MINUTES);
69 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
70 BCD_TO_BIN(cmos_minutes);
71
72 /*
73 * since we're only adjusting minutes and seconds,
74 * don't interfere with hour overflow. This avoids
75 * messing with unknown time zones but requires your
76 * RTC not to be off by more than 15 minutes
77 */
78 real_seconds = nowtime % 60;
79 real_minutes = nowtime / 60;
80 if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
81 /* correct for half hour time zone */
82 real_minutes += 30;
83 real_minutes %= 60;
84
85 if (abs(real_minutes - cmos_minutes) < 30) {
86 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
87 BIN_TO_BCD(real_seconds);
88 BIN_TO_BCD(real_minutes);
89 }
90 CMOS_WRITE(real_seconds, RTC_SECONDS);
91 CMOS_WRITE(real_minutes, RTC_MINUTES);
92 } else {
93 printk(KERN_WARNING
94 "set_rtc_mmss: can't update from %d to %d\n",
95 cmos_minutes, real_minutes);
96 retval = -1;
97 }
98
99 /* The following flags have to be released exactly in this order,
100 * otherwise the DS12887 (popular MC146818A clone with integrated
101 * battery and quartz) will not reset the oscillator and will not
102 * update precisely 500 ms later. You won't find this mentioned in
103 * the Dallas Semiconductor data sheets, but who believes data
104 * sheets anyway ... -- Markus Kuhn
105 */
106 CMOS_WRITE(save_control, RTC_CONTROL);
107 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
108 spin_unlock(&rtc_lock);
109
110 return retval;
111}
112
113void check_rtc_time(void)
114{
115 /* the RTC clock just finished ticking over again this second
116 * - if we have an externally synchronized Linux clock, then update
117 * RTC clock accordingly every ~11 minutes. set_rtc_mmss() has to be
118 * called as close as possible to 500 ms before the new second starts.
119 */
120 if ((time_status & STA_UNSYNC) == 0 &&
121 xtime.tv_sec > last_rtc_update + 660 &&
122 xtime.tv_nsec / 1000 >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
123 xtime.tv_nsec / 1000 <= 500000 + ((unsigned) TICK_SIZE) / 2
124 ) {
125 if (set_rtc_mmss(xtime.tv_sec) == 0)
126 last_rtc_update = xtime.tv_sec;
127 else
128 /* do it again in 60s */
129 last_rtc_update = xtime.tv_sec - 600;
130 }
131}
132
133/*
134 * calibrate the TSC clock against the RTC
135 */
136void __init calibrate_clock(void)
137{
138 unsigned long count0, counth, count1;
139 unsigned char status;
140
141 /* make sure the RTC is running and is set to operate in 24hr mode */
142 status = RTSRC;
143 RTCRB |= RTCRB_SET;
144 RTCRB |= RTCRB_TM_24HR;
145 RTCRA |= RTCRA_DVR;
146 RTCRA &= ~RTCRA_DVR;
147 RTCRB &= ~RTCRB_SET;
148
149 /* work out the clock speed by counting clock cycles between ends of
150 * the RTC update cycle - track the RTC through one complete update
151 * cycle (1 second)
152 */
153 startup_timestamp_counter();
154
155 while (!(RTCRA & RTCRA_UIP)) {}
156 while ((RTCRA & RTCRA_UIP)) {}
157
158 count0 = TMTSCBC;
159
160 while (!(RTCRA & RTCRA_UIP)) {}
161
162 counth = TMTSCBC;
163
164 while ((RTCRA & RTCRA_UIP)) {}
165
166 count1 = TMTSCBC;
167
168 shutdown_timestamp_counter();
169
170 MN10300_TSCCLK = count0 - count1; /* the timers count down */
171 mn10300_rtc_update_period = counth - count1;
172 MN10300_TSC_PER_HZ = MN10300_TSCCLK / HZ;
173}