2 * Copyright (c) 2003 Izumi Tsutsui. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 * $NetBSD: mc146818.c,v 1.16 2008/05/14 13:29:28 tsutsui Exp $
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
31 * mc146818 and compatible time of day chip subroutines
34 #include <sys/param.h>
35 #include <sys/systm.h>
37 #include <sys/clock.h>
39 #include <sys/mutex.h>
41 #include <machine/bus.h>
43 #include <dev/mc146818/mc146818reg.h>
44 #include <dev/mc146818/mc146818var.h>
48 static u_int mc146818_def_getcent(device_t);
49 static void mc146818_def_setcent(device_t, u_int);
52 mc146818_attach(device_t dev)
54 struct mc146818_softc *sc;
56 sc = device_get_softc(dev);
58 if (mtx_initialized(&sc->sc_mtx) == 0) {
59 device_printf(dev, "%s: mutex not initialized\n", __func__);
63 if (sc->sc_mcread == NULL)
64 sc->sc_mcread = mc146818_def_read;
65 if (sc->sc_mcwrite == NULL)
66 sc->sc_mcwrite = mc146818_def_write;
68 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
70 * Note that setting MC146818_NO_CENT_ADJUST means that
71 * the century has to be stored in NVRAM somewhere.
73 if (sc->sc_getcent == NULL)
74 sc->sc_getcent = mc146818_def_getcent;
75 if (sc->sc_setcent == NULL)
76 sc->sc_setcent = mc146818_def_setcent;
79 mtx_lock_spin(&sc->sc_mtx);
80 if (!(*sc->sc_mcread)(dev, MC_REGD) & MC_REGD_VRT) {
81 mtx_unlock_spin(&sc->sc_mtx);
82 device_printf(dev, "%s: battery low\n", __func__);
86 sc->sc_rega = MC_BASE_32_KHz;
87 (*sc->sc_mcwrite)(dev, MC_REGA, sc->sc_rega);
90 sc->sc_regb |= (sc->sc_flag & MC146818_BCD) ? 0 : MC_REGB_BINARY;
91 sc->sc_regb |= (sc->sc_flag & MC146818_12HR) ? 0 : MC_REGB_24HR;
92 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
93 mtx_unlock_spin(&sc->sc_mtx);
95 clock_register(dev, 1000000); /* 1 second resolution */
101 * Get time of day and convert it to a struct timespec.
102 * Return 0 on success, an error number otherwise.
105 mc146818_gettime(device_t dev, struct timespec *ts)
107 struct mc146818_softc *sc;
109 int timeout, cent, year;
111 sc = device_get_softc(dev);
113 timeout = 1000000; /* XXX how long should we wait? */
116 * If MC_REGA_UIP is 0 we have at least 244us before the next
117 * update. If it's 1 an update is imminent.
120 mtx_lock_spin(&sc->sc_mtx);
121 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP))
123 mtx_unlock_spin(&sc->sc_mtx);
125 device_printf(dev, "%s: timeout\n", __func__);
130 #define FROMREG(x) ((sc->sc_flag & MC146818_BCD) ? FROMBCD(x) : (x))
133 ct.sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
134 ct.min = FROMREG((*sc->sc_mcread)(dev, MC_MIN));
135 ct.hour = FROMREG((*sc->sc_mcread)(dev, MC_HOUR));
136 /* Map dow from 1 - 7 to 0 - 6. */
137 ct.dow = FROMREG((*sc->sc_mcread)(dev, MC_DOW)) - 1;
138 ct.day = FROMREG((*sc->sc_mcread)(dev, MC_DOM));
139 ct.mon = FROMREG((*sc->sc_mcread)(dev, MC_MONTH));
140 year = FROMREG((*sc->sc_mcread)(dev, MC_YEAR));
141 year += sc->sc_year0;
142 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
143 cent = (*sc->sc_getcent)(dev);
145 } else if (year < POSIX_BASE_YEAR)
147 mtx_unlock_spin(&sc->sc_mtx);
151 return (clock_ct_to_ts(&ct, ts));
156 mc146818_getsecs(device_t dev, int *secp)
158 struct mc146818_softc *sc;
161 sc = device_get_softc(dev);
163 timeout = 1000000; /* XXX how long should we wait? */
166 mtx_lock_spin(&sc->sc_mtx);
167 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP)) {
168 sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
169 mtx_unlock_spin(&sc->sc_mtx);
172 mtx_unlock_spin(&sc->sc_mtx);
173 if (--timeout == 0) {
174 device_printf(dev, "%s: timeout\n", __func__);
187 * Set the time of day clock based on the value of the struct timespec arg.
188 * Return 0 on success, an error number otherwise.
191 mc146818_settime(device_t dev, struct timespec *ts)
193 struct mc146818_softc *sc;
197 sc = device_get_softc(dev);
199 /* Accuracy is only one second. */
200 if (ts->tv_nsec >= 500000000)
203 clock_ts_to_ct(ts, &ct);
205 mtx_lock_spin(&sc->sc_mtx);
206 /* Disable RTC updates and interrupts (if enabled). */
207 (*sc->sc_mcwrite)(dev, MC_REGB,
208 ((sc->sc_regb & (MC_REGB_BINARY | MC_REGB_24HR)) | MC_REGB_SET));
210 #define TOREG(x) ((sc->sc_flag & MC146818_BCD) ? TOBCD(x) : (x))
212 (*sc->sc_mcwrite)(dev, MC_SEC, TOREG(ct.sec));
213 (*sc->sc_mcwrite)(dev, MC_MIN, TOREG(ct.min));
214 (*sc->sc_mcwrite)(dev, MC_HOUR, TOREG(ct.hour));
215 /* Map dow from 0 - 6 to 1 - 7. */
216 (*sc->sc_mcwrite)(dev, MC_DOW, TOREG(ct.dow + 1));
217 (*sc->sc_mcwrite)(dev, MC_DOM, TOREG(ct.day));
218 (*sc->sc_mcwrite)(dev, MC_MONTH, TOREG(ct.mon));
220 year = ct.year - sc->sc_year0;
221 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
223 (*sc->sc_setcent)(dev, cent);
225 } else if (year > 99)
227 (*sc->sc_mcwrite)(dev, MC_YEAR, TOREG(year));
229 /* Reenable RTC updates and interrupts. */
230 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
231 mtx_unlock_spin(&sc->sc_mtx);
242 mc146818_def_read(device_t dev, u_int reg)
244 struct mc146818_softc *sc;
246 sc = device_get_softc(dev);
247 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg);
248 return (bus_space_read_1(sc->sc_bst, sc->sc_bsh, MC_DATA));
252 mc146818_def_write(device_t dev, u_int reg, u_int val)
254 struct mc146818_softc *sc;
256 sc = device_get_softc(dev);
257 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg);
258 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_DATA, val);
265 * Looks like it's common even across platforms to store the century at
266 * 0x32 in the NVRAM of the mc146818.
271 mc146818_def_getcent(device_t dev)
273 struct mc146818_softc *sc;
275 sc = device_get_softc(dev);
276 return ((*sc->sc_mcread)(dev, MC_CENT));
280 mc146818_def_setcent(device_t dev, u_int cent)
282 struct mc146818_softc *sc;
284 sc = device_get_softc(dev);
285 (*sc->sc_mcwrite)(dev, MC_CENT, cent);