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