xref: /netbsd-src/sys/arch/next68k/next68k/rtc.c (revision d37a996a49db27ca1b1e656cc3e261bfe3295a71)
1 /*      $NetBSD: rtc.c,v 1.8 2003/07/15 02:59:33 lukem 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/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.8 2003/07/15 02:59:33 lukem Exp $");
43 
44 #include <sys/param.h>
45 #include <sys/cdefs.h>          /* for __P */
46 #include <sys/systm.h>          /* for panic */
47 
48 #include <machine/bus.h>
49 #include <machine/cpu.h>
50 
51 #include <dev/clock_subr.h>
52 
53 #include <next68k/next68k/rtc.h>
54 
55 #include <next68k/dev/clockreg.h>
56 #include <next68k/dev/intiovar.h>
57 
58 /* #define RTC_DEBUG */
59 
60 u_char new_clock;
61 volatile u_int *scr2 = (u_int *)NEXT_P_SCR2; /* will get memory mapped in rtc_init */
62 
63 void
64 rtc_init(void)
65 {
66 	u_char val;
67 
68 	scr2 = (u_int *)IIOV(NEXT_P_SCR2);
69 	val = rtc_read(RTC_STATUS);
70 	new_clock = (val & RTC_NEW_CLOCK) ? 1 : 0;
71 
72 	printf("Looks like a %s clock chip.\n",
73 			(new_clock?
74 					"MCS1850 (new style)":
75 					"MC68HC68T1 (old style)"));
76 
77 #ifdef RTC_DEBUG
78 	rtc_print();
79 #endif
80 }
81 
82 void
83 rtc_print(void)
84 {
85 
86 #define RTC_PRINT(x)	printf("\t%16s= 0x%02x\n",#x, rtc_read(x))
87 
88 	if (new_clock) {
89 		RTC_PRINT(RTC_RAM);
90 		RTC_PRINT(RTC_CNTR0);
91 		RTC_PRINT(RTC_CNTR1);
92 		RTC_PRINT(RTC_CNTR2);
93 		RTC_PRINT(RTC_CNTR3);
94 		RTC_PRINT(RTC_ALARM0);
95 		RTC_PRINT(RTC_ALARM1);
96 		RTC_PRINT(RTC_ALARM2);
97 		RTC_PRINT(RTC_ALARM3);
98 		RTC_PRINT(RTC_STATUS);
99 		RTC_PRINT(RTC_CONTROL);
100 	} else {
101 		RTC_PRINT(RTC_RAM);
102 		RTC_PRINT(RTC_SEC);
103 		RTC_PRINT(RTC_MIN);
104 		RTC_PRINT(RTC_HRS);
105 		RTC_PRINT(RTC_DAY);
106 		RTC_PRINT(RTC_DATE);
107 		RTC_PRINT(RTC_MON);
108 		RTC_PRINT(RTC_YR);
109 		RTC_PRINT(RTC_ALARM_SEC);
110 		RTC_PRINT(RTC_ALARM_MIN);
111 		RTC_PRINT(RTC_ALARM_HR);
112 		RTC_PRINT(RTC_STATUS);
113 		RTC_PRINT(RTC_CONTROL);
114 		RTC_PRINT(RTC_INTRCTL);
115 	}
116 }
117 
118 
119 u_char
120 rtc_read(u_char reg)
121 {
122 	int i;
123 	u_int tmp;
124 	u_char val;
125 
126 	*scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE;
127 	DELAY(1);
128 
129 	val = reg;
130 	for (i=0; i<8; i++) {
131 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
132 		if (val & 0x80)
133 			tmp |= SCR2_RTDATA;
134 
135 		*scr2 = tmp;
136 		DELAY(1);
137 		*scr2 = tmp | SCR2_RTCLK;
138 		DELAY(1);
139 		*scr2 = tmp;
140 		DELAY(1);
141 
142 		val <<= 1;
143 	}
144 
145 	val = 0;			/* should be anyway */
146 	for (i=0; i<8; i++) {
147 		val <<= 1;
148 
149 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
150 
151 		*scr2 = tmp | SCR2_RTCLK;
152 		DELAY(1);
153 		*scr2 = tmp;
154 		DELAY(1);
155 
156 		if (*scr2 & SCR2_RTDATA)
157 			val |= 1;
158 	}
159 
160 	*scr2 &= ~(SCR2_RTDATA|SCR2_RTCLK|SCR2_RTCE);
161 	DELAY(1);
162 
163 	return val;
164 }
165 
166 void
167 rtc_write(u_char reg, u_char v)
168 {
169 	int i;
170 	u_int tmp;
171 	u_char val;
172 
173 	*scr2 = (*scr2 & ~(SCR2_RTDATA | SCR2_RTCLK)) | SCR2_RTCE;
174 	DELAY(1);
175 
176 	val = reg|RTC_WRITE;
177 
178 	for (i=0; i<8; i++) {
179 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
180 		if (val & 0x80)
181 			tmp |= SCR2_RTDATA;
182 
183 		*scr2 = tmp;
184 		DELAY(1);
185 		*scr2 = tmp | SCR2_RTCLK;
186 		DELAY(1);
187 		*scr2 = tmp;
188 		DELAY(1);
189 
190 		val <<= 1;
191 	}
192 
193 	DELAY(1);
194 
195 	for (i=0; i<8; i++) {
196 		tmp = *scr2 & ~(SCR2_RTDATA | SCR2_RTCLK);
197 		if (v & 0x80)
198 			tmp |= SCR2_RTDATA;
199 
200 		*scr2 = tmp;
201 		DELAY(1);
202 		*scr2 = tmp | SCR2_RTCLK;
203 		DELAY(1);
204 		*scr2 = tmp;
205 		DELAY(1);
206 
207 		v <<= 1;
208 	}
209 
210 	*scr2 &= ~(SCR2_RTDATA|SCR2_RTCLK|SCR2_RTCE);
211 	DELAY(1);
212 }
213 
214 void
215 poweroff(void)
216 {
217 	int reg, t;
218 
219 	if(new_clock) {
220 		reg = RTC_CNTR3;
221 	} else {
222 		reg = RTC_CNTR0;
223 	}
224 
225 	t = rtc_read(reg);	/* seconds */
226 	/* wait for clock to tick */
227 	while(t == rtc_read(reg));
228 
229 	DELAY(850000);	/* hardware bug workaround ? */
230 
231 	if(new_clock) {
232 		reg = RTC_CONTROL;
233 	} else {
234 		reg = RTC_INTRCTL;
235 	}
236 
237 	rtc_write(reg, rtc_read(reg)|(RTC_PDOWN));
238 
239 	printf("....................."); /* @@@ work around some sort of bug. */
240 
241 	panic("Failed to poweroff!");
242 }
243 
244 
245 time_t
246 getsecs(void)
247 {
248 	u_int secs = 0;
249 
250 	if (new_clock) {
251 		secs = rtc_read(RTC_CNTR3) << 24 |
252 				rtc_read(RTC_CNTR2) << 16 |
253 				rtc_read(RTC_CNTR1) << 8	 |
254 				rtc_read(RTC_CNTR0);
255 	} else {
256 		struct clock_ymdhms val;
257 		{
258 			u_char y;
259 			y = FROMBCD(rtc_read(RTC_YR));
260 			if (y >= 69) {
261 				val.dt_year = 1900+y;
262 			} else {
263 				val.dt_year = 2000+y;
264 			}
265 		}
266 		val.dt_mon	= FROMBCD(rtc_read(RTC_MON)&0x1f);
267 		val.dt_day	= FROMBCD(rtc_read(RTC_DATE)&0x3f);
268 		val.dt_wday = FROMBCD(rtc_read(RTC_DAY)&0x7);
269 		{
270 			u_char h;
271 			h = rtc_read(RTC_HRS);
272 			if (h & 0x80) {					/* time is am/pm format */
273 				val.dt_hour = FROMBCD(h&0x1f);
274 				if (h & 0x20) { /* pm */
275 					if (val.dt_hour < 12) val.dt_hour += 12;
276 				} else {  /* am */
277 					if (val.dt_hour == 12) val.dt_hour = 0;
278 				}
279 			} else {								/* time is 24 hour format */
280 				val.dt_hour = FROMBCD(h & 0x3f);
281 			}
282 		}
283 		val.dt_min	= FROMBCD(rtc_read(RTC_MIN)&0x7f);
284 		val.dt_sec	= FROMBCD(rtc_read(RTC_SEC)&0x7f);
285 
286 		secs = clock_ymdhms_to_secs(&val);
287 	}
288 
289 	return secs;
290 }
291 
292 void
293 setsecs(time_t secs)
294 {
295 
296 	/* Stop the clock */
297 	rtc_write(RTC_CONTROL,rtc_read(RTC_CONTROL) & ~RTC_START);
298 
299 #ifdef RTC_DEBUG
300 	printf("Setting RTC to 0x%08x.  Regs before:\n",secs);
301 	rtc_print();
302 #endif
303 
304 	if (new_clock) {
305 		rtc_write(RTC_CNTR3, (secs << 24) & 0xff);
306 		rtc_write(RTC_CNTR2, (secs << 16) & 0xff);
307 		rtc_write(RTC_CNTR1, (secs <<	 8) & 0xff);
308 		rtc_write(RTC_CNTR0, (secs) & 0xff);
309 
310 	} else {
311 		struct clock_ymdhms val;
312 		clock_secs_to_ymdhms(secs,&val);
313 		rtc_write(RTC_SEC,TOBCD(val.dt_sec));
314 		rtc_write(RTC_MIN,TOBCD(val.dt_min));
315 		{
316 			u_char h;
317 			h = rtc_read(RTC_HRS);
318 			if (h & 0x80) {						/* time is am/pm format */
319 				if (val.dt_hour == 0) {
320 					rtc_write(RTC_HRS,TOBCD(12)|0x80);
321 				} else if (val.dt_hour < 12) {	/* am */
322 					rtc_write(RTC_HRS,TOBCD(val.dt_hour)|0x80);
323 				} else if (val.dt_hour == 12) {
324 						rtc_write(RTC_HRS,TOBCD(12)|0x80|0x20);
325 				} else {								/* pm */
326 					rtc_write(RTC_HRS,TOBCD(val.dt_hour-12)|0x80|0x20);
327 				}
328 			} else {									/* time is 24 hour format */
329 				rtc_write(RTC_HRS,TOBCD(val.dt_hour));
330 			}
331 		}
332 		rtc_write(RTC_DAY,TOBCD(val.dt_wday));
333 		rtc_write(RTC_DATE,TOBCD(val.dt_day));
334 		rtc_write(RTC_MON,TOBCD(val.dt_mon));
335 		rtc_write(RTC_YR,TOBCD(val.dt_year%100));
336 	}
337 
338 #ifdef RTC_DEBUG
339 	printf("Regs after:\n",secs);
340 	rtc_print();
341 #endif
342 
343 	/* restart the clock */
344 	rtc_write(RTC_CONTROL,rtc_read(RTC_CONTROL) | RTC_START);
345 
346 }
347