Deleted Added
full compact
mk48txx.c (135481) mk48txx.c (137813)
1/*-
2 * Copyright (c) 2000 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Paul Kranenburg.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 19 unchanged lines hidden (view full) ---

28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
1/*-
2 * Copyright (c) 2000 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Paul Kranenburg.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 19 unchanged lines hidden (view full) ---

28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 * $NetBSD: mk48txx.c,v 1.7 2001/04/08 17:05:10 tsutsui Exp $
36 * from: NetBSD: mk48txx.c,v 1.15 2004/07/05 09:24:31 pk Exp
37 */
38
39#include <sys/cdefs.h>
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/dev/mk48txx/mk48txx.c 135481 2004-09-19 21:38:11Z marius $");
40__FBSDID("$FreeBSD: head/sys/dev/mk48txx/mk48txx.c 137813 2004-11-17 12:54:12Z marius $");
41
42/*
41
42/*
43 * Mostek MK48T02, MK48T08, MK48T59 time-of-day chip subroutines.
43 * Mostek MK48T02, MK48T08, MK48T18, MK48T59 time-of-day chip subroutines.
44 */
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/bus.h>
49#include <sys/clock.h>
44 */
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/bus.h>
49#include <sys/clock.h>
50#include <sys/malloc.h>
51
52#include <machine/bus.h>
53
54#include <dev/mk48txx/mk48txxreg.h>
50
51#include <machine/bus.h>
52
53#include <dev/mk48txx/mk48txxreg.h>
54#include <dev/mk48txx/mk48txxvar.h>
55
56#include "clock_if.h"
57
55
56#include "clock_if.h"
57
58struct mk48txx_softc {
59 bus_space_tag_t mk_bt; /* bus tag & handle */
60 bus_space_handle_t mk_bh; /* */
61 bus_size_t mk_nvramsz; /* Size of NVRAM on the chip */
62 bus_size_t mk_clkoffset; /* Offset in NVRAM to clock bits */
63 u_int mk_year0; /* What year is represented on the system
64 by the chip's year counter at 0 */
65};
58static uint8_t mk48txx_def_nvrd(device_t, int);
59static void mk48txx_def_nvwr(device_t, int, u_int8_t);
66
60
67int mk48txx_auto_century_adjust = 1;
68
69struct {
70 const char *name;
71 bus_size_t nvramsz;
72 bus_size_t clkoff;
73 int flags;
74#define MK48TXX_EXT_REGISTERS 1 /* Has extended register set */
75} mk48txx_models[] = {
76 { "mk48t02", MK48T02_CLKSZ, MK48T02_CLKOFF, 0 },
77 { "mk48t08", MK48T08_CLKSZ, MK48T08_CLKOFF, 0 },
61struct {
62 const char *name;
63 bus_size_t nvramsz;
64 bus_size_t clkoff;
65 int flags;
66#define MK48TXX_EXT_REGISTERS 1 /* Has extended register set */
67} mk48txx_models[] = {
68 { "mk48t02", MK48T02_CLKSZ, MK48T02_CLKOFF, 0 },
69 { "mk48t08", MK48T08_CLKSZ, MK48T08_CLKOFF, 0 },
70 { "mk48t18", MK48T18_CLKSZ, MK48T18_CLKOFF, 0 },
78 { "mk48t59", MK48T59_CLKSZ, MK48T59_CLKOFF, MK48TXX_EXT_REGISTERS },
79};
80
81int
71 { "mk48t59", MK48T59_CLKSZ, MK48T59_CLKOFF, MK48TXX_EXT_REGISTERS },
72};
73
74int
82mk48txx_attach(device_t dev, bus_space_tag_t bt, bus_space_handle_t bh,
83 const char *model, int year0)
75mk48txx_attach(device_t dev)
84{
85 struct mk48txx_softc *sc;
76{
77 struct mk48txx_softc *sc;
86 bus_size_t clkoff = 0, nvramsz = 0;
87 int i;
88
78 int i;
79
89 device_printf(dev, "model %s", model);
80 sc = device_get_softc(dev);
81
82 device_printf(dev, "model %s", sc->sc_model);
90 i = sizeof(mk48txx_models) / sizeof(mk48txx_models[0]);
91 while (--i >= 0) {
83 i = sizeof(mk48txx_models) / sizeof(mk48txx_models[0]);
84 while (--i >= 0) {
92 if (strcmp(model, mk48txx_models[i].name) == 0) {
93 nvramsz = mk48txx_models[i].nvramsz;
94 clkoff = mk48txx_models[i].clkoff;
85 if (strcmp(sc->sc_model, mk48txx_models[i].name) == 0) {
95 break;
96 }
97 }
98 if (i < 0) {
99 device_printf(dev, " (unsupported)\n");
100 return (ENXIO);
101 }
102 printf("\n");
86 break;
87 }
88 }
89 if (i < 0) {
90 device_printf(dev, " (unsupported)\n");
91 return (ENXIO);
92 }
93 printf("\n");
94 sc->sc_nvramsz = mk48txx_models[i].nvramsz;
95 sc->sc_clkoffset = mk48txx_models[i].clkoff;
103
96
97 if (sc->sc_nvrd == NULL)
98 sc->sc_nvrd = mk48txx_def_nvrd;
99 if (sc->sc_nvwr == NULL)
100 sc->sc_nvwr = mk48txx_def_nvwr;
101
104 if ((mk48txx_models[i].flags & MK48TXX_EXT_REGISTERS) &&
102 if ((mk48txx_models[i].flags & MK48TXX_EXT_REGISTERS) &&
105 (bus_space_read_1(bt, bh, clkoff + MK48TXX_FLAGS) &
103 ((*sc->sc_nvrd)(dev, sc->sc_clkoffset + MK48TXX_FLAGS) &
106 MK48TXX_FLAGS_BL)) {
107 device_printf(dev, "mk48txx_attach: battery low\n");
108 return (ENXIO);
109 }
110
104 MK48TXX_FLAGS_BL)) {
105 device_printf(dev, "mk48txx_attach: battery low\n");
106 return (ENXIO);
107 }
108
111 sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
112 sc->mk_bt = bt;
113 sc->mk_bh = bh;
114 sc->mk_nvramsz = nvramsz;
115 sc->mk_clkoffset = clkoff;
116 sc->mk_year0 = year0;
117 device_set_softc(dev, sc);
118 clock_register(dev, 1000000); /* 1 second resolution. */
119
120 return (0);
121}
122
123/*
124 * Get time-of-day and convert to a `struct timespec'
125 * Return 0 on success; an error number otherwise.
126 */
127int
128mk48txx_gettime(device_t dev, struct timespec *ts)
129{
109 clock_register(dev, 1000000); /* 1 second resolution. */
110
111 return (0);
112}
113
114/*
115 * Get time-of-day and convert to a `struct timespec'
116 * Return 0 on success; an error number otherwise.
117 */
118int
119mk48txx_gettime(device_t dev, struct timespec *ts)
120{
130 struct mk48txx_softc *mk = device_get_softc(dev);
131 bus_space_tag_t bt = mk->mk_bt;
132 bus_space_handle_t bh = mk->mk_bh;
133 bus_size_t clkoff = mk->mk_clkoffset;
121 struct mk48txx_softc *sc;
122 bus_size_t clkoff;
134 struct clocktime ct;
135 int year;
136 u_int8_t csr;
137
123 struct clocktime ct;
124 int year;
125 u_int8_t csr;
126
127 sc = device_get_softc(dev);
128 clkoff = sc->sc_clkoffset;
129
138 /* enable read (stop time) */
130 /* enable read (stop time) */
139 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR);
131 csr = (*sc->sc_nvrd)(dev, clkoff + MK48TXX_ICSR);
140 csr |= MK48TXX_CSR_READ;
132 csr |= MK48TXX_CSR_READ;
141 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr);
133 (*sc->sc_nvwr)(dev, clkoff + MK48TXX_ICSR, csr);
142
134
143#define FROMREG(reg, mask) \
144 (bus_space_read_1(bt, bh, clkoff + (reg)) & (mask))
135#define FROMREG(reg, mask) ((*sc->sc_nvrd)(dev, clkoff + (reg)) & (mask))
145
146 ct.nsec = 0;
147 ct.sec = FROMBCD(FROMREG(MK48TXX_ISEC, MK48TXX_SEC_MASK));
148 ct.min = FROMBCD(FROMREG(MK48TXX_IMIN, MK48TXX_MIN_MASK));
149 ct.hour = FROMBCD(FROMREG(MK48TXX_IHOUR, MK48TXX_HOUR_MASK));
150 ct.day = FROMBCD(FROMREG(MK48TXX_IDAY, MK48TXX_DAY_MASK));
151 /* Map dow from 1 - 7 to 0 - 6; FROMBCD() isn't necessary here. */
152 ct.dow = FROMREG(MK48TXX_IWDAY, MK48TXX_WDAY_MASK) - 1;
153 ct.mon = FROMBCD(FROMREG(MK48TXX_IMON, MK48TXX_MON_MASK));
154 year = FROMBCD(FROMREG(MK48TXX_IYEAR, MK48TXX_YEAR_MASK));
155
156 /*
157 * XXX: At least the MK48T59 (probably all MK48Txx models with
158 * extended registers) has a century bit in the MK48TXX_IWDAY
159 * register which should be used here to make up the century
136
137 ct.nsec = 0;
138 ct.sec = FROMBCD(FROMREG(MK48TXX_ISEC, MK48TXX_SEC_MASK));
139 ct.min = FROMBCD(FROMREG(MK48TXX_IMIN, MK48TXX_MIN_MASK));
140 ct.hour = FROMBCD(FROMREG(MK48TXX_IHOUR, MK48TXX_HOUR_MASK));
141 ct.day = FROMBCD(FROMREG(MK48TXX_IDAY, MK48TXX_DAY_MASK));
142 /* Map dow from 1 - 7 to 0 - 6; FROMBCD() isn't necessary here. */
143 ct.dow = FROMREG(MK48TXX_IWDAY, MK48TXX_WDAY_MASK) - 1;
144 ct.mon = FROMBCD(FROMREG(MK48TXX_IMON, MK48TXX_MON_MASK));
145 year = FROMBCD(FROMREG(MK48TXX_IYEAR, MK48TXX_YEAR_MASK));
146
147 /*
148 * XXX: At least the MK48T59 (probably all MK48Txx models with
149 * extended registers) has a century bit in the MK48TXX_IWDAY
150 * register which should be used here to make up the century
160 * when mk48txx_auto_century_adjust (which actually means
161 * manually adjust the century in the driver) is set to 0.
151 * when MK48TXX_NO_CENT_ADJUST (which actually means don't
152 * _manually_ adjust the century in the driver) is set to 1.
162 * Sun/Solaris doesn't use this bit (probably for backwards
163 * compatibility with Sun hardware equipped with older MK48Txx
164 * models) and at present this driver is only used on sparc64
165 * so not respecting the century bit doesn't really matter at
166 * the moment but generally this should be implemented.
167 */
168
169#undef FROMREG
170
153 * Sun/Solaris doesn't use this bit (probably for backwards
154 * compatibility with Sun hardware equipped with older MK48Txx
155 * models) and at present this driver is only used on sparc64
156 * so not respecting the century bit doesn't really matter at
157 * the moment but generally this should be implemented.
158 */
159
160#undef FROMREG
161
171 year += mk->mk_year0;
172 if (year < POSIX_BASE_YEAR && mk48txx_auto_century_adjust != 0)
162 year += sc->sc_year0;
163 if (year < POSIX_BASE_YEAR &&
164 (sc->sc_flag & MK48TXX_NO_CENT_ADJUST) == 0)
173 year += 100;
174
175 ct.year = year;
176
177 /* time wears on */
165 year += 100;
166
167 ct.year = year;
168
169 /* time wears on */
178 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR);
170 csr = (*sc->sc_nvrd)(dev, clkoff + MK48TXX_ICSR);
179 csr &= ~MK48TXX_CSR_READ;
171 csr &= ~MK48TXX_CSR_READ;
180 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr);
172 (*sc->sc_nvwr)(dev, clkoff + MK48TXX_ICSR, csr);
181
182 return (clock_ct_to_ts(&ct, ts));
183}
184
185/*
186 * Set the time-of-day clock based on the value of the `struct timespec' arg.
187 * Return 0 on success; an error number otherwise.
188 */
189int
190mk48txx_settime(device_t dev, struct timespec *ts)
191{
173
174 return (clock_ct_to_ts(&ct, ts));
175}
176
177/*
178 * Set the time-of-day clock based on the value of the `struct timespec' arg.
179 * Return 0 on success; an error number otherwise.
180 */
181int
182mk48txx_settime(device_t dev, struct timespec *ts)
183{
192 struct mk48txx_softc *mk = device_get_softc(dev);
193 bus_space_tag_t bt = mk->mk_bt;
194 bus_space_handle_t bh = mk->mk_bh;
195 bus_size_t clkoff = mk->mk_clkoffset;
184 struct mk48txx_softc *sc;
185 bus_size_t clkoff;
196 struct clocktime ct;
197 u_int8_t csr;
198 int year;
199
186 struct clocktime ct;
187 u_int8_t csr;
188 int year;
189
190 sc = device_get_softc(dev);
191 clkoff = sc->sc_clkoffset;
192
200 /* Accuracy is only one second. */
201 if (ts->tv_nsec >= 500000000)
202 ts->tv_sec++;
203 ts->tv_nsec = 0;
204 clock_ts_to_ct(ts, &ct);
205
193 /* Accuracy is only one second. */
194 if (ts->tv_nsec >= 500000000)
195 ts->tv_sec++;
196 ts->tv_nsec = 0;
197 clock_ts_to_ct(ts, &ct);
198
206 year = ct.year - mk->mk_year0;
207 if (year > 99 && mk48txx_auto_century_adjust != 0)
199 year = ct.year - sc->sc_year0;
200 if (year > 99 && (sc->sc_flag & MK48TXX_NO_CENT_ADJUST) == 0)
208 year -= 100;
209
210 /* enable write */
201 year -= 100;
202
203 /* enable write */
211 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR);
204 csr = (*sc->sc_nvrd)(dev, clkoff + MK48TXX_ICSR);
212 csr |= MK48TXX_CSR_WRITE;
205 csr |= MK48TXX_CSR_WRITE;
213 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr);
206 (*sc->sc_nvwr)(dev, clkoff + MK48TXX_ICSR, csr);
214
215#define TOREG(reg, mask, val) \
207
208#define TOREG(reg, mask, val) \
216 (bus_space_write_1(bt, bh, clkoff + (reg), \
217 (bus_space_read_1(bt, bh, clkoff + (reg)) & ~(mask)) | \
209 ((*sc->sc_nvwr)(dev, clkoff + (reg), \
210 ((*sc->sc_nvrd)(dev, clkoff + (reg)) & ~(mask)) | \
218 ((val) & (mask))))
219
220 TOREG(MK48TXX_ISEC, MK48TXX_SEC_MASK, TOBCD(ct.sec));
221 TOREG(MK48TXX_IMIN, MK48TXX_MIN_MASK, TOBCD(ct.min));
222 TOREG(MK48TXX_IHOUR, MK48TXX_HOUR_MASK, TOBCD(ct.hour));
223 /* Map dow from 0 - 6 to 1 - 7; TOBCD() isn't necessary here. */
224 TOREG(MK48TXX_IWDAY, MK48TXX_WDAY_MASK, ct.dow + 1);
225 TOREG(MK48TXX_IDAY, MK48TXX_DAY_MASK, TOBCD(ct.day));
226 TOREG(MK48TXX_IMON, MK48TXX_MON_MASK, TOBCD(ct.mon));
227 TOREG(MK48TXX_IYEAR, MK48TXX_YEAR_MASK, TOBCD(year));
228
229 /*
230 * XXX: Use the century bit for storing the century when
211 ((val) & (mask))))
212
213 TOREG(MK48TXX_ISEC, MK48TXX_SEC_MASK, TOBCD(ct.sec));
214 TOREG(MK48TXX_IMIN, MK48TXX_MIN_MASK, TOBCD(ct.min));
215 TOREG(MK48TXX_IHOUR, MK48TXX_HOUR_MASK, TOBCD(ct.hour));
216 /* Map dow from 0 - 6 to 1 - 7; TOBCD() isn't necessary here. */
217 TOREG(MK48TXX_IWDAY, MK48TXX_WDAY_MASK, ct.dow + 1);
218 TOREG(MK48TXX_IDAY, MK48TXX_DAY_MASK, TOBCD(ct.day));
219 TOREG(MK48TXX_IMON, MK48TXX_MON_MASK, TOBCD(ct.mon));
220 TOREG(MK48TXX_IYEAR, MK48TXX_YEAR_MASK, TOBCD(year));
221
222 /*
223 * XXX: Use the century bit for storing the century when
231 * mk48txx_auto_century_adjust is set to 0.
224 * MK48TXX_NO_CENT_ADJUST is set to 1.
232 */
233
234#undef TOREG
235
236 /* load them up */
225 */
226
227#undef TOREG
228
229 /* load them up */
237 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR);
230 csr = (*sc->sc_nvrd)(dev, clkoff + MK48TXX_ICSR);
238 csr &= ~MK48TXX_CSR_WRITE;
231 csr &= ~MK48TXX_CSR_WRITE;
239 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr);
232 (*sc->sc_nvwr)(dev, clkoff + MK48TXX_ICSR, csr);
240 return (0);
241}
242
233 return (0);
234}
235
243int
244mk48txx_get_nvram_size(device_t dev, bus_size_t *vp)
236static u_int8_t
237mk48txx_def_nvrd(device_t dev, int off)
245{
238{
246 struct mk48txx_softc *mk;
239 struct mk48txx_softc *sc;
247
240
248 mk = device_get_softc(dev);
249 *vp = mk->mk_nvramsz;
250 return (0);
241 sc = device_get_softc(dev);
242 return (bus_space_read_1(sc->sc_bst, sc->sc_bsh, off));
251}
243}
244
245static void
246mk48txx_def_nvwr(device_t dev, int off, u_int8_t v)
247{
248 struct mk48txx_softc *sc;
249
250 sc = device_get_softc(dev);
251 bus_space_write_1(sc->sc_bst, sc->sc_bsh, off, v);
252}