mk48txx.c revision 119352
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 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the NetBSD 19 * Foundation, Inc. and its contributors. 20 * 4. Neither the name of The NetBSD Foundation nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 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 $ 37 * 38 * $FreeBSD: head/sys/dev/mk48txx/mk48txx.c 119352 2003-08-23 05:56:58Z marcel $ 39 */ 40 41/* 42 * Mostek MK48T02, MK48T08, MK48T59 time-of-day chip subroutines. 43 */ 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/bus.h> 48#include <sys/clock.h> 49#include <sys/malloc.h> 50 51#include <machine/bus.h> 52 53#include <dev/mk48txx/mk48txxreg.h> 54 55#include "clock_if.h" 56 57struct mk48txx_softc { 58 bus_space_tag_t mk_bt; /* bus tag & handle */ 59 bus_space_handle_t mk_bh; /* */ 60 bus_size_t mk_nvramsz; /* Size of NVRAM on the chip */ 61 bus_size_t mk_clkoffset; /* Offset in NVRAM to clock bits */ 62 u_int mk_year0; /* What year is represented on the system 63 by the chip's year counter at 0 */ 64}; 65 66int mk48txx_auto_century_adjust = 1; 67 68struct { 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 80int 81mk48txx_attach(device_t dev, bus_space_tag_t bt, bus_space_handle_t bh, 82 const char *model, int year0) 83{ 84 struct mk48txx_softc *sc; 85 bus_size_t clkoff = 0, nvramsz = 0; 86 int i; 87 88 device_printf(dev, "model %s", model); 89 i = sizeof(mk48txx_models) / sizeof(mk48txx_models[0]); 90 while (--i >= 0) { 91 if (strcmp(model, mk48txx_models[i].name) == 0) { 92 nvramsz = mk48txx_models[i].nvramsz; 93 clkoff = mk48txx_models[i].clkoff; 94 break; 95 } 96 } 97 if (i < 0) { 98 device_printf(dev, " (unsupported)\n"); 99 return (ENXIO); 100 } 101 printf("\n"); 102 103 sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 104 sc->mk_bt = bt; 105 sc->mk_bh = bh; 106 sc->mk_nvramsz = nvramsz; 107 sc->mk_clkoffset = clkoff; 108 sc->mk_year0 = year0; 109 device_set_softc(dev, sc); 110 clock_register(dev, 1000000); /* 1 second resolution. */ 111 112 return (0); 113} 114 115/* 116 * Get time-of-day and convert to a `struct timespec' 117 * Return 0 on success; an error number otherwise. 118 */ 119int 120mk48txx_gettime(device_t dev, struct timespec *ts) 121{ 122 struct mk48txx_softc *mk = device_get_softc(dev); 123 bus_space_tag_t bt = mk->mk_bt; 124 bus_space_handle_t bh = mk->mk_bh; 125 bus_size_t clkoff = mk->mk_clkoffset; 126 struct clocktime ct; 127 int year; 128 u_int8_t csr; 129 130 /* enable read (stop time) */ 131 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 132 csr |= MK48TXX_CSR_READ; 133 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 134 135 ct.nsec = 0; 136 ct.sec = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_ISEC)); 137 ct.min = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMIN)); 138 ct.hour = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IHOUR)); 139 ct.day = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IDAY)); 140 ct.dow = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IWDAY)) % 7; 141 ct.mon = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMON)); 142 year = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IYEAR)); 143 144 year += mk->mk_year0; 145 if (year < POSIX_BASE_YEAR && mk48txx_auto_century_adjust != 0) 146 year += 100; 147 148 ct.year = year; 149 150 /* time wears on */ 151 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 152 csr &= ~MK48TXX_CSR_READ; 153 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 154 155 return (clock_ct_to_ts(&ct, ts)); 156} 157 158/* 159 * Set the time-of-day clock based on the value of the `struct timespec' arg. 160 * Return 0 on success; an error number otherwise. 161 */ 162int 163mk48txx_settime(device_t dev, struct timespec *ts) 164{ 165 struct mk48txx_softc *mk = device_get_softc(dev); 166 bus_space_tag_t bt = mk->mk_bt; 167 bus_space_handle_t bh = mk->mk_bh; 168 bus_size_t clkoff = mk->mk_clkoffset; 169 struct clocktime ct; 170 u_int8_t csr; 171 int year; 172 173 /* Accuracy is only one second. */ 174 if (ts->tv_nsec >= 500000000) 175 ts->tv_sec++; 176 ts->tv_nsec = 0; 177 clock_ts_to_ct(ts, &ct); 178 179 year = ct.year - mk->mk_year0; 180 if (year > 99 && mk48txx_auto_century_adjust != 0) 181 year -= 100; 182 183 /* enable write */ 184 csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 185 csr |= MK48TXX_CSR_WRITE; 186 bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 187 188 bus_space_write_1(bt, bh, clkoff + MK48TXX_ISEC, TOBCD(ct.sec)); 189 bus_space_write_1(bt, bh, clkoff + MK48TXX_IMIN, TOBCD(ct.min)); 190 bus_space_write_1(bt, bh, clkoff + MK48TXX_IHOUR, TOBCD(ct.hour)); 191 bus_space_write_1(bt, bh, clkoff + MK48TXX_IWDAY, TOBCD(ct.dow)); 192 bus_space_write_1(bt, bh, clkoff + MK48TXX_IDAY, TOBCD(ct.day)); 193 bus_space_write_1(bt, bh, clkoff + MK48TXX_IMON, TOBCD(ct.mon)); 194 bus_space_write_1(bt, bh, clkoff + MK48TXX_IYEAR, TOBCD(year)); 195 196 /* load them up */ 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 return (0); 201} 202 203int 204mk48txx_get_nvram_size(device_t dev, bus_size_t *vp) 205{ 206 struct mk48txx_softc *mk; 207 208 mk = device_get_softc(dev); 209 *vp = mk->mk_nvramsz; 210 return (0); 211} 212