1 /* $NetBSD: rtc.c,v 1.15 2009/09/20 16:18:21 tsutsui Exp $ */
4 * Copyright (c) 2001 Valeriy E. Ushakov
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * `rtc' is a DS1287A (== MC146818A) time-of-day clock at EBus.
32 * In Krups it's not used to store idprom so this driver doesn't
33 * support it. Don't know about other ms-IIep systems.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.15 2009/09/20 16:18:21 tsutsui Exp $");
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <sys/malloc.h>
43 #include <sys/systm.h>
48 #include <machine/bus.h>
49 #include <machine/autoconf.h>
51 #include <dev/clock_subr.h>
52 #include <dev/ic/mc146818reg.h>
54 #include <dev/ebus/ebusreg.h>
55 #include <dev/ebus/ebusvar.h>
57 struct rtc_ebus_softc
{
60 bus_space_tag_t sc_bt
; /* parent bus tag */
61 bus_space_handle_t sc_bh
; /* handle for registers */
64 static int rtcmatch_ebus(device_t
, cfdata_t
, void *);
65 static void rtcattach_ebus(device_t
, device_t
, void *);
67 CFATTACH_DECL(rtc_ebus
, sizeof(struct rtc_ebus_softc
),
68 rtcmatch_ebus
, rtcattach_ebus
, NULL
, NULL
);
70 /* XXX: global TOD clock handle (sparc/clock.c) */
71 extern todr_chip_handle_t todr_handle
;
74 static int rtc_gettime(todr_chip_handle_t
, struct timeval
*);
75 static int rtc_settime(todr_chip_handle_t
, struct timeval
*);
77 int rtc_auto_century_adjust
= 1; /* XXX: do we ever want not to? */
81 * MD read/write functions declared in mc146818reg.h
87 mc146818_read(void *cookie
, u_int reg
)
89 struct rtc_ebus_softc
*sc
= cookie
;
91 bus_space_write_1(sc
->sc_bt
, sc
->sc_bh
, RTC_ADDR
, reg
);
92 return (bus_space_read_1(sc
->sc_bt
, sc
->sc_bh
, RTC_DATA
));
96 mc146818_write(void *cookie
, u_int reg
, u_int datum
)
98 struct rtc_ebus_softc
*sc
= cookie
;
100 bus_space_write_1(sc
->sc_bt
, sc
->sc_bh
, RTC_ADDR
, reg
);
101 bus_space_write_1(sc
->sc_bt
, sc
->sc_bh
, RTC_DATA
, datum
);
106 rtcmatch_ebus(device_t parent
, cfdata_t cf
, void *aux
)
108 struct ebus_attach_args
*ea
= aux
;
110 return (strcmp(cf
->cf_name
, ea
->ea_name
) == 0);
114 rtcattach_ebus(device_t parent
, device_t self
, void *aux
)
116 struct rtc_ebus_softc
*sc
= device_private(self
);
117 struct ebus_attach_args
*ea
= aux
;
118 todr_chip_handle_t handle
;
120 sc
->sc_bt
= ea
->ea_bustag
;
121 if (bus_space_map(sc
->sc_bt
, EBUS_ADDR_FROM_REG(&ea
->ea_reg
[0]),
122 ea
->ea_reg
[0].size
, 0, &sc
->sc_bh
) != 0)
124 printf(": unable to map registers\n");
128 /* XXX: no "model" property in Krups */
129 printf(": time-of-day clock\n");
132 * Turn interrupts off (clear MC_REGB_?IE bits), just in case
133 * (although they shouldn't be wired to an interrupt
134 * controller on sparcs).
136 mc146818_write(sc
, MC_REGB
, MC_REGB_BINARY
| MC_REGB_24HR
);
138 /* setup our todr_handle */
139 handle
= malloc(ALIGN(sizeof(struct todr_chip_handle
)),
143 handle
->bus_cookie
= NULL
; /* unused */
144 handle
->todr_gettime
= rtc_gettime
;
145 handle
->todr_settime
= rtc_settime
;
146 handle
->todr_setwen
= NULL
; /* not necessary, no idprom to protect */
153 * Get time-of-day and convert to a `struct timeval'
154 * Return 0 on success; an error number otherwise.
157 rtc_gettime(todr_chip_handle_t handle
, struct timeval
*tv
)
159 struct rtc_ebus_softc
*sc
= handle
->cookie
;
160 struct clock_ymdhms dt
;
163 /* update in progress; spin loop */
164 while (mc146818_read(sc
, MC_REGA
) & MC_REGA_UIP
)
167 /* stop updates (XXX: do we need that???) */
168 mc146818_write(sc
, MC_REGB
,
169 (mc146818_read(sc
, MC_REGB
) | MC_REGB_SET
));
172 dt
.dt_sec
= mc146818_read(sc
, MC_SEC
);
173 dt
.dt_min
= mc146818_read(sc
, MC_MIN
);
174 dt
.dt_hour
= mc146818_read(sc
, MC_HOUR
);
175 dt
.dt_day
= mc146818_read(sc
, MC_DOM
);
176 dt
.dt_mon
= mc146818_read(sc
, MC_MONTH
);
177 year
= mc146818_read(sc
, MC_YEAR
);
179 /* reenable updates */
180 mc146818_write(sc
, MC_REGB
,
181 (mc146818_read(sc
, MC_REGB
) & ~MC_REGB_SET
));
183 /* year in the century 0..99: adjust to AD */
185 if (year
< POSIX_BASE_YEAR
&& rtc_auto_century_adjust
!= 0)
189 /* simple sanity checks */
190 if (dt
.dt_mon
> 12 || dt
.dt_day
> 31
191 || dt
.dt_hour
>= 24 || dt
.dt_min
>= 60 || dt
.dt_sec
>= 60)
194 tv
->tv_sec
= clock_ymdhms_to_secs(&dt
);
200 * Set the time-of-day clock based on the value of the `struct timeval' arg.
201 * Return 0 on success; an error number otherwise.
204 rtc_settime(todr_chip_handle_t handle
, struct timeval
*tv
)
206 struct rtc_ebus_softc
*sc
= handle
->cookie
;
207 struct clock_ymdhms dt
;
210 clock_secs_to_ymdhms(tv
->tv_sec
, &dt
);
212 year
= dt
.dt_year
- 1900;
213 if (year
>= 100 && rtc_auto_century_adjust
!= 0)
217 mc146818_write(sc
, MC_REGB
,
218 (mc146818_read(sc
, MC_REGB
) | MC_REGB_SET
));
220 mc146818_write(sc
, MC_SEC
, dt
.dt_sec
);
221 mc146818_write(sc
, MC_MIN
, dt
.dt_min
);
222 mc146818_write(sc
, MC_HOUR
, dt
.dt_hour
);
223 mc146818_write(sc
, MC_DOW
, dt
.dt_wday
+ 1);
224 mc146818_write(sc
, MC_DOM
, dt
.dt_day
);
225 mc146818_write(sc
, MC_MONTH
, dt
.dt_mon
);
226 mc146818_write(sc
, MC_YEAR
, year
);
228 /* reenable updates */
229 mc146818_write(sc
, MC_REGB
,
230 (mc146818_read(sc
, MC_REGB
) & ~MC_REGB_SET
));