1 /* $NetBSD: mk48txx.c,v 1.7 2001/04/08 17:05:10 tsutsui 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/param.h> 43 #include <sys/malloc.h> 44 #include <sys/systm.h> 45 #include <sys/errno.h> 46 47 #include <machine/bus.h> 48 #include <dev/clock_subr.h> 49 #include <dev/ic/mk48txxreg.h> 50 51 52 struct mk48txx { 53 bus_space_tag_t mk_bt; /* bus tag & handle */ 54 bus_space_handle_t mk_bh; /* */ 55 bus_size_t mk_nvramsz; /* Size of NVRAM on the chip */ 56 bus_size_t mk_clkoffset; /* Offset in NVRAM to clock bits */ 57 u_int mk_year0; /* What year is represented on the system 58 by the chip's year counter at 0 */ 59 }; 60 61 int mk48txx_gettime(todr_chip_handle_t, struct timeval *); 62 int mk48txx_settime(todr_chip_handle_t, struct timeval *); 63 int mk48txx_getcal(todr_chip_handle_t, int *); 64 int mk48txx_setcal(todr_chip_handle_t, int); 65 66 int mk48txx_auto_century_adjust = 1; 67 68 struct { 69 const char *name; 70 bus_size_t nvramsz; 71 bus_size_t clkoff; 72 int flags; 73 #define MK48TXX_EXT_REGISTERS 1 /* Has extended register set */ 74 } mk48txx_models[] = { 75 { "mk48t02", MK48T02_CLKSZ, MK48T02_CLKOFF, 0 }, 76 { "mk48t08", MK48T08_CLKSZ, MK48T08_CLKOFF, 0 }, 77 { "mk48t59", MK48T59_CLKSZ, MK48T59_CLKOFF, MK48TXX_EXT_REGISTERS }, 78 }; 79 80 todr_chip_handle_t 81 mk48txx_attach(bt, bh, model, year0) 82 bus_space_tag_t bt; 83 bus_space_handle_t bh; 84 const char *model; 85 int year0; 86 { 87 todr_chip_handle_t handle; 88 struct mk48txx *mk; 89 bus_size_t nvramsz, clkoff; 90 int sz; 91 int i; 92 93 printf(": %s", model); 94 95 i = sizeof(mk48txx_models)/sizeof(mk48txx_models[0]); 96 while (--i >= 0) { 97 if (strcmp(model, mk48txx_models[i].name) == 0) { 98 nvramsz = mk48txx_models[i].nvramsz; 99 clkoff = mk48txx_models[i].clkoff; 100 break; 101 } 102 } 103 if (i < 0) { 104 printf(": unsupported model"); 105 return (NULL); 106 } 107 108 sz = ALIGN(sizeof(struct todr_chip_handle)) + sizeof(struct mk48txx); 109 handle = malloc(sz, M_DEVBUF, M_NOWAIT); 110 mk = (struct mk48txx *)((u_long)handle + 111 ALIGN(sizeof(struct todr_chip_handle))); 112 handle->cookie = mk; 113 handle->todr_gettime = mk48txx_gettime; 114 handle->todr_settime = mk48txx_settime; 115 handle->todr_getcal = mk48txx_getcal; 116 handle->todr_setcal = mk48txx_setcal; 117 handle->todr_setwen = NULL; 118 mk->mk_bt = bt; 119 mk->mk_bh = bh; 120 mk->mk_nvramsz = nvramsz; 121 mk->mk_clkoffset = clkoff; 122 mk->mk_year0 = year0; 123 124 return (handle); 125 } 126 127 /* 128 * Get time-of-day and convert to a `struct timeval' 129 * Return 0 on success; an error number otherwise. 130 */ 131 int 132 mk48txx_gettime(handle, tv) 133 todr_chip_handle_t handle; 134 struct timeval *tv; 135 { 136 struct mk48txx *mk = handle->cookie; 137 bus_space_tag_t bt = mk->mk_bt; 138 bus_space_handle_t bh = mk->mk_bh; 139 bus_size_t clkoff = mk->mk_clkoffset; 140 struct clock_ymdhms dt; 141 int year; 142 u_int8_t csr; 143 144 todr_wenable(handle, 1); 145 146 /* enable read (stop time) */ 147 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 148 csr |= MK48TXX_CSR_READ; 149 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 150 151 dt.dt_sec = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_ISEC)); 152 dt.dt_min = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMIN)); 153 dt.dt_hour = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IHOUR)); 154 dt.dt_day = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IDAY)); 155 dt.dt_wday = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IWDAY)); 156 dt.dt_mon = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMON)); 157 year = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IYEAR)); 158 159 year += mk->mk_year0; 160 if (year < POSIX_BASE_YEAR && mk48txx_auto_century_adjust != 0) 161 year += 100; 162 163 dt.dt_year = year; 164 165 /* time wears on */ 166 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 167 csr &= ~MK48TXX_CSR_READ; 168 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 169 todr_wenable(handle, 0); 170 171 /* simple sanity checks */ 172 if (dt.dt_mon > 12 || dt.dt_day > 31 || 173 dt.dt_hour >= 24 || dt.dt_min >= 60 || dt.dt_sec >= 60) 174 return (1); 175 176 tv->tv_sec = clock_ymdhms_to_secs(&dt); 177 tv->tv_usec = 0; 178 return (0); 179 } 180 181 /* 182 * Set the time-of-day clock based on the value of the `struct timeval' arg. 183 * Return 0 on success; an error number otherwise. 184 */ 185 int 186 mk48txx_settime(handle, tv) 187 todr_chip_handle_t handle; 188 struct timeval *tv; 189 { 190 struct mk48txx *mk = handle->cookie; 191 bus_space_tag_t bt = mk->mk_bt; 192 bus_space_handle_t bh = mk->mk_bh; 193 bus_size_t clkoff = mk->mk_clkoffset; 194 struct clock_ymdhms dt; 195 u_int8_t csr; 196 int year; 197 198 /* Note: we ignore `tv_usec' */ 199 clock_secs_to_ymdhms(tv->tv_sec, &dt); 200 201 year = dt.dt_year - mk->mk_year0; 202 if (year > 99 && mk48txx_auto_century_adjust != 0) 203 year -= 100; 204 205 todr_wenable(handle, 1); 206 /* enable write */ 207 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 208 csr |= MK48TXX_CSR_WRITE; 209 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 210 211 bus_space_write_1(bt, bh, clkoff + MK48TXX_ISEC, TOBCD(dt.dt_sec)); 212 bus_space_write_1(bt, bh, clkoff + MK48TXX_IMIN, TOBCD(dt.dt_min)); 213 bus_space_write_1(bt, bh, clkoff + MK48TXX_IHOUR, TOBCD(dt.dt_hour)); 214 bus_space_write_1(bt, bh, clkoff + MK48TXX_IWDAY, TOBCD(dt.dt_wday)); 215 bus_space_write_1(bt, bh, clkoff + MK48TXX_IDAY, TOBCD(dt.dt_day)); 216 bus_space_write_1(bt, bh, clkoff + MK48TXX_IMON, TOBCD(dt.dt_mon)); 217 bus_space_write_1(bt, bh, clkoff + MK48TXX_IYEAR, TOBCD(year)); 218 219 /* load them up */ 220 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 221 csr &= ~MK48TXX_CSR_WRITE; 222 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 223 todr_wenable(handle, 0); 224 return (0); 225 } 226 227 int 228 mk48txx_getcal(handle, vp) 229 todr_chip_handle_t handle; 230 int *vp; 231 { 232 return (EOPNOTSUPP); 233 } 234 235 int 236 mk48txx_setcal(handle, v) 237 todr_chip_handle_t handle; 238 int v; 239 { 240 return (EOPNOTSUPP); 241 } 242 243 int 244 mk48txx_get_nvram_size(handle, vp) 245 todr_chip_handle_t handle; 246 bus_size_t *vp; 247 { 248 struct mk48txx *mk = handle->cookie; 249 *vp = mk->mk_nvramsz; 250 return (0); 251 } 252