g2rtc.c revision 1.6
11.6Sdyoung/* $NetBSD: g2rtc.c,v 1.6 2011/07/19 15:52:29 dyoung Exp $ */ 21.1Suwe 31.1Suwe/*- 41.1Suwe * Copyright (c) 2002 The NetBSD Foundation, Inc. 51.1Suwe * All rights reserved. 61.1Suwe * 71.1Suwe * Redistribution and use in source and binary forms, with or without 81.1Suwe * modification, are permitted provided that the following conditions 91.1Suwe * are met: 101.1Suwe * 1. Redistributions of source code must retain the above copyright 111.1Suwe * notice, this list of conditions and the following disclaimer. 121.1Suwe * 2. Redistributions in binary form must reproduce the above copyright 131.1Suwe * notice, this list of conditions and the following disclaimer in the 141.1Suwe * documentation and/or other materials provided with the distribution. 151.1Suwe * 161.1Suwe * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 171.1Suwe * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 181.1Suwe * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 191.1Suwe * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 201.1Suwe * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 211.1Suwe * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 221.1Suwe * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 231.1Suwe * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 241.1Suwe * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 251.1Suwe * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 261.1Suwe * POSSIBILITY OF SUCH DAMAGE. 271.1Suwe */ 281.1Suwe 291.1Suwe#include <sys/cdefs.h> 301.6Sdyoung__KERNEL_RCSID(0, "$NetBSD: g2rtc.c,v 1.6 2011/07/19 15:52:29 dyoung Exp $"); 311.1Suwe 321.1Suwe#include <sys/param.h> 331.1Suwe#include <sys/systm.h> 341.2She#include <sys/device.h> 351.6Sdyoung#include <sys/bus.h> 361.1Suwe 371.1Suwe#include <dev/clock_subr.h> 381.1Suwe 391.1Suwe#include <dreamcast/dev/g2/g2busvar.h> 401.1Suwe 411.1Suwe 421.1Suwe#define G2RTC_REG_BASE 0x00710000 431.1Suwe#define G2RTC_REG_SIZE 12 441.1Suwe 451.1Suwe/* Offset by 20 years, 5 of them are leap */ 461.1Suwe#define G2RTC_OFFSET (20 * SECYR + 5 * SECDAY) 471.1Suwe 481.1Suwestruct g2rtc_softc { 491.5Stsutsui device_t sc_dev; 501.1Suwe 511.1Suwe bus_space_tag_t sc_bt; 521.1Suwe bus_space_handle_t sc_bh; 531.5Stsutsui struct todr_chip_handle sc_tch; 541.1Suwe}; 551.1Suwe 561.1Suwe/* autoconf glue */ 571.5Stsutsuistatic int g2rtc_match(device_t, cfdata_t, void *); 581.5Stsutsuistatic void g2rtc_attach(device_t, device_t, void *); 591.1Suwe 601.5StsutsuiCFATTACH_DECL_NEW(g2rtc, sizeof(struct g2rtc_softc), 611.5Stsutsui g2rtc_match, g2rtc_attach, NULL, NULL); 621.1Suwe 631.1Suwe 641.1Suwe/* todr(9) methods */ 651.4Stsutsuistatic int g2rtc_todr_gettime(todr_chip_handle_t, struct timeval *); 661.4Stsutsuistatic int g2rtc_todr_settime(todr_chip_handle_t, struct timeval *); 671.1Suwe 681.1Suwestatic inline uint32_t g2rtc_read(bus_space_tag_t, bus_space_handle_t); 691.1Suwe 701.1Suwe 711.1Suwestatic int 721.5Stsutsuig2rtc_match(device_t parent, cfdata_t cf, void *aux) 731.1Suwe{ 741.1Suwe static int g2rtc_matched = 0; 751.1Suwe 761.1Suwe if (g2rtc_matched) 771.1Suwe return 0; 781.1Suwe 791.1Suwe g2rtc_matched = 1; 801.1Suwe return 1; 811.1Suwe} 821.1Suwe 831.1Suwe 841.1Suwestatic void 851.5Stsutsuig2rtc_attach(device_t parent, device_t self, void *aux) 861.1Suwe{ 871.5Stsutsui struct g2rtc_softc *sc = device_private(self); 881.1Suwe struct g2bus_attach_args *ga = aux; 891.5Stsutsui todr_chip_handle_t tch; 901.1Suwe 911.5Stsutsui sc->sc_dev = self; 921.1Suwe sc->sc_bt = ga->ga_memt; 931.1Suwe if (bus_space_map(sc->sc_bt, G2RTC_REG_BASE, G2RTC_REG_SIZE, 0, 941.5Stsutsui &sc->sc_bh) != 0) { 951.1Suwe printf(": unable to map registers\n"); 961.1Suwe return; 971.1Suwe } 981.1Suwe printf(": time-of-day clock\n"); 991.1Suwe 1001.5Stsutsui tch = &sc->sc_tch; 1011.5Stsutsui tch->cookie = sc; 1021.5Stsutsui tch->todr_gettime = g2rtc_todr_gettime, 1031.5Stsutsui tch->todr_settime = g2rtc_todr_settime, 1041.5Stsutsui todr_attach(tch); 1051.1Suwe} 1061.1Suwe 1071.1Suwe 1081.1Suwestatic inline uint32_t 1091.1Suweg2rtc_read(bus_space_tag_t bt, bus_space_handle_t bh) 1101.1Suwe{ 1111.1Suwe 1121.1Suwe return ((bus_space_read_4(bt, bh, 0) & 0xffff) << 16) 1131.5Stsutsui | (bus_space_read_4(bt, bh, 4) & 0xffff); 1141.1Suwe} 1151.1Suwe 1161.1Suwe 1171.1Suwe/* 1181.1Suwe * Get time-of-day and convert to `struct timeval'. 1191.1Suwe * Return 0 on success; an error number otherwise. 1201.1Suwe */ 1211.1Suwestatic int 1221.4Stsutsuig2rtc_todr_gettime(todr_chip_handle_t handle, struct timeval *tv) 1231.1Suwe{ 1241.1Suwe struct g2rtc_softc *sc = handle->cookie; 1251.1Suwe uint32_t new, old; 1261.1Suwe int i; 1271.1Suwe 1281.1Suwe for (old = 0;;) { 1291.1Suwe for (i = 0; i < 3; i++) { 1301.1Suwe new = g2rtc_read(sc->sc_bt, sc->sc_bh); 1311.1Suwe if (new != old) 1321.1Suwe break; 1331.1Suwe } 1341.1Suwe if (i < 3) 1351.1Suwe old = new; 1361.1Suwe else 1371.1Suwe break; 1381.1Suwe } 1391.1Suwe 1401.1Suwe tv->tv_sec = new - G2RTC_OFFSET; 1411.1Suwe tv->tv_usec = 0; 1421.1Suwe 1431.1Suwe return 0; 1441.1Suwe} 1451.1Suwe 1461.1Suwe 1471.1Suwe/* 1481.1Suwe * Set the time-of-day clock based on the value of the `struct timeval' arg. 1491.1Suwe * Return 0 on success; an error number otherwise. 1501.1Suwe */ 1511.1Suwestatic int 1521.4Stsutsuig2rtc_todr_settime(todr_chip_handle_t handle, struct timeval *tv) 1531.1Suwe{ 1541.1Suwe struct g2rtc_softc *sc = handle->cookie; 1551.1Suwe uint32_t secs; 1561.1Suwe int i, retry; 1571.1Suwe 1581.1Suwe secs = (uint32_t)tv->tv_sec + G2RTC_OFFSET; 1591.1Suwe 1601.1Suwe for (retry = 0; retry < 5; retry++) { 1611.1Suwe 1621.1Suwe /* Don't change the order */ 1631.1Suwe bus_space_write_4(sc->sc_bt, sc->sc_bh, 8, 1); 1641.1Suwe bus_space_write_4(sc->sc_bt, sc->sc_bh, 4, secs & 0xffff); 1651.1Suwe bus_space_write_4(sc->sc_bt, sc->sc_bh, 0, secs >> 16); 1661.1Suwe 1671.1Suwe /* verify */ 1681.1Suwe for (i = 0; i < 3; i++) 1691.1Suwe if (g2rtc_read(sc->sc_bt, sc->sc_bh) == secs) 1701.1Suwe return 0; /* ok */ 1711.1Suwe } 1721.1Suwe 1731.1Suwe return EIO; 1741.1Suwe} 175