a2kbbc.c revision 1.13
1/*	$NetBSD: a2kbbc.c,v 1.13 2002/09/27 20:29:43 thorpej Exp $ */
2
3/*
4 * Copyright (c) 1988 University of Utah.
5 * Copyright (c) 1982, 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * the Systems Programming Group of the University of Utah Computer
10 * Science Department.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *	This product includes software developed by the University of
23 *	California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: Utah $Hdr: clock.c 1.18 91/01/21$
41 *
42 *	@(#)clock.c	7.6 (Berkeley) 5/7/91
43 */
44
45#include <sys/cdefs.h>
46__KERNEL_RCSID(0, "$NetBSD: a2kbbc.c,v 1.13 2002/09/27 20:29:43 thorpej Exp $");
47
48#include <sys/param.h>
49#include <sys/kernel.h>
50#include <sys/device.h>
51#include <sys/systm.h>
52#include <machine/psl.h>
53#include <machine/cpu.h>
54#include <amiga/amiga/device.h>
55#include <amiga/amiga/custom.h>
56#include <amiga/amiga/cia.h>
57#include <amiga/dev/rtc.h>
58#include <amiga/dev/zbusvar.h>
59
60#include <dev/clock_subr.h>
61
62int a2kbbc_match(struct device *, struct cfdata *, void *);
63void a2kbbc_attach(struct device *, struct device *, void *);
64
65const struct cfattach a2kbbc_ca = {
66        sizeof(struct device), a2kbbc_match, a2kbbc_attach
67};
68
69void *a2kclockaddr;
70int a2kugettod(struct timeval *);
71int a2kusettod(struct timeval *);
72
73int
74a2kbbc_match(struct device *pdp, struct cfdata *cfp, void *auxp)
75{
76	static int a2kbbc_matched = 0;
77
78	if (!matchname("a2kbbc", auxp))
79		return (0);
80
81	/* Allow only one instance. */
82	if (a2kbbc_matched)
83		return (0);
84
85	if (/* is_a1200() || */ is_a3000() || is_a4000()
86#ifdef DRACO
87	    || is_draco()
88#endif
89	    )
90		return (0);
91
92	a2kclockaddr = (void *)ztwomap(0xdc0000);
93	if (a2kugettod(0) == 0)
94		return (0);
95
96	a2kbbc_matched = 1;
97	return (1);
98}
99
100/*
101 * Attach us to the rtc function pointers.
102 */
103void
104a2kbbc_attach(struct device *pdp, struct device *dp, void *auxp)
105{
106	printf("\n");
107	a2kclockaddr = (void *)ztwomap(0xdc0000);
108
109	ugettod = a2kugettod;
110	usettod = a2kusettod;
111}
112
113int
114a2kugettod(struct timeval *tvp)
115{
116	struct rtclock2000 *rt;
117	struct clock_ymdhms dt;
118	time_t secs;
119	int i;
120
121	rt = a2kclockaddr;
122
123	/*
124	 * hold clock
125	 */
126	rt->control1 |= A2CONTROL1_HOLD;
127	i = 0x1000;
128	while (rt->control1 & A2CONTROL1_BUSY && i--)
129		;
130	if (rt->control1 & A2CONTROL1_BUSY)
131		return (0);	/* Give up and say it's not there */
132
133	/* Copy the info.  Careful about the order! */
134	dt.dt_sec   = rt->second1 * 10 + rt->second2;
135	dt.dt_min   = rt->minute1 * 10 + rt->minute2;
136	dt.dt_hour  = (rt->hour1 & 3) * 10 + rt->hour2;
137	dt.dt_day   = rt->day1    * 10 + rt->day2;
138	dt.dt_mon   = rt->month1  * 10 + rt->month2;
139	dt.dt_year  = rt->year1   * 10 + rt->year2;
140	dt.dt_wday  = rt->weekday;
141
142	/*
143	 * The oki clock chip has a register to put the clock into
144	 * 12/24h mode.
145	 *
146	 *  clockmode   |    A2HOUR1_PM
147	 *  24h   12h   |  am = 0, pm = 1
148	 * ---------------------------------
149	 *   0    12    |       0
150	 *   1     1    |       0
151	 *  ..    ..    |       0
152	 *  11    11    |       0
153	 *  12    12    |       1
154	 *  13     1    |       1
155	 *  ..    ..    |       1
156	 *  23    11    |       1
157	 *
158	 */
159
160	if ((rt->control3 & A2CONTROL3_24HMODE) == 0) {
161		if ((rt->hour1 & A2HOUR1_PM) == 0 && dt.dt_hour == 12)
162			dt.dt_hour = 0;
163		else if ((rt->hour1 & A2HOUR1_PM) && dt.dt_hour != 12)
164			dt.dt_hour += 12;
165	}
166
167	/*
168	 * release the clock
169	 */
170	rt->control1 &= ~A2CONTROL1_HOLD;
171
172	dt.dt_year += CLOCK_BASE_YEAR;
173	if (dt.dt_year < STARTOFTIME)
174		dt.dt_year += 100;
175
176	if ((dt.dt_hour > 23) ||
177	    (dt.dt_day  > 31) ||
178	    (dt.dt_mon  > 12) ||
179	    /* (dt.dt_year < STARTOFTIME) || */ (dt.dt_year > 2036))
180		return (0);
181
182	secs = clock_ymdhms_to_secs(&dt);
183	if (tvp) {
184		tvp->tv_sec = secs;
185		tvp->tv_usec = 0;
186	}
187	return (1);
188}
189
190int
191a2kusettod(struct timeval *tvp)
192{
193	struct rtclock2000 *rt;
194	struct clock_ymdhms dt;
195	int ampm, i;
196	time_t secs;
197
198	secs = tvp->tv_sec;
199	rt = a2kclockaddr;
200	/*
201	 * there seem to be problems with the bitfield addressing
202	 * currently used..
203	 */
204	if (! rt)
205		return (0);
206
207	clock_secs_to_ymdhms(secs, &dt);
208
209	/*
210	 * hold clock
211	 */
212	rt->control1 |= A2CONTROL1_HOLD;
213	i = 0x1000;
214	while (rt->control1 & A2CONTROL1_BUSY && i--)
215		;
216	if (rt->control1 & A2CONTROL1_BUSY)
217		return (0);	/* Give up and say it's not there */
218
219	ampm = 0;
220	if ((rt->control3 & A2CONTROL3_24HMODE) == 0) {
221		if (dt.dt_hour >= 12) {
222			ampm = A2HOUR1_PM;
223			if (dt.dt_hour != 12)
224				dt.dt_hour -= 12;
225		} else if (dt.dt_hour == 0) {
226			dt.dt_hour = 12;
227		}
228	}
229	rt->hour1   = (dt.dt_hour / 10) | ampm;
230	rt->hour2   = dt.dt_hour % 10;
231	rt->second1 = dt.dt_sec / 10;
232	rt->second2 = dt.dt_sec % 10;
233	rt->minute1 = dt.dt_min / 10;
234	rt->minute2 = dt.dt_min % 10;
235	rt->day1    = dt.dt_day / 10;
236	rt->day2    = dt.dt_day % 10;
237	rt->month1  = dt.dt_mon / 10;
238	rt->month2  = dt.dt_mon % 10;
239	rt->year1   = (dt.dt_year / 10) % 10;
240	rt->year2   = dt.dt_year % 10;
241	rt->weekday = dt.dt_wday;
242
243	/*
244	 * release the clock
245	 */
246	rt->control2 &= ~A2CONTROL1_HOLD;
247
248	return (1);
249}
250