1 /* $NetBSD: mk48txx.c,v 1.18 2005/12/11 12:21:27 christos Exp $ */ 2 /*- 3 * Copyright (c) 2000 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Paul Kranenburg. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Mostek MK48T02, MK48T08, MK48T59 time-of-day chip subroutines. 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: mk48txx.c,v 1.18 2005/12/11 12:21:27 christos Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/device.h> 48 #include <sys/errno.h> 49 50 #include <machine/bus.h> 51 #include <dev/clock_subr.h> 52 #include <dev/ic/mk48txxreg.h> 53 #include <dev/ic/mk48txxvar.h> 54 55 int mk48txx_gettime(todr_chip_handle_t, volatile struct timeval *); 56 int mk48txx_settime(todr_chip_handle_t, volatile struct timeval *); 57 int mk48txx_getcal(todr_chip_handle_t, int *); 58 int mk48txx_setcal(todr_chip_handle_t, int); 59 u_int8_t mk48txx_def_nvrd(struct mk48txx_softc *, int); 60 void mk48txx_def_nvwr(struct mk48txx_softc *, int, u_int8_t); 61 62 struct { 63 const char *name; 64 bus_size_t nvramsz; 65 bus_size_t clkoff; 66 int flags; 67 #define MK48TXX_EXT_REGISTERS 1 /* Has extended register set */ 68 } mk48txx_models[] = { 69 { "mk48t02", MK48T02_CLKSZ, MK48T02_CLKOFF, 0 }, 70 { "mk48t08", MK48T08_CLKSZ, MK48T08_CLKOFF, 0 }, 71 { "mk48t18", MK48T18_CLKSZ, MK48T18_CLKOFF, 0 }, 72 { "mk48t59", MK48T59_CLKSZ, MK48T59_CLKOFF, MK48TXX_EXT_REGISTERS }, 73 }; 74 75 void 76 mk48txx_attach(sc) 77 struct mk48txx_softc *sc; 78 { 79 todr_chip_handle_t handle; 80 int i; 81 82 printf(": %s", sc->sc_model); 83 84 i = sizeof(mk48txx_models) / sizeof(mk48txx_models[0]); 85 while (--i >= 0) { 86 if (strcmp(sc->sc_model, mk48txx_models[i].name) == 0) 87 break; 88 } 89 if (i < 0) 90 panic("mk48txx_attach: unsupported model"); 91 92 sc->sc_nvramsz = mk48txx_models[i].nvramsz; 93 sc->sc_clkoffset = mk48txx_models[i].clkoff; 94 95 handle = &sc->sc_handle; 96 handle->cookie = sc; 97 handle->todr_gettime = mk48txx_gettime; 98 handle->todr_settime = mk48txx_settime; 99 handle->todr_getcal = mk48txx_getcal; 100 handle->todr_setcal = mk48txx_setcal; 101 handle->todr_setwen = NULL; 102 103 if (sc->sc_nvrd == NULL) 104 sc->sc_nvrd = mk48txx_def_nvrd; 105 if (sc->sc_nvwr == NULL) 106 sc->sc_nvwr = mk48txx_def_nvwr; 107 } 108 109 /* 110 * Get time-of-day and convert to a `struct timeval' 111 * Return 0 on success; an error number otherwise. 112 */ 113 int 114 mk48txx_gettime(handle, tv) 115 todr_chip_handle_t handle; 116 volatile struct timeval *tv; 117 { 118 struct mk48txx_softc *sc; 119 bus_size_t clkoff; 120 struct clock_ymdhms dt; 121 int year; 122 u_int8_t csr; 123 124 sc = handle->cookie; 125 clkoff = sc->sc_clkoffset; 126 127 todr_wenable(handle, 1); 128 129 /* enable read (stop time) */ 130 csr = (*sc->sc_nvrd)(sc, clkoff + MK48TXX_ICSR); 131 csr |= MK48TXX_CSR_READ; 132 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_ICSR, csr); 133 134 dt.dt_sec = FROMBCD((*sc->sc_nvrd)(sc, clkoff + MK48TXX_ISEC)); 135 dt.dt_min = FROMBCD((*sc->sc_nvrd)(sc, clkoff + MK48TXX_IMIN)); 136 dt.dt_hour = FROMBCD((*sc->sc_nvrd)(sc, clkoff + MK48TXX_IHOUR)); 137 dt.dt_day = FROMBCD((*sc->sc_nvrd)(sc, clkoff + MK48TXX_IDAY)); 138 dt.dt_wday = FROMBCD((*sc->sc_nvrd)(sc, clkoff + MK48TXX_IWDAY)); 139 dt.dt_mon = FROMBCD((*sc->sc_nvrd)(sc, clkoff + MK48TXX_IMON)); 140 year = FROMBCD((*sc->sc_nvrd)(sc, clkoff + MK48TXX_IYEAR)); 141 142 year += sc->sc_year0; 143 if (year < POSIX_BASE_YEAR && 144 (sc->sc_flag & MK48TXX_NO_CENT_ADJUST) == 0) 145 year += 100; 146 147 dt.dt_year = year; 148 149 /* time wears on */ 150 csr = (*sc->sc_nvrd)(sc, clkoff + MK48TXX_ICSR); 151 csr &= ~MK48TXX_CSR_READ; 152 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_ICSR, csr); 153 todr_wenable(handle, 0); 154 155 /* simple sanity checks */ 156 if (dt.dt_mon > 12 || dt.dt_day > 31 || 157 dt.dt_hour >= 24 || dt.dt_min >= 60 || dt.dt_sec >= 60) 158 return EIO; 159 160 tv->tv_sec = clock_ymdhms_to_secs(&dt); 161 if (tv->tv_sec == -1) return ERANGE; 162 tv->tv_usec = 0; 163 return 0; 164 } 165 166 /* 167 * Set the time-of-day clock based on the value of the `struct timeval' arg. 168 * Return 0 on success; an error number otherwise. 169 */ 170 int 171 mk48txx_settime(handle, tv) 172 todr_chip_handle_t handle; 173 volatile struct timeval *tv; 174 { 175 struct mk48txx_softc *sc; 176 bus_size_t clkoff; 177 struct clock_ymdhms dt; 178 u_int8_t csr; 179 int year; 180 long sec; 181 182 sc = handle->cookie; 183 clkoff = sc->sc_clkoffset; 184 185 /* Note: we ignore `tv_usec' */ 186 sec = tv->tv_sec + ((tv->tv_usec < 500000) ? 0 : 1); 187 clock_secs_to_ymdhms(sec, &dt); 188 189 year = dt.dt_year - sc->sc_year0; 190 if (year > 99 && 191 (sc->sc_flag & MK48TXX_NO_CENT_ADJUST) == 0) 192 year -= 100; 193 194 todr_wenable(handle, 1); 195 /* enable write */ 196 csr = (*sc->sc_nvrd)(sc, clkoff + MK48TXX_ICSR); 197 csr |= MK48TXX_CSR_WRITE; 198 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_ICSR, csr); 199 200 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_ISEC, TOBCD(dt.dt_sec)); 201 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_IMIN, TOBCD(dt.dt_min)); 202 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_IHOUR, TOBCD(dt.dt_hour)); 203 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_IWDAY, TOBCD(dt.dt_wday)); 204 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_IDAY, TOBCD(dt.dt_day)); 205 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_IMON, TOBCD(dt.dt_mon)); 206 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_IYEAR, TOBCD(year)); 207 208 /* load them up */ 209 csr = (*sc->sc_nvrd)(sc, clkoff + MK48TXX_ICSR); 210 csr &= ~MK48TXX_CSR_WRITE; 211 (*sc->sc_nvwr)(sc, clkoff + MK48TXX_ICSR, csr); 212 todr_wenable(handle, 0); 213 return 0; 214 } 215 216 int 217 mk48txx_getcal(handle, vp) 218 todr_chip_handle_t handle; 219 int *vp; 220 { 221 222 return EOPNOTSUPP; 223 } 224 225 int 226 mk48txx_setcal(handle, v) 227 todr_chip_handle_t handle; 228 int v; 229 { 230 231 return EOPNOTSUPP; 232 } 233 234 int 235 mk48txx_get_nvram_size(handle, vp) 236 todr_chip_handle_t handle; 237 bus_size_t *vp; 238 { 239 struct mk48txx_softc *sc; 240 241 sc = handle->cookie; 242 *vp = sc->sc_nvramsz; 243 return 0; 244 } 245 246 u_int8_t 247 mk48txx_def_nvrd(struct mk48txx_softc *sc, int off) 248 { 249 250 return bus_space_read_1(sc->sc_bst, sc->sc_bsh, off); 251 } 252 253 void 254 mk48txx_def_nvwr(struct mk48txx_softc *sc, int off, u_int8_t v) 255 { 256 257 bus_space_write_1(sc->sc_bst, sc->sc_bsh, off, v); 258 } 259