Deleted Added
full compact
mc146818.c (146417) mc146818.c (146982)
1/*-
2 * Copyright (c) 2003 Izumi Tsutsui. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * from: NetBSD: mc146818.c,v 1.4 2003/11/24 06:20:40 tsutsui Exp
27 */
28
29#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2003 Izumi Tsutsui. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * from: NetBSD: mc146818.c,v 1.4 2003/11/24 06:20:40 tsutsui Exp
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/dev/mc146818/mc146818.c 146417 2005-05-19 21:20:42Z marius $");
30__FBSDID("$FreeBSD: head/sys/dev/mc146818/mc146818.c 146982 2005-06-04 23:24:50Z marius $");
31
32/*
33 * mc146818 and compatible time of day chip subroutines
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/bus.h>
39#include <sys/clock.h>
40#include <sys/lock.h>
41#include <sys/mutex.h>
42
43#include <machine/bus.h>
44
45#include <dev/mc146818/mc146818reg.h>
46#include <dev/mc146818/mc146818var.h>
47
48#include "clock_if.h"
49
50static u_int mc146818_def_getcent(device_t);
51static void mc146818_def_setcent(device_t, u_int);
52static u_int mc146818_def_read(device_t, u_int);
53static void mc146818_def_write(device_t, u_int, u_int);
54
55int
56mc146818_attach(device_t dev)
57{
58 struct mc146818_softc *sc;
59
60 sc = device_get_softc(dev);
61
62 if (mtx_initialized(&sc->sc_mtx) == 0) {
63 device_printf(dev, "%s: mutex not initialized\n", __func__);
64 return (ENXIO);
65 }
66
67 if (sc->sc_mcread == NULL)
68 sc->sc_mcread = mc146818_def_read;
69 if (sc->sc_mcwrite == NULL)
70 sc->sc_mcwrite = mc146818_def_write;
71
72 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
73 /*
74 * Note that setting MC146818_NO_CENT_ADJUST means that
75 * the century has to be stored in NVRAM somewhere.
76 */
77 if (sc->sc_getcent == NULL)
78 sc->sc_getcent = mc146818_def_getcent;
79 if (sc->sc_setcent == NULL)
80 sc->sc_setcent = mc146818_def_setcent;
81 }
82
31
32/*
33 * mc146818 and compatible time of day chip subroutines
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/bus.h>
39#include <sys/clock.h>
40#include <sys/lock.h>
41#include <sys/mutex.h>
42
43#include <machine/bus.h>
44
45#include <dev/mc146818/mc146818reg.h>
46#include <dev/mc146818/mc146818var.h>
47
48#include "clock_if.h"
49
50static u_int mc146818_def_getcent(device_t);
51static void mc146818_def_setcent(device_t, u_int);
52static u_int mc146818_def_read(device_t, u_int);
53static void mc146818_def_write(device_t, u_int, u_int);
54
55int
56mc146818_attach(device_t dev)
57{
58 struct mc146818_softc *sc;
59
60 sc = device_get_softc(dev);
61
62 if (mtx_initialized(&sc->sc_mtx) == 0) {
63 device_printf(dev, "%s: mutex not initialized\n", __func__);
64 return (ENXIO);
65 }
66
67 if (sc->sc_mcread == NULL)
68 sc->sc_mcread = mc146818_def_read;
69 if (sc->sc_mcwrite == NULL)
70 sc->sc_mcwrite = mc146818_def_write;
71
72 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
73 /*
74 * Note that setting MC146818_NO_CENT_ADJUST means that
75 * the century has to be stored in NVRAM somewhere.
76 */
77 if (sc->sc_getcent == NULL)
78 sc->sc_getcent = mc146818_def_getcent;
79 if (sc->sc_setcent == NULL)
80 sc->sc_setcent = mc146818_def_setcent;
81 }
82
83 mtx_lock(&sc->sc_mtx);
83 mtx_lock_spin(&sc->sc_mtx);
84 if (!(*sc->sc_mcread)(dev, MC_REGD) & MC_REGD_VRT) {
84 if (!(*sc->sc_mcread)(dev, MC_REGD) & MC_REGD_VRT) {
85 mtx_unlock(&sc->sc_mtx);
85 mtx_unlock_spin(&sc->sc_mtx);
86 device_printf(dev, "%s: battery low\n", __func__);
87 return (ENXIO);
88 }
89
90 sc->sc_rega = MC_BASE_32_KHz;
91 (*sc->sc_mcwrite)(dev, MC_REGA, sc->sc_rega);
92
93 sc->sc_regb = 0;
94 sc->sc_regb |= (sc->sc_flag & MC146818_BCD) ? 0 : MC_REGB_BINARY;
95 sc->sc_regb |= (sc->sc_flag & MC146818_12HR) ? 0 : MC_REGB_24HR;
96 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
86 device_printf(dev, "%s: battery low\n", __func__);
87 return (ENXIO);
88 }
89
90 sc->sc_rega = MC_BASE_32_KHz;
91 (*sc->sc_mcwrite)(dev, MC_REGA, sc->sc_rega);
92
93 sc->sc_regb = 0;
94 sc->sc_regb |= (sc->sc_flag & MC146818_BCD) ? 0 : MC_REGB_BINARY;
95 sc->sc_regb |= (sc->sc_flag & MC146818_12HR) ? 0 : MC_REGB_24HR;
96 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
97 mtx_unlock(&sc->sc_mtx);
97 mtx_unlock_spin(&sc->sc_mtx);
98
99 clock_register(dev, 1000000); /* 1 second resolution. */
100
101 return (0);
102}
103
104/*
105 * Get time of day and convert it to a struct timespec.
106 * Return 0 on success, an error number otherwise.
107 */
108int
109mc146818_gettime(device_t dev, struct timespec *ts)
110{
111 struct mc146818_softc *sc;
112 struct clocktime ct;
113 int timeout, cent, year;
114
115 sc = device_get_softc(dev);
116
117 timeout = 1000000; /* XXX how long should we wait? */
118
98
99 clock_register(dev, 1000000); /* 1 second resolution. */
100
101 return (0);
102}
103
104/*
105 * Get time of day and convert it to a struct timespec.
106 * Return 0 on success, an error number otherwise.
107 */
108int
109mc146818_gettime(device_t dev, struct timespec *ts)
110{
111 struct mc146818_softc *sc;
112 struct clocktime ct;
113 int timeout, cent, year;
114
115 sc = device_get_softc(dev);
116
117 timeout = 1000000; /* XXX how long should we wait? */
118
119 mtx_lock(&sc->sc_mtx);
120 /*
121 * If MC_REGA_UIP is 0 we have at least 244us before the next
122 * update. If it's 1 an update is imminent.
123 */
124 for (;;) {
119 /*
120 * If MC_REGA_UIP is 0 we have at least 244us before the next
121 * update. If it's 1 an update is imminent.
122 */
123 for (;;) {
124 mtx_lock_spin(&sc->sc_mtx);
125 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP))
126 break;
125 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP))
126 break;
127 mtx_unlock_spin(&sc->sc_mtx);
127 if (--timeout < 0) {
128 if (--timeout < 0) {
128 mtx_unlock(&sc->sc_mtx);
129 device_printf(dev, "%s: timeout\n", __func__);
130 return (EBUSY);
131 }
132 }
133
134#define FROMREG(x) ((sc->sc_flag & MC146818_BCD) ? FROMBCD(x) : (x))
135
136 ct.nsec = 0;
137 ct.sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
138 ct.min = FROMREG((*sc->sc_mcread)(dev, MC_MIN));
139 ct.hour = FROMREG((*sc->sc_mcread)(dev, MC_HOUR));
140 /* Map dow from 1 - 7 to 0 - 6. */
141 ct.dow = FROMREG((*sc->sc_mcread)(dev, MC_DOW)) - 1;
142 ct.day = FROMREG((*sc->sc_mcread)(dev, MC_DOM));
143 ct.mon = FROMREG((*sc->sc_mcread)(dev, MC_MONTH));
144 year = FROMREG((*sc->sc_mcread)(dev, MC_YEAR));
145 year += sc->sc_year0;
146 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
147 cent = (*sc->sc_getcent)(dev);
148 year += cent * 100;
149 } else if (year < POSIX_BASE_YEAR)
150 year += 100;
129 device_printf(dev, "%s: timeout\n", __func__);
130 return (EBUSY);
131 }
132 }
133
134#define FROMREG(x) ((sc->sc_flag & MC146818_BCD) ? FROMBCD(x) : (x))
135
136 ct.nsec = 0;
137 ct.sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
138 ct.min = FROMREG((*sc->sc_mcread)(dev, MC_MIN));
139 ct.hour = FROMREG((*sc->sc_mcread)(dev, MC_HOUR));
140 /* Map dow from 1 - 7 to 0 - 6. */
141 ct.dow = FROMREG((*sc->sc_mcread)(dev, MC_DOW)) - 1;
142 ct.day = FROMREG((*sc->sc_mcread)(dev, MC_DOM));
143 ct.mon = FROMREG((*sc->sc_mcread)(dev, MC_MONTH));
144 year = FROMREG((*sc->sc_mcread)(dev, MC_YEAR));
145 year += sc->sc_year0;
146 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
147 cent = (*sc->sc_getcent)(dev);
148 year += cent * 100;
149 } else if (year < POSIX_BASE_YEAR)
150 year += 100;
151 mtx_unlock(&sc->sc_mtx);
151 mtx_unlock_spin(&sc->sc_mtx);
152
153 ct.year = year;
154
155 return (clock_ct_to_ts(&ct, ts));
156}
157
158#ifdef notyet
159int
160mc146818_getsecs(device_t dev, int *secp)
161{
162 struct mc146818_softc *sc;
163 int sec, timeout;
164
165 sc = device_get_softc(dev);
166
167 timeout = 1000000; /* XXX how long should we wait? */
168
152
153 ct.year = year;
154
155 return (clock_ct_to_ts(&ct, ts));
156}
157
158#ifdef notyet
159int
160mc146818_getsecs(device_t dev, int *secp)
161{
162 struct mc146818_softc *sc;
163 int sec, timeout;
164
165 sc = device_get_softc(dev);
166
167 timeout = 1000000; /* XXX how long should we wait? */
168
169 mtx_lock(&sc->sc_mtx);
170 for (;;) {
169 for (;;) {
170 mtx_lock_spin(&sc->sc_mtx);
171 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP)) {
172 sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
171 if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP)) {
172 sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
173 mtx_unlock_spin(&sc->sc_mtx);
173 break;
174 }
174 break;
175 }
176 mtx_unlock_spin(&sc->sc_mtx);
175 if (--timeout == 0) {
177 if (--timeout == 0) {
176 mtx_unlock(&sc->sc_mtx);
177 device_printf(dev, "%s: timeout\n", __func__);
178 return (EBUSY);
179 }
180 }
178 device_printf(dev, "%s: timeout\n", __func__);
179 return (EBUSY);
180 }
181 }
181 mtx_unlock(&sc->sc_mtx);
182
183#undef FROMREG
184
185 *secp = sec;
186 return (0);
187}
188#endif
189
190/*
191 * Set the time of day clock based on the value of the struct timespec arg.
192 * Return 0 on success, an error number otherwise.
193 */
194int
195mc146818_settime(device_t dev, struct timespec *ts)
196{
197 struct mc146818_softc *sc;
198 struct clocktime ct;
199 int cent, year;
200
201 sc = device_get_softc(dev);
202
203 /* Accuracy is only one second. */
204 if (ts->tv_nsec >= 500000000)
205 ts->tv_sec++;
206 ts->tv_nsec = 0;
207 clock_ts_to_ct(ts, &ct);
208
182
183#undef FROMREG
184
185 *secp = sec;
186 return (0);
187}
188#endif
189
190/*
191 * Set the time of day clock based on the value of the struct timespec arg.
192 * Return 0 on success, an error number otherwise.
193 */
194int
195mc146818_settime(device_t dev, struct timespec *ts)
196{
197 struct mc146818_softc *sc;
198 struct clocktime ct;
199 int cent, year;
200
201 sc = device_get_softc(dev);
202
203 /* Accuracy is only one second. */
204 if (ts->tv_nsec >= 500000000)
205 ts->tv_sec++;
206 ts->tv_nsec = 0;
207 clock_ts_to_ct(ts, &ct);
208
209 mtx_lock(&sc->sc_mtx);
209 mtx_lock_spin(&sc->sc_mtx);
210 /* Disable RTC updates and interrupts (if enabled). */
211 (*sc->sc_mcwrite)(dev, MC_REGB,
212 ((sc->sc_regb & (MC_REGB_BINARY | MC_REGB_24HR)) | MC_REGB_SET));
213
214#define TOREG(x) ((sc->sc_flag & MC146818_BCD) ? TOBCD(x) : (x))
215
216 (*sc->sc_mcwrite)(dev, MC_SEC, TOREG(ct.sec));
217 (*sc->sc_mcwrite)(dev, MC_MIN, TOREG(ct.min));
218 (*sc->sc_mcwrite)(dev, MC_HOUR, TOREG(ct.hour));
219 /* Map dow from 0 - 6 to 1 - 7. */
220 (*sc->sc_mcwrite)(dev, MC_DOW, TOREG(ct.dow + 1));
221 (*sc->sc_mcwrite)(dev, MC_DOM, TOREG(ct.day));
222 (*sc->sc_mcwrite)(dev, MC_MONTH, TOREG(ct.mon));
223
224 year = ct.year - sc->sc_year0;
225 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
226 cent = year / 100;
227 (*sc->sc_setcent)(dev, cent);
228 year -= cent * 100;
229 } else if (year > 99)
230 year -= 100;
231 (*sc->sc_mcwrite)(dev, MC_YEAR, TOREG(year));
232
233 /* Reenable RTC updates and interrupts. */
234 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
210 /* Disable RTC updates and interrupts (if enabled). */
211 (*sc->sc_mcwrite)(dev, MC_REGB,
212 ((sc->sc_regb & (MC_REGB_BINARY | MC_REGB_24HR)) | MC_REGB_SET));
213
214#define TOREG(x) ((sc->sc_flag & MC146818_BCD) ? TOBCD(x) : (x))
215
216 (*sc->sc_mcwrite)(dev, MC_SEC, TOREG(ct.sec));
217 (*sc->sc_mcwrite)(dev, MC_MIN, TOREG(ct.min));
218 (*sc->sc_mcwrite)(dev, MC_HOUR, TOREG(ct.hour));
219 /* Map dow from 0 - 6 to 1 - 7. */
220 (*sc->sc_mcwrite)(dev, MC_DOW, TOREG(ct.dow + 1));
221 (*sc->sc_mcwrite)(dev, MC_DOM, TOREG(ct.day));
222 (*sc->sc_mcwrite)(dev, MC_MONTH, TOREG(ct.mon));
223
224 year = ct.year - sc->sc_year0;
225 if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
226 cent = year / 100;
227 (*sc->sc_setcent)(dev, cent);
228 year -= cent * 100;
229 } else if (year > 99)
230 year -= 100;
231 (*sc->sc_mcwrite)(dev, MC_YEAR, TOREG(year));
232
233 /* Reenable RTC updates and interrupts. */
234 (*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
235 mtx_unlock(&sc->sc_mtx);
235 mtx_unlock_spin(&sc->sc_mtx);
236
237#undef TOREG
238
239 return (0);
240}
241
242#define MC_ADDR 0
243#define MC_DATA 1
244
245static u_int
246mc146818_def_read(device_t dev, u_int reg)
247{
248 struct mc146818_softc *sc;
249
250 sc = device_get_softc(dev);
251 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg);
252 return (bus_space_read_1(sc->sc_bst, sc->sc_bsh, MC_DATA));
253}
254
255static void
256mc146818_def_write(device_t dev, u_int reg, u_int val)
257{
258 struct mc146818_softc *sc;
259
260 sc = device_get_softc(dev);
261 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg);
262 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_DATA, val);
263}
264
265/*
266 * Looks like it's common even across platforms to store the century at
267 * 0x32 in the NVRAM of the mc146818.
268 */
269#define MC_CENT 0x32
270
271static u_int
272mc146818_def_getcent(device_t dev)
273{
274 struct mc146818_softc *sc;
275
276 sc = device_get_softc(dev);
277 return ((*sc->sc_mcread)(dev, MC_CENT));
278}
279
280static void
281mc146818_def_setcent(device_t dev, u_int cent)
282{
283 struct mc146818_softc *sc;
284
285 sc = device_get_softc(dev);
286 (*sc->sc_mcwrite)(dev, MC_CENT, cent);
287}
236
237#undef TOREG
238
239 return (0);
240}
241
242#define MC_ADDR 0
243#define MC_DATA 1
244
245static u_int
246mc146818_def_read(device_t dev, u_int reg)
247{
248 struct mc146818_softc *sc;
249
250 sc = device_get_softc(dev);
251 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg);
252 return (bus_space_read_1(sc->sc_bst, sc->sc_bsh, MC_DATA));
253}
254
255static void
256mc146818_def_write(device_t dev, u_int reg, u_int val)
257{
258 struct mc146818_softc *sc;
259
260 sc = device_get_softc(dev);
261 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_ADDR, reg);
262 bus_space_write_1(sc->sc_bst, sc->sc_bsh, MC_DATA, val);
263}
264
265/*
266 * Looks like it's common even across platforms to store the century at
267 * 0x32 in the NVRAM of the mc146818.
268 */
269#define MC_CENT 0x32
270
271static u_int
272mc146818_def_getcent(device_t dev)
273{
274 struct mc146818_softc *sc;
275
276 sc = device_get_softc(dev);
277 return ((*sc->sc_mcread)(dev, MC_CENT));
278}
279
280static void
281mc146818_def_setcent(device_t dev, u_int cent)
282{
283 struct mc146818_softc *sc;
284
285 sc = device_get_softc(dev);
286 (*sc->sc_mcwrite)(dev, MC_CENT, cent);
287}