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