1194632Sraj/*- 2194632Sraj * Copyright (C) 2006-2008 Semihalf, Grzegorz Bernacki 3194632Sraj * All rights reserved. 4194632Sraj * 5194632Sraj * Redistribution and use in source and binary forms, with or without 6194632Sraj * modification, are permitted provided that the following conditions 7194632Sraj * are met: 8194632Sraj * 1. Redistributions of source code must retain the above copyright 9194632Sraj * notice, this list of conditions and the following disclaimer. 10194632Sraj * 2. Redistributions in binary form must reproduce the above copyright 11194632Sraj * notice, this list of conditions and the following disclaimer in the 12194632Sraj * documentation and/or other materials provided with the distribution. 13194632Sraj * 14194632Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194632Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194632Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194632Sraj * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18194632Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194632Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194632Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194632Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194632Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194632Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194632Sraj * SUCH DAMAGE. 25194632Sraj * 26194632Sraj */ 27194632Sraj 28194632Sraj#include <sys/cdefs.h> 29194632Sraj__FBSDID("$FreeBSD$"); 30194632Sraj 31194632Sraj#include <sys/param.h> 32194632Sraj#include <sys/systm.h> 33194632Sraj#include <sys/bus.h> 34194632Sraj#include <sys/clock.h> 35194632Sraj#include <sys/lock.h> 36194632Sraj#include <sys/mutex.h> 37194632Sraj 38194632Sraj#include <machine/bus.h> 39194632Sraj 40194632Sraj#include <powerpc/mpc85xx/ds1553_reg.h> 41194632Sraj 42194632Srajstatic uint8_t ds1553_direct_read(device_t, bus_size_t); 43194632Srajstatic void ds1553_direct_write(device_t, bus_size_t, uint8_t); 44194632Sraj 45194632Srajint 46194632Srajds1553_attach(device_t dev) 47194632Sraj{ 48194632Sraj struct ds1553_softc *sc; 49194632Sraj uint8_t sec, flags; 50194632Sraj 51194632Sraj sc = device_get_softc(dev); 52194632Sraj 53194632Sraj if (mtx_initialized(&sc->sc_mtx) == 0) { 54194632Sraj device_printf(dev, "%s: mutex not initialized\n", __func__); 55194632Sraj return (ENXIO); 56194632Sraj } 57194632Sraj 58194632Sraj if (sc->sc_read == NULL) 59194632Sraj sc->sc_read = ds1553_direct_read; 60194632Sraj if (sc->sc_write == NULL) 61194632Sraj sc->sc_write = ds1553_direct_write; 62194632Sraj 63194632Sraj sc->year_offset = POSIX_BASE_YEAR; 64194632Sraj 65194632Sraj mtx_lock_spin(&sc->sc_mtx); 66194632Sraj 67194632Sraj /* Turn RTC on if it was not on */ 68194632Sraj sec = (*sc->sc_read)(dev, DS1553_OFF_SECONDS); 69194632Sraj if (sec & DS1553_BIT_OSC) { 70194632Sraj sec &= ~(DS1553_BIT_OSC); 71194632Sraj (*sc->sc_write)(dev, DS1553_OFF_SECONDS, sec); 72194632Sraj } 73194632Sraj 74194632Sraj /* Low-battery check */ 75194632Sraj flags = (*sc->sc_read)(dev, DS1553_OFF_FLAGS); 76194632Sraj if (flags & DS1553_BIT_BLF) 77194632Sraj device_printf(dev, "voltage-low detected.\n"); 78194632Sraj 79194632Sraj mtx_unlock_spin(&sc->sc_mtx); 80194632Sraj 81194632Sraj return (0); 82194632Sraj} 83194632Sraj 84194632Sraj/* 85194632Sraj * Get time of day and convert it to a struct timespec. 86194632Sraj * Return 0 on success, an error number otherwise. 87194632Sraj */ 88194632Srajint 89194632Srajds1553_gettime(device_t dev, struct timespec *ts) 90194632Sraj{ 91194632Sraj struct clocktime ct; 92194632Sraj struct ds1553_softc *sc; 93194632Sraj uint8_t control; 94194632Sraj 95194632Sraj sc = device_get_softc(dev); 96194632Sraj 97194632Sraj mtx_lock_spin(&sc->sc_mtx); 98194632Sraj 99194632Sraj control = (*sc->sc_read)(dev, DS1553_OFF_CONTROL) | DS1553_BIT_READ; 100194632Sraj (*sc->sc_write)(dev, DS1553_OFF_CONTROL, control); 101194632Sraj 102194632Sraj ct.nsec = 0; 103194632Sraj ct.sec = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_SECONDS) & 104194632Sraj DS1553_MASK_SECONDS); 105194632Sraj ct.min = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_MINUTES) & 106194632Sraj DS1553_MASK_MINUTES); 107194632Sraj ct.hour = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_HOURS) & 108194632Sraj DS1553_MASK_HOUR); 109194632Sraj ct.dow = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_DAYOFWEEK) & 110194632Sraj DS1553_MASK_DAYOFWEEK) - 1; 111194632Sraj ct.day = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_DATE) & 112194632Sraj DS1553_MASK_DATE); 113194632Sraj ct.mon = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_MONTH) & 114194632Sraj DS1553_MASK_MONTH); 115194632Sraj ct.year = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_YEAR)); 116194632Sraj 117194632Sraj control &= ~DS1553_BIT_READ; 118194632Sraj (*sc->sc_write)(dev, DS1553_OFF_CONTROL, control); 119194632Sraj 120194632Sraj ct.year += sc->year_offset; 121194632Sraj 122194632Sraj mtx_unlock_spin(&sc->sc_mtx); 123194632Sraj 124194632Sraj return (clock_ct_to_ts(&ct, ts)); 125194632Sraj} 126194632Sraj 127194632Sraj/* 128194632Sraj * Set the time of day clock based on the value of the struct timespec arg. 129194632Sraj * Return 0 on success, an error number otherwise. 130194632Sraj */ 131194632Srajint 132194632Srajds1553_settime(device_t dev, struct timespec *ts) 133194632Sraj{ 134194632Sraj struct clocktime ct; 135194632Sraj struct ds1553_softc *sc; 136194632Sraj uint8_t control; 137194632Sraj 138194632Sraj sc = device_get_softc(dev); 139194632Sraj bzero(&ct, sizeof(struct clocktime)); 140194632Sraj 141194632Sraj /* Accuracy is only one second. */ 142194632Sraj if (ts->tv_nsec >= 500000000) 143194632Sraj ts->tv_sec++; 144194632Sraj ts->tv_nsec = 0; 145194632Sraj clock_ts_to_ct(ts, &ct); 146194632Sraj 147194632Sraj ct.year -= sc->year_offset; 148194632Sraj 149194632Sraj mtx_lock_spin(&sc->sc_mtx); 150194632Sraj 151194632Sraj /* Halt updates to external registers */ 152194632Sraj control = (*sc->sc_read)(dev, DS1553_OFF_CONTROL) | DS1553_BIT_WRITE; 153194632Sraj (*sc->sc_write)(dev, DS1553_OFF_CONTROL, control); 154194632Sraj 155194632Sraj (*sc->sc_write)(dev, DS1553_OFF_SECONDS, TOBCD(ct.sec) & 156194632Sraj DS1553_MASK_SECONDS); 157194632Sraj (*sc->sc_write)(dev, DS1553_OFF_MINUTES, TOBCD(ct.min) & 158194632Sraj DS1553_MASK_MINUTES); 159194632Sraj (*sc->sc_write)(dev, DS1553_OFF_HOURS, TOBCD(ct.hour) & 160194632Sraj DS1553_MASK_HOUR); 161194632Sraj (*sc->sc_write)(dev, DS1553_OFF_DAYOFWEEK, TOBCD(ct.dow + 1) & 162194632Sraj DS1553_MASK_DAYOFWEEK); 163194632Sraj (*sc->sc_write)(dev, DS1553_OFF_DATE, TOBCD(ct.day) & 164194632Sraj DS1553_MASK_DATE); 165194632Sraj (*sc->sc_write)(dev, DS1553_OFF_MONTH, TOBCD(ct.mon) & 166194632Sraj DS1553_MASK_MONTH); 167194632Sraj (*sc->sc_write)(dev, DS1553_OFF_YEAR, TOBCD(ct.year)); 168194632Sraj 169194632Sraj /* Resume updates to external registers */ 170194632Sraj control &= ~DS1553_BIT_WRITE; 171194632Sraj (*sc->sc_write)(dev, DS1553_OFF_CONTROL, control); 172194632Sraj 173194632Sraj mtx_unlock_spin(&sc->sc_mtx); 174194632Sraj 175194632Sraj return (0); 176194632Sraj} 177194632Sraj 178194632Srajstatic uint8_t 179194632Srajds1553_direct_read(device_t dev, bus_size_t off) 180194632Sraj{ 181194632Sraj struct ds1553_softc *sc; 182194632Sraj 183194632Sraj sc = device_get_softc(dev); 184194632Sraj return (bus_space_read_1(sc->sc_bst, sc->sc_bsh, off)); 185194632Sraj} 186194632Sraj 187194632Srajstatic void 188194632Srajds1553_direct_write(device_t dev, bus_size_t off, uint8_t val) 189194632Sraj{ 190194632Sraj struct ds1553_softc *sc; 191194632Sraj 192194632Sraj sc = device_get_softc(dev); 193194632Sraj bus_space_write_1(sc->sc_bst, sc->sc_bsh, off, val); 194194632Sraj} 195