1/* $OpenBSD: mk48txx.c,v 1.10 2022/10/16 01:22:39 jsg 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 46struct 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 55int mk48txx_gettime(todr_chip_handle_t, struct timeval *); 56int mk48txx_settime(todr_chip_handle_t, struct timeval *); 57 58int mk48txx_auto_century_adjust = 1; 59 60struct { 61 const char *name; 62 bus_size_t nvramsz; 63 bus_size_t clkoff; 64 int flags; 65#define MK48TXX_EXT_REGISTERS 1 /* Has extended register set */ 66} mk48txx_models[] = { 67 { "mk48t02", MK48T02_CLKSZ, MK48T02_CLKOFF, 0 }, 68 { "mk48t08", MK48T08_CLKSZ, MK48T08_CLKOFF, 0 }, 69 { "mk48t18", MK48T18_CLKSZ, MK48T18_CLKOFF, 0 }, 70 { "mk48t59", MK48T59_CLKSZ, MK48T59_CLKOFF, MK48TXX_EXT_REGISTERS }, 71}; 72 73todr_chip_handle_t 74mk48txx_attach(bus_space_tag_t bt, bus_space_handle_t bh, const char *model, 75 int year0) 76{ 77 todr_chip_handle_t handle; 78 struct mk48txx *mk; 79 bus_size_t nvramsz, clkoff; 80 int sz; 81 int i; 82 83 printf(": %s", model); 84 85 i = nitems(mk48txx_models); 86 while (--i >= 0) { 87 if (strcmp(model, mk48txx_models[i].name) == 0) { 88 nvramsz = mk48txx_models[i].nvramsz; 89 clkoff = mk48txx_models[i].clkoff; 90 break; 91 } 92 } 93 if (i < 0) { 94 printf(": unsupported model"); 95 return (NULL); 96 } 97 98 sz = ALIGN(sizeof(struct todr_chip_handle)) + sizeof(struct mk48txx); 99 handle = malloc(sz, M_DEVBUF, M_NOWAIT); 100 if (handle == NULL) { 101 printf(": failed to allocate memory"); 102 return NULL; 103 } 104 mk = (struct mk48txx *)((u_long)handle + 105 ALIGN(sizeof(struct todr_chip_handle))); 106 handle->cookie = mk; 107 handle->todr_gettime = mk48txx_gettime; 108 handle->todr_settime = mk48txx_settime; 109 handle->todr_setwen = NULL; 110 handle->todr_quality = 0; 111 mk->mk_bt = bt; 112 mk->mk_bh = bh; 113 mk->mk_nvramsz = nvramsz; 114 mk->mk_clkoffset = clkoff; 115 mk->mk_year0 = year0; 116 117 return (handle); 118} 119 120/* 121 * Get time-of-day and convert to a `struct timeval' 122 * Return 0 on success; an error number otherwise. 123 */ 124int 125mk48txx_gettime(todr_chip_handle_t handle, struct timeval *tv) 126{ 127 struct mk48txx *mk = handle->cookie; 128 bus_space_tag_t bt = mk->mk_bt; 129 bus_space_handle_t bh = mk->mk_bh; 130 bus_size_t clkoff = mk->mk_clkoffset; 131 struct clock_ymdhms dt; 132 int year; 133 u_int8_t csr; 134 135 todr_wenable(handle, 1); 136 137 /* enable read (stop time) */ 138 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 139 csr |= MK48TXX_CSR_READ; 140 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 141 142 dt.dt_sec = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_ISEC)); 143 dt.dt_min = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMIN)); 144 dt.dt_hour = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IHOUR)); 145 dt.dt_day = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IDAY)); 146 dt.dt_wday = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IWDAY)); 147 dt.dt_mon = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMON)); 148 year = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IYEAR)); 149 150 year += mk->mk_year0; 151 if (year < POSIX_BASE_YEAR && mk48txx_auto_century_adjust != 0 && 152 mk->mk_year0 >= POSIX_BASE_YEAR) 153 year += 100; 154 155 dt.dt_year = year; 156 157 /* time wears on */ 158 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 159 csr &= ~MK48TXX_CSR_READ; 160 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 161 todr_wenable(handle, 0); 162 163 /* simple sanity checks */ 164 if (dt.dt_mon > 12 || dt.dt_day > 31 || 165 dt.dt_hour >= 24 || dt.dt_min >= 60 || dt.dt_sec >= 60) 166 return (1); 167 168 tv->tv_sec = clock_ymdhms_to_secs(&dt); 169 tv->tv_usec = 0; 170 return (0); 171} 172 173/* 174 * Set the time-of-day clock based on the value of the `struct timeval' arg. 175 * Return 0 on success; an error number otherwise. 176 */ 177int 178mk48txx_settime(todr_chip_handle_t handle, struct timeval *tv) 179{ 180 struct mk48txx *mk = handle->cookie; 181 bus_space_tag_t bt = mk->mk_bt; 182 bus_space_handle_t bh = mk->mk_bh; 183 bus_size_t clkoff = mk->mk_clkoffset; 184 struct clock_ymdhms dt; 185 u_int8_t csr; 186 int year; 187 188 /* Note: we ignore `tv_usec' */ 189 clock_secs_to_ymdhms(tv->tv_sec, &dt); 190 191 year = dt.dt_year - mk->mk_year0; 192 if (year > 99 && mk48txx_auto_century_adjust != 0) 193 year -= 100; 194 195 todr_wenable(handle, 1); 196 /* enable write */ 197 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 198 csr |= MK48TXX_CSR_WRITE; 199 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 200 201 bus_space_write_1(bt, bh, clkoff + MK48TXX_ISEC, TOBCD(dt.dt_sec)); 202 bus_space_write_1(bt, bh, clkoff + MK48TXX_IMIN, TOBCD(dt.dt_min)); 203 bus_space_write_1(bt, bh, clkoff + MK48TXX_IHOUR, TOBCD(dt.dt_hour)); 204 bus_space_write_1(bt, bh, clkoff + MK48TXX_IWDAY, TOBCD(dt.dt_wday)); 205 bus_space_write_1(bt, bh, clkoff + MK48TXX_IDAY, TOBCD(dt.dt_day)); 206 bus_space_write_1(bt, bh, clkoff + MK48TXX_IMON, TOBCD(dt.dt_mon)); 207 bus_space_write_1(bt, bh, clkoff + MK48TXX_IYEAR, TOBCD(year)); 208 209 /* load them up */ 210 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 211 csr &= ~MK48TXX_CSR_WRITE; 212 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 213 todr_wenable(handle, 0); 214 return (0); 215} 216 217int 218mk48txx_get_nvram_size(todr_chip_handle_t handle, bus_size_t *vp) 219{ 220 struct mk48txx *mk = handle->cookie; 221 *vp = mk->mk_nvramsz; 222 return (0); 223} 224