mk48txx.c revision 119352
193836Stmm/*- 293836Stmm * Copyright (c) 2000 The NetBSD Foundation, Inc. 393836Stmm * All rights reserved. 493836Stmm * 593836Stmm * This code is derived from software contributed to The NetBSD Foundation 693836Stmm * by Paul Kranenburg. 793836Stmm * 893836Stmm * Redistribution and use in source and binary forms, with or without 993836Stmm * modification, are permitted provided that the following conditions 1093836Stmm * are met: 1193836Stmm * 1. Redistributions of source code must retain the above copyright 1293836Stmm * notice, this list of conditions and the following disclaimer. 1393836Stmm * 2. Redistributions in binary form must reproduce the above copyright 1493836Stmm * notice, this list of conditions and the following disclaimer in the 1593836Stmm * documentation and/or other materials provided with the distribution. 1693836Stmm * 3. All advertising materials mentioning features or use of this software 1793836Stmm * must display the following acknowledgement: 1893836Stmm * This product includes software developed by the NetBSD 1993836Stmm * Foundation, Inc. and its contributors. 2093836Stmm * 4. Neither the name of The NetBSD Foundation nor the names of its 2193836Stmm * contributors may be used to endorse or promote products derived 2293836Stmm * from this software without specific prior written permission. 2393836Stmm * 2493836Stmm * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2593836Stmm * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2693836Stmm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2793836Stmm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2893836Stmm * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2993836Stmm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3093836Stmm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3193836Stmm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3293836Stmm * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3393836Stmm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3493836Stmm * POSSIBILITY OF SUCH DAMAGE. 3593836Stmm * 3693836Stmm * $NetBSD: mk48txx.c,v 1.7 2001/04/08 17:05:10 tsutsui Exp $ 3793836Stmm * 3893836Stmm * $FreeBSD: head/sys/dev/mk48txx/mk48txx.c 119352 2003-08-23 05:56:58Z marcel $ 3993836Stmm */ 4093836Stmm 4193836Stmm/* 4293836Stmm * Mostek MK48T02, MK48T08, MK48T59 time-of-day chip subroutines. 4393836Stmm */ 4493836Stmm 4593836Stmm#include <sys/param.h> 4693836Stmm#include <sys/systm.h> 4793836Stmm#include <sys/bus.h> 4893836Stmm#include <sys/clock.h> 4993836Stmm#include <sys/malloc.h> 5093836Stmm 5193836Stmm#include <machine/bus.h> 5293836Stmm 53119352Smarcel#include <dev/mk48txx/mk48txxreg.h> 5493836Stmm 5593836Stmm#include "clock_if.h" 5693836Stmm 5793836Stmmstruct mk48txx_softc { 5893836Stmm bus_space_tag_t mk_bt; /* bus tag & handle */ 5993836Stmm bus_space_handle_t mk_bh; /* */ 6093836Stmm bus_size_t mk_nvramsz; /* Size of NVRAM on the chip */ 6193836Stmm bus_size_t mk_clkoffset; /* Offset in NVRAM to clock bits */ 6293836Stmm u_int mk_year0; /* What year is represented on the system 6393836Stmm by the chip's year counter at 0 */ 6493836Stmm}; 6593836Stmm 6693836Stmmint mk48txx_auto_century_adjust = 1; 6793836Stmm 6893836Stmmstruct { 6993836Stmm const char *name; 7093836Stmm bus_size_t nvramsz; 7193836Stmm bus_size_t clkoff; 7293836Stmm int flags; 7393836Stmm#define MK48TXX_EXT_REGISTERS 1 /* Has extended register set */ 7493836Stmm} mk48txx_models[] = { 7593836Stmm { "mk48t02", MK48T02_CLKSZ, MK48T02_CLKOFF, 0 }, 7693836Stmm { "mk48t08", MK48T08_CLKSZ, MK48T08_CLKOFF, 0 }, 7793836Stmm { "mk48t59", MK48T59_CLKSZ, MK48T59_CLKOFF, MK48TXX_EXT_REGISTERS }, 7893836Stmm}; 7993836Stmm 8093836Stmmint 8193836Stmmmk48txx_attach(device_t dev, bus_space_tag_t bt, bus_space_handle_t bh, 8293836Stmm const char *model, int year0) 8393836Stmm{ 8493836Stmm struct mk48txx_softc *sc; 8593836Stmm bus_size_t clkoff = 0, nvramsz = 0; 8693836Stmm int i; 8793836Stmm 8893836Stmm device_printf(dev, "model %s", model); 8993836Stmm i = sizeof(mk48txx_models) / sizeof(mk48txx_models[0]); 9093836Stmm while (--i >= 0) { 9193836Stmm if (strcmp(model, mk48txx_models[i].name) == 0) { 9293836Stmm nvramsz = mk48txx_models[i].nvramsz; 9393836Stmm clkoff = mk48txx_models[i].clkoff; 9493836Stmm break; 9593836Stmm } 9693836Stmm } 9793836Stmm if (i < 0) { 9893836Stmm device_printf(dev, " (unsupported)\n"); 9993836Stmm return (ENXIO); 10093836Stmm } 10193836Stmm printf("\n"); 10293836Stmm 10393836Stmm sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT); 10493836Stmm sc->mk_bt = bt; 10593836Stmm sc->mk_bh = bh; 10693836Stmm sc->mk_nvramsz = nvramsz; 10793836Stmm sc->mk_clkoffset = clkoff; 10893836Stmm sc->mk_year0 = year0; 10993836Stmm device_set_softc(dev, sc); 11093836Stmm clock_register(dev, 1000000); /* 1 second resolution. */ 11193836Stmm 11293836Stmm return (0); 11393836Stmm} 11493836Stmm 11593836Stmm/* 11693836Stmm * Get time-of-day and convert to a `struct timespec' 11793836Stmm * Return 0 on success; an error number otherwise. 11893836Stmm */ 11993836Stmmint 12093836Stmmmk48txx_gettime(device_t dev, struct timespec *ts) 12193836Stmm{ 12293836Stmm struct mk48txx_softc *mk = device_get_softc(dev); 12393836Stmm bus_space_tag_t bt = mk->mk_bt; 12493836Stmm bus_space_handle_t bh = mk->mk_bh; 12593836Stmm bus_size_t clkoff = mk->mk_clkoffset; 12693836Stmm struct clocktime ct; 12793836Stmm int year; 12893836Stmm u_int8_t csr; 12993836Stmm 13093836Stmm /* enable read (stop time) */ 13193836Stmm csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 13293836Stmm csr |= MK48TXX_CSR_READ; 13393836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 13493836Stmm 13593836Stmm ct.nsec = 0; 13693836Stmm ct.sec = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_ISEC)); 13793836Stmm ct.min = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMIN)); 13893836Stmm ct.hour = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IHOUR)); 13993836Stmm ct.day = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IDAY)); 14093836Stmm ct.dow = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IWDAY)) % 7; 14193836Stmm ct.mon = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IMON)); 14293836Stmm year = FROMBCD(bus_space_read_1(bt, bh, clkoff + MK48TXX_IYEAR)); 14393836Stmm 14493836Stmm year += mk->mk_year0; 14593836Stmm if (year < POSIX_BASE_YEAR && mk48txx_auto_century_adjust != 0) 14693836Stmm year += 100; 14793836Stmm 14893836Stmm ct.year = year; 14993836Stmm 15093836Stmm /* time wears on */ 15193836Stmm csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 15293836Stmm csr &= ~MK48TXX_CSR_READ; 15393836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 15493836Stmm 15593836Stmm return (clock_ct_to_ts(&ct, ts)); 15693836Stmm} 15793836Stmm 15893836Stmm/* 15993836Stmm * Set the time-of-day clock based on the value of the `struct timespec' arg. 16093836Stmm * Return 0 on success; an error number otherwise. 16193836Stmm */ 16293836Stmmint 16393836Stmmmk48txx_settime(device_t dev, struct timespec *ts) 16493836Stmm{ 16593836Stmm struct mk48txx_softc *mk = device_get_softc(dev); 16693836Stmm bus_space_tag_t bt = mk->mk_bt; 16793836Stmm bus_space_handle_t bh = mk->mk_bh; 16893836Stmm bus_size_t clkoff = mk->mk_clkoffset; 16993836Stmm struct clocktime ct; 17093836Stmm u_int8_t csr; 17193836Stmm int year; 17293836Stmm 17393836Stmm /* Accuracy is only one second. */ 17493836Stmm if (ts->tv_nsec >= 500000000) 17593836Stmm ts->tv_sec++; 17693836Stmm ts->tv_nsec = 0; 17793836Stmm clock_ts_to_ct(ts, &ct); 17893836Stmm 17993836Stmm year = ct.year - mk->mk_year0; 18093836Stmm if (year > 99 && mk48txx_auto_century_adjust != 0) 18193836Stmm year -= 100; 18293836Stmm 18393836Stmm /* enable write */ 18493836Stmm csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 18593836Stmm csr |= MK48TXX_CSR_WRITE; 18693836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 18793836Stmm 18893836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_ISEC, TOBCD(ct.sec)); 18993836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_IMIN, TOBCD(ct.min)); 19093836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_IHOUR, TOBCD(ct.hour)); 19193836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_IWDAY, TOBCD(ct.dow)); 19293836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_IDAY, TOBCD(ct.day)); 19393836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_IMON, TOBCD(ct.mon)); 19493836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_IYEAR, TOBCD(year)); 19593836Stmm 19693836Stmm /* load them up */ 19793836Stmm csr = bus_space_read_1(bt, bh, clkoff + MK48TXX_ICSR); 19893836Stmm csr &= ~MK48TXX_CSR_WRITE; 19993836Stmm bus_space_write_1(bt, bh, clkoff + MK48TXX_ICSR, csr); 20093836Stmm return (0); 20193836Stmm} 20293836Stmm 20393836Stmmint 20493836Stmmmk48txx_get_nvram_size(device_t dev, bus_size_t *vp) 20593836Stmm{ 20693836Stmm struct mk48txx_softc *mk; 20793836Stmm 20893836Stmm mk = device_get_softc(dev); 20993836Stmm *vp = mk->mk_nvramsz; 21093836Stmm return (0); 21193836Stmm} 212