1 /*- 2 * Copyright (C) 2006-2008 Semihalf, Grzegorz Bernacki 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/bus.h> 34 #include <sys/clock.h> 35 #include <sys/lock.h> 36 #include <sys/mutex.h> 37 38 #include <machine/bus.h> 39 40 #include <powerpc/mpc85xx/ds1553_reg.h> 41 42 static uint8_t ds1553_direct_read(device_t, bus_size_t); 43 static void ds1553_direct_write(device_t, bus_size_t, uint8_t); 44 45 int 46 ds1553_attach(device_t dev) 47 { 48 struct ds1553_softc *sc; 49 uint8_t sec, flags; 50 51 sc = device_get_softc(dev); 52 53 if (mtx_initialized(&sc->sc_mtx) == 0) { 54 device_printf(dev, "%s: mutex not initialized\n", __func__); 55 return (ENXIO); 56 } 57 58 if (sc->sc_read == NULL) 59 sc->sc_read = ds1553_direct_read; 60 if (sc->sc_write == NULL) 61 sc->sc_write = ds1553_direct_write; 62 63 sc->year_offset = POSIX_BASE_YEAR; 64 65 mtx_lock_spin(&sc->sc_mtx); 66 67 /* Turn RTC on if it was not on */ 68 sec = (*sc->sc_read)(dev, DS1553_OFF_SECONDS); 69 if (sec & DS1553_BIT_OSC) { 70 sec &= ~(DS1553_BIT_OSC); 71 (*sc->sc_write)(dev, DS1553_OFF_SECONDS, sec); 72 } 73 74 /* Low-battery check */ 75 flags = (*sc->sc_read)(dev, DS1553_OFF_FLAGS); 76 if (flags & DS1553_BIT_BLF) 77 device_printf(dev, "voltage-low detected.\n"); 78 79 mtx_unlock_spin(&sc->sc_mtx); 80 81 return (0); 82 } 83 84 /* 85 * Get time of day and convert it to a struct timespec. 86 * Return 0 on success, an error number otherwise. 87 */ 88 int 89 ds1553_gettime(device_t dev, struct timespec *ts) 90 { 91 struct clocktime ct; 92 struct ds1553_softc *sc; 93 uint8_t control; 94 95 sc = device_get_softc(dev); 96 97 mtx_lock_spin(&sc->sc_mtx); 98 99 control = (*sc->sc_read)(dev, DS1553_OFF_CONTROL) | DS1553_BIT_READ; 100 (*sc->sc_write)(dev, DS1553_OFF_CONTROL, control); 101 102 ct.nsec = 0; 103 ct.sec = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_SECONDS) & 104 DS1553_MASK_SECONDS); 105 ct.min = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_MINUTES) & 106 DS1553_MASK_MINUTES); 107 ct.hour = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_HOURS) & 108 DS1553_MASK_HOUR); 109 ct.dow = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_DAYOFWEEK) & 110 DS1553_MASK_DAYOFWEEK) - 1; 111 ct.day = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_DATE) & 112 DS1553_MASK_DATE); 113 ct.mon = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_MONTH) & 114 DS1553_MASK_MONTH); 115 ct.year = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_YEAR)); 116 117 control &= ~DS1553_BIT_READ; 118 (*sc->sc_write)(dev, DS1553_OFF_CONTROL, control); 119 120 ct.year += sc->year_offset; 121 122 mtx_unlock_spin(&sc->sc_mtx); 123 124 return (clock_ct_to_ts(&ct, ts)); 125 } 126 127 /* 128 * Set the time of day clock based on the value of the struct timespec arg. 129 * Return 0 on success, an error number otherwise. 130 */ 131 int 132 ds1553_settime(device_t dev, struct timespec *ts) 133 { 134 struct clocktime ct; 135 struct ds1553_softc *sc; 136 uint8_t control; 137 138 sc = device_get_softc(dev); 139 bzero(&ct, sizeof(struct clocktime)); 140 141 /* Accuracy is only one second. */ 142 if (ts->tv_nsec >= 500000000) 143 ts->tv_sec++; 144 ts->tv_nsec = 0; 145 clock_ts_to_ct(ts, &ct); 146 147 ct.year -= sc->year_offset; 148 149 mtx_lock_spin(&sc->sc_mtx); 150 151 /* Halt updates to external registers */ 152 control = (*sc->sc_read)(dev, DS1553_OFF_CONTROL) | DS1553_BIT_WRITE; 153 (*sc->sc_write)(dev, DS1553_OFF_CONTROL, control); 154 155 (*sc->sc_write)(dev, DS1553_OFF_SECONDS, TOBCD(ct.sec) & 156 DS1553_MASK_SECONDS); 157 (*sc->sc_write)(dev, DS1553_OFF_MINUTES, TOBCD(ct.min) & 158 DS1553_MASK_MINUTES); 159 (*sc->sc_write)(dev, DS1553_OFF_HOURS, TOBCD(ct.hour) & 160 DS1553_MASK_HOUR); 161 (*sc->sc_write)(dev, DS1553_OFF_DAYOFWEEK, TOBCD(ct.dow + 1) & 162 DS1553_MASK_DAYOFWEEK); 163 (*sc->sc_write)(dev, DS1553_OFF_DATE, TOBCD(ct.day) & 164 DS1553_MASK_DATE); 165 (*sc->sc_write)(dev, DS1553_OFF_MONTH, TOBCD(ct.mon) & 166 DS1553_MASK_MONTH); 167 (*sc->sc_write)(dev, DS1553_OFF_YEAR, TOBCD(ct.year)); 168 169 /* Resume updates to external registers */ 170 control &= ~DS1553_BIT_WRITE; 171 (*sc->sc_write)(dev, DS1553_OFF_CONTROL, control); 172 173 mtx_unlock_spin(&sc->sc_mtx); 174 175 return (0); 176 } 177 178 static uint8_t 179 ds1553_direct_read(device_t dev, bus_size_t off) 180 { 181 struct ds1553_softc *sc; 182 183 sc = device_get_softc(dev); 184 return (bus_space_read_1(sc->sc_bst, sc->sc_bsh, off)); 185 } 186 187 static void 188 ds1553_direct_write(device_t dev, bus_size_t off, uint8_t val) 189 { 190 struct ds1553_softc *sc; 191 192 sc = device_get_softc(dev); 193 bus_space_write_1(sc->sc_bst, sc->sc_bsh, off, val); 194 } 195