1 /* $OpenBSD: mk48txx.c,v 1.5 2008/06/26 05:42:15 ray Exp $ */ 2 /* $NetBSD: mk48txx.c,v 1.7 2001/04/08 17:05:10 tsutsui Exp $ */ 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Mostek MK48T02, MK48T08, MK48T59 time-of-day chip subroutines. 34 */ 35 36 #include <sys/param.h> 37 #include <sys/malloc.h> 38 #include <sys/systm.h> 39 #include <sys/errno.h> 40 41 #include <machine/bus.h> 42 #include <dev/clock_subr.h> 43 #include <dev/ic/mk48txxreg.h> 44 45 46 struct mk48txx { 47 bus_space_tag_t mk_bt; /* bus tag & handle */ 48 bus_space_handle_t mk_bh; /* */ 49 bus_size_t mk_nvramsz; /* Size of NVRAM on the chip */ 50 bus_size_t mk_clkoffset; /* Offset in NVRAM to clock bits */ 51 u_int mk_year0; /* What year is represented on the system 52 by the chip's year counter at 0 */ 53 }; 54 55 int mk48txx_gettime(todr_chip_handle_t, struct timeval *); 56 int mk48txx_settime(todr_chip_handle_t, struct timeval *); 57 int mk48txx_getcal(todr_chip_handle_t, int *); 58 int mk48txx_setcal(todr_chip_handle_t, int); 59 60 int mk48txx_auto_century_adjust = 1; 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 todr_chip_handle_t 76 mk48txx_attach(bt, bh, model, year0) 77 bus_space_tag_t bt; 78 bus_space_handle_t bh; 79 const char *model; 80 int year0; 81 { 82 todr_chip_handle_t handle; 83 struct mk48txx *mk; 84 bus_size_t nvramsz, clkoff; 85 int sz; 86 int i; 87 88 printf(": %s", model); 89 90 i = sizeof(mk48txx_models)/sizeof(mk48txx_models[0]); 91 while (--i >= 0) { 92 if (strcmp(model, mk48txx_models[i].name) == 0) { 93 nvramsz = mk48txx_models[i].nvramsz; 94 clkoff = mk48txx_models[i].clkoff; 95 break; 96 } 97 } 98 if (i < 0) { 99 printf(": unsupported model"); 100 return (NULL); 101 } 102 103 sz = ALIGN(sizeof(struct todr_chip_handle)) + sizeof(struct mk48txx); 104 handle = malloc(sz, M_DEVBUF, M_NOWAIT); 105 if (handle == NULL) { 106 printf(": failed to allocate memory"); 107 return NULL; 108 } 109 mk = (struct mk48txx *)((u_long)handle + 110 ALIGN(sizeof(struct todr_chip_handle))); 111 handle->cookie = mk; 112 handle->todr_gettime = mk48txx_gettime; 113 handle->todr_settime = mk48txx_settime; 114 handle->todr_getcal = mk48txx_getcal; 115 handle->todr_setcal = mk48txx_setcal; 116 handle->todr_setwen = NULL; 117 mk->mk_bt = bt; 118 mk->mk_bh = bh; 119 mk->mk_nvramsz = nvramsz; 120 mk->mk_clkoffset = clkoff; 121 mk->mk_year0 = year0; 122 123 return (handle); 124 } 125 126 /* 127 * Get time-of-day and convert to a `struct timeval' 128 * Return 0 on success; an error number otherwise. 129 */ 130 int 131 mk48txx_gettime(handle, tv) 132 todr_chip_handle_t handle; 133 struct timeval *tv; 134 { 135 struct mk48txx *mk = handle->cookie; 136 bus_space_tag_t bt = mk->mk_bt; 137 bus_space_handle_t bh = mk->mk_bh; 138 bus_size_t clkoff = mk->mk_clkoffset; 139 struct clock_ymdhms dt; 140 int year; 141 u_int8_t csr; 142 143 todr_wenable(handle, 1); 144 145 /* enable read (stop time) */ 146 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 147 csr |= MK48TXX_CSR_READ; 148 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 149 150 dt.dt_sec = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_ISEC)); 151 dt.dt_min = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMIN)); 152 dt.dt_hour = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IHOUR)); 153 dt.dt_day = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IDAY)); 154 dt.dt_wday = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IWDAY)); 155 dt.dt_mon = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMON)); 156 year = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IYEAR)); 157 158 year += mk->mk_year0; 159 if (year < POSIX_BASE_YEAR && mk48txx_auto_century_adjust != 0) 160 year += 100; 161 162 dt.dt_year = year; 163 164 /* time wears on */ 165 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 166 csr &= ~MK48TXX_CSR_READ; 167 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 168 todr_wenable(handle, 0); 169 170 /* simple sanity checks */ 171 if (dt.dt_mon > 12 || dt.dt_day > 31 || 172 dt.dt_hour >= 24 || dt.dt_min >= 60 || dt.dt_sec >= 60) 173 return (1); 174 175 tv->tv_sec = clock_ymdhms_to_secs(&dt); 176 tv->tv_usec = 0; 177 return (0); 178 } 179 180 /* 181 * Set the time-of-day clock based on the value of the `struct timeval' arg. 182 * Return 0 on success; an error number otherwise. 183 */ 184 int 185 mk48txx_settime(handle, tv) 186 todr_chip_handle_t handle; 187 struct timeval *tv; 188 { 189 struct mk48txx *mk = handle->cookie; 190 bus_space_tag_t bt = mk->mk_bt; 191 bus_space_handle_t bh = mk->mk_bh; 192 bus_size_t clkoff = mk->mk_clkoffset; 193 struct clock_ymdhms dt; 194 u_int8_t csr; 195 int year; 196 197 /* Note: we ignore `tv_usec' */ 198 clock_secs_to_ymdhms(tv->tv_sec, &dt); 199 200 year = dt.dt_year - mk->mk_year0; 201 if (year > 99 && mk48txx_auto_century_adjust != 0) 202 year -= 100; 203 204 todr_wenable(handle, 1); 205 /* enable write */ 206 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 207 csr |= MK48TXX_CSR_WRITE; 208 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 209 210 bus_space_write_1(bt, bh, clkoff + MK48TXX_ISEC, TOBCD(dt.dt_sec)); 211 bus_space_write_1(bt, bh, clkoff + MK48TXX_IMIN, TOBCD(dt.dt_min)); 212 bus_space_write_1(bt, bh, clkoff + MK48TXX_IHOUR, TOBCD(dt.dt_hour)); 213 bus_space_write_1(bt, bh, clkoff + MK48TXX_IWDAY, TOBCD(dt.dt_wday)); 214 bus_space_write_1(bt, bh, clkoff + MK48TXX_IDAY, TOBCD(dt.dt_day)); 215 bus_space_write_1(bt, bh, clkoff + MK48TXX_IMON, TOBCD(dt.dt_mon)); 216 bus_space_write_1(bt, bh, clkoff + MK48TXX_IYEAR, TOBCD(year)); 217 218 /* load them up */ 219 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 220 csr &= ~MK48TXX_CSR_WRITE; 221 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 222 todr_wenable(handle, 0); 223 return (0); 224 } 225 226 int 227 mk48txx_getcal(handle, vp) 228 todr_chip_handle_t handle; 229 int *vp; 230 { 231 return (EOPNOTSUPP); 232 } 233 234 int 235 mk48txx_setcal(handle, v) 236 todr_chip_handle_t handle; 237 int v; 238 { 239 return (EOPNOTSUPP); 240 } 241 242 int 243 mk48txx_get_nvram_size(handle, vp) 244 todr_chip_handle_t handle; 245 bus_size_t *vp; 246 { 247 struct mk48txx *mk = handle->cookie; 248 *vp = mk->mk_nvramsz; 249 return (0); 250 } 251