xref: /netbsd/sys/arch/next68k/next68k/rtc.c (revision c4a72b64)
1 /*      $NetBSD: rtc.c,v 1.7 2002/09/27 15:36:32 provos Exp $        */
2 /*
3  * Copyright (c) 1998 Darrin Jewell
4  * Copyright (c) 1997 Rolf Grossmann
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Rolf Grossmann.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /* These haven't been tested to see how they interact with NeXTstep's
34  * interpretation of the rtc.
35  */
36 
37 /* Now using this in the kernel.  This should be turned into a device
38  * Darrin B Jewell <jewell@mit.edu>  Tue Jan 27 20:59:25 1998
39  */
40 
41 #include <sys/param.h>
42 #include <sys/cdefs.h>          /* for __P */
43 #include <sys/systm.h>          /* for panic */
44 
45 #include <machine/bus.h>
46 #include <machine/cpu.h>
47 
48 #include <dev/clock_subr.h>
49 
50 #include <next68k/next68k/rtc.h>
51 
52 #include <next68k/dev/clockreg.h>
53 #include <next68k/dev/intiovar.h>
54 
55 /* #define RTC_DEBUG */
56 
57 u_char new_clock;
58 volatile u_int *scr2 = (u_int *)NEXT_P_SCR2; /* will get memory mapped in rtc_init */
59 
60 void
61 rtc_init(void)
62 {
63 	u_char val;
64 
65 	scr2 = (u_int *)IIOV(NEXT_P_SCR2);
66 	val = rtc_read(RTC_STATUS);
67 	new_clock = (val & RTC_NEW_CLOCK) ? 1 : 0;
68 
69 	printf("Looks like a %s clock chip.\n",
70 			(new_clock?
71 					"MCS1850 (new style)":
72 					"MC68HC68T1 (old style)"));
73 
74 #ifdef RTC_DEBUG
75 	rtc_print();
76 #endif
77 }
78 
79 void
80 rtc_print(void)
81 {
82 
83 #define RTC_PRINT(x)	printf("\t%16s= 0x%02x\n",#x, rtc_read(x))
84 
85 	if (new_clock) {
86 		RTC_PRINT(RTC_RAM);
87 		RTC_PRINT(RTC_CNTR0);
88 		RTC_PRINT(RTC_CNTR1);
89 		RTC_PRINT(RTC_CNTR2);
90 		RTC_PRINT(RTC_CNTR3);
91 		RTC_PRINT(RTC_ALARM0);
92 		RTC_PRINT(RTC_ALARM1);
93 		RTC_PRINT(RTC_ALARM2);
94 		RTC_PRINT(RTC_ALARM3);
95 		RTC_PRINT(RTC_STATUS);
96 		RTC_PRINT(RTC_CONTROL);
97 	} else {
98 		RTC_PRINT(RTC_RAM);
99 		RTC_PRINT(RTC_SEC);
100 		RTC_PRINT(RTC_MIN);
101 		RTC_PRINT(RTC_HRS);
102 		RTC_PRINT(RTC_DAY);
103 		RTC_PRINT(RTC_DATE);
104 		RTC_PRINT(RTC_MON);
105 		RTC_PRINT(RTC_YR);
106 		RTC_PRINT(RTC_ALARM_SEC);
107 		RTC_PRINT(RTC_ALARM_MIN);
108 		RTC_PRINT(RTC_ALARM_HR);
109 		RTC_PRINT(RTC_STATUS);
110 		RTC_PRINT(RTC_CONTROL);
111 		RTC_PRINT(RTC_INTRCTL);
112 	}
113 }
114 
115 
116 u_char
117 rtc_read(u_char reg)
118 {
119 	int i;
120 	u_int tmp;
121 	u_char val;
122 
123 	*scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE;
124 	DELAY(1);
125 
126 	val = reg;
127 	for (i=0; i<8; i++) {
128 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
129 		if (val & 0x80)
130 			tmp |= SCR2_RTDATA;
131 
132 		*scr2 = tmp;
133 		DELAY(1);
134 		*scr2 = tmp | SCR2_RTCLK;
135 		DELAY(1);
136 		*scr2 = tmp;
137 		DELAY(1);
138 
139 		val <<= 1;
140 	}
141 
142 	val = 0;			/* should be anyway */
143 	for (i=0; i<8; i++) {
144 		val <<= 1;
145 
146 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
147 
148 		*scr2 = tmp | SCR2_RTCLK;
149 		DELAY(1);
150 		*scr2 = tmp;
151 		DELAY(1);
152 
153 		if (*scr2 & SCR2_RTDATA)
154 			val |= 1;
155 	}
156 
157 	*scr2 &= ~(SCR2_RTDATA|SCR2_RTCLK|SCR2_RTCE);
158 	DELAY(1);
159 
160 	return val;
161 }
162 
163 void
164 rtc_write(u_char reg, u_char v)
165 {
166 	int i;
167 	u_int tmp;
168 	u_char val;
169 
170 	*scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE;
171 	DELAY(1);
172 
173 	val = reg|RTC_WRITE;
174 
175 	for (i=0; i<8; i++) {
176 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
177 		if (val & 0x80)
178 			tmp |= SCR2_RTDATA;
179 
180 		*scr2 = tmp;
181 		DELAY(1);
182 		*scr2 = tmp | SCR2_RTCLK;
183 		DELAY(1);
184 		*scr2 = tmp;
185 		DELAY(1);
186 
187 		val <<= 1;
188 	}
189 
190 	DELAY(1);
191 
192 	for (i=0; i<8; i++) {
193 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
194 		if (v & 0x80)
195 			tmp |= SCR2_RTDATA;
196 
197 		*scr2 = tmp;
198 		DELAY(1);
199 		*scr2 = tmp | SCR2_RTCLK;
200 		DELAY(1);
201 		*scr2 = tmp;
202 		DELAY(1);
203 
204 		v <<= 1;
205 	}
206 
207 	*scr2 &= ~(SCR2_RTDATA|SCR2_RTCLK|SCR2_RTCE);
208 	DELAY(1);
209 }
210 
211 void
212 poweroff(void)
213 {
214 	int reg, t;
215 
216 	if(new_clock) {
217 		reg = RTC_CNTR3;
218 	} else {
219 		reg = RTC_CNTR0;
220 	}
221 
222 	t = rtc_read(reg);	/* seconds */
223 	/* wait for clock to tick */
224 	while(t == rtc_read(reg));
225 
226 	DELAY(850000);	/* hardware bug workaround ? */
227 
228 	if(new_clock) {
229 		reg = RTC_CONTROL;
230 	} else {
231 		reg = RTC_INTRCTL;
232 	}
233 
234 	rtc_write(reg, rtc_read(reg)|(RTC_PDOWN));
235 
236 	printf("....................."); /* @@@ work around some sort of bug. */
237 
238 	panic("Failed to poweroff!");
239 }
240 
241 
242 time_t
243 getsecs(void)
244 {
245 	u_int secs = 0;
246 
247 	if (new_clock) {
248 		secs = rtc_read(RTC_CNTR3) << 24 |
249 				rtc_read(RTC_CNTR2) << 16 |
250 				rtc_read(RTC_CNTR1) << 8	 |
251 				rtc_read(RTC_CNTR0);
252 	} else {
253 		struct clock_ymdhms val;
254 		{
255 			u_char y;
256 			y = FROMBCD(rtc_read(RTC_YR));
257 			if (y >= 69) {
258 				val.dt_year = 1900+y;
259 			} else {
260 				val.dt_year = 2000+y;
261 			}
262 		}
263 		val.dt_mon	= FROMBCD(rtc_read(RTC_MON)&0x1f);
264 		val.dt_day	= FROMBCD(rtc_read(RTC_DATE)&0x3f);
265 		val.dt_wday = FROMBCD(rtc_read(RTC_DAY)&0x7);
266 		{
267 			u_char h;
268 			h = rtc_read(RTC_HRS);
269 			if (h & 0x80) {					/* time is am/pm format */
270 				val.dt_hour = FROMBCD(h&0x1f);
271 				if (h & 0x20) { /* pm */
272 					if (val.dt_hour < 12) val.dt_hour += 12;
273 				} else {  /* am */
274 					if (val.dt_hour == 12) val.dt_hour = 0;
275 				}
276 			} else {								/* time is 24 hour format */
277 				val.dt_hour = FROMBCD(h & 0x3f);
278 			}
279 		}
280 		val.dt_min	= FROMBCD(rtc_read(RTC_MIN)&0x7f);
281 		val.dt_sec	= FROMBCD(rtc_read(RTC_SEC)&0x7f);
282 
283 		secs = clock_ymdhms_to_secs(&val);
284 	}
285 
286 	return secs;
287 }
288 
289 void
290 setsecs(time_t secs)
291 {
292 
293 	/* Stop the clock */
294 	rtc_write(RTC_CONTROL,rtc_read(RTC_CONTROL) & ~RTC_START);
295 
296 #ifdef RTC_DEBUG
297 	printf("Setting RTC to 0x%08x.  Regs before:\n",secs);
298 	rtc_print();
299 #endif
300 
301 	if (new_clock) {
302 		rtc_write(RTC_CNTR3, (secs << 24) & 0xff);
303 		rtc_write(RTC_CNTR2, (secs << 16) & 0xff);
304 		rtc_write(RTC_CNTR1, (secs <<	 8) & 0xff);
305 		rtc_write(RTC_CNTR0, (secs) & 0xff);
306 
307 	} else {
308 		struct clock_ymdhms val;
309 		clock_secs_to_ymdhms(secs,&val);
310 		rtc_write(RTC_SEC,TOBCD(val.dt_sec));
311 		rtc_write(RTC_MIN,TOBCD(val.dt_min));
312 		{
313 			u_char h;
314 			h = rtc_read(RTC_HRS);
315 			if (h & 0x80) {						/* time is am/pm format */
316 				if (val.dt_hour == 0) {
317 					rtc_write(RTC_HRS,TOBCD(12)|0x80);
318 				} else if (val.dt_hour < 12) {	/* am */
319 					rtc_write(RTC_HRS,TOBCD(val.dt_hour)|0x80);
320 				} else if (val.dt_hour == 12) {
321 						rtc_write(RTC_HRS,TOBCD(12)|0x80|0x20);
322 				} else {								/* pm */
323 					rtc_write(RTC_HRS,TOBCD(val.dt_hour-12)|0x80|0x20);
324 				}
325 			} else {									/* time is 24 hour format */
326 				rtc_write(RTC_HRS,TOBCD(val.dt_hour));
327 			}
328 		}
329 		rtc_write(RTC_DAY,TOBCD(val.dt_wday));
330 		rtc_write(RTC_DATE,TOBCD(val.dt_day));
331 		rtc_write(RTC_MON,TOBCD(val.dt_mon));
332 		rtc_write(RTC_YR,TOBCD(val.dt_year%100));
333 	}
334 
335 #ifdef RTC_DEBUG
336 	printf("Regs after:\n",secs);
337 	rtc_print();
338 #endif
339 
340 	/* restart the clock */
341 	rtc_write(RTC_CONTROL,rtc_read(RTC_CONTROL) | RTC_START);
342 
343 }
344