1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2017 Hiroki Mori. All rights reserved. 5 * Copyright (c) 2017 Ian Lepore. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * This code base on isl12xx.c 28 */ 29 30 #include <sys/cdefs.h> 31 /* 32 * Driver for realtime clock EPSON RTC-8583 33 */ 34 35 #include "opt_platform.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/bus.h> 40 #include <sys/clock.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/module.h> 44 45 #ifdef FDT 46 #include <dev/ofw/ofw_bus.h> 47 #include <dev/ofw/ofw_bus_subr.h> 48 #endif 49 50 #include <dev/iicbus/iiconf.h> 51 #include <dev/iicbus/iicbus.h> 52 53 #include "clock_if.h" 54 #include "iicbus_if.h" 55 56 #define RTC8583_SC_REG 0x01 /* RTC Seconds */ 57 #define RTC8583_USERSRAM_REG 0x10 /* User SRAM register (first) */ 58 #define MAX_TRANSFER 16 59 60 /* 61 * A struct laid out in the same order as the time registers in the chip. 62 */ 63 struct time_regs { 64 uint8_t msec, sec, min, hour, day, month; 65 }; 66 67 struct rtc8583_softc { 68 device_t dev; 69 device_t busdev; 70 struct intr_config_hook 71 init_hook; 72 }; 73 74 #ifdef FDT 75 static struct ofw_compat_data compat_data[] = { 76 {"epson,rtc8583", 1}, 77 {NULL, 0}, 78 }; 79 #endif 80 81 static void rtc8583_init(void *arg); 82 static int rtc8583_probe(device_t dev); 83 static int rtc8583_attach(device_t dev); 84 static int rtc8583_detach(device_t dev); 85 86 static int rtc8583_gettime(device_t dev, struct timespec *ts); 87 static int rtc8583_settime(device_t dev, struct timespec *ts); 88 89 static int rtc8583_writeto(device_t slavedev, uint8_t regaddr, 90 void *buffer, uint16_t buflen, int waithow); 91 92 /* Implementation */ 93 94 static int 95 rtc8583_writeto(device_t slavedev, uint8_t regaddr, void *buffer, 96 uint16_t buflen, int waithow) 97 { 98 struct iic_msg msgs; 99 uint8_t slaveaddr; 100 uint8_t newbuf[MAX_TRANSFER]; 101 102 slaveaddr = iicbus_get_addr(slavedev); 103 104 newbuf[0] = regaddr; 105 memcpy(newbuf + 1, buffer, buflen); 106 msgs.slave = slaveaddr; 107 msgs.flags = IIC_M_WR; 108 msgs.len = 1 + buflen; 109 msgs.buf = newbuf; 110 111 return (iicbus_transfer_excl(slavedev, &msgs, 1, waithow)); 112 } 113 114 static inline int 115 rtc8583_read1(struct rtc8583_softc *sc, uint8_t reg, uint8_t *data) 116 { 117 118 return (iicdev_readfrom(sc->dev, reg, data, 1, IIC_WAIT)); 119 } 120 121 static inline int 122 rtc8583_write1(struct rtc8583_softc *sc, uint8_t reg, uint8_t val) 123 { 124 125 return (rtc8583_writeto(sc->dev, reg, &val, 1, IIC_WAIT)); 126 } 127 128 static void 129 rtc8583_init(void *arg) 130 { 131 struct rtc8583_softc *sc; 132 133 sc = (struct rtc8583_softc*)arg; 134 config_intrhook_disestablish(&sc->init_hook); 135 136 /* 137 * Register as a system realtime clock. 138 */ 139 clock_register_flags(sc->dev, 1000000, CLOCKF_SETTIME_NO_ADJ); 140 clock_schedule(sc->dev, 1); 141 return; 142 } 143 144 static int 145 rtc8583_probe(device_t dev) 146 { 147 148 #ifdef FDT 149 if (!ofw_bus_status_okay(dev)) 150 return (ENXIO); 151 152 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 153 device_set_desc(dev, "EPSON RTC-8583"); 154 return (BUS_PROBE_DEFAULT); 155 } 156 #endif 157 return (ENXIO); 158 } 159 160 static int 161 rtc8583_attach(device_t dev) 162 { 163 struct rtc8583_softc *sc; 164 165 sc = device_get_softc(dev); 166 sc->dev = dev; 167 sc->busdev = device_get_parent(sc->dev); 168 169 /* 170 * Chip init must wait until interrupts are enabled. Often i2c access 171 * works only when the interrupts are available. 172 */ 173 sc->init_hook.ich_func = rtc8583_init; 174 sc->init_hook.ich_arg = sc; 175 if (config_intrhook_establish(&sc->init_hook) != 0) 176 return (ENOMEM); 177 178 return (0); 179 } 180 181 static int 182 rtc8583_detach(device_t dev) 183 { 184 185 clock_unregister(dev); 186 return (0); 187 } 188 189 static int 190 rtc8583_gettime(device_t dev, struct timespec *ts) 191 { 192 struct rtc8583_softc *sc; 193 struct bcd_clocktime bct; 194 struct time_regs tregs; 195 uint8_t y, ytmp, sreg; 196 int err; 197 198 sc = device_get_softc(dev); 199 200 /* Read the bcd time registers. */ 201 if ((err = iicdev_readfrom(sc->dev, RTC8583_SC_REG, &tregs, sizeof(tregs), 202 IIC_WAIT)) != 0) 203 return (err); 204 205 y = tregs.day >> 6; 206 /* Get year from user SRAM */ 207 rtc8583_read1(sc, RTC8583_USERSRAM_REG, &sreg); 208 209 /* 210 * Check if year adjustment is required. 211 * RTC has only 2 bits for year value (i.e. maximum is 4 years), so 212 * full year value is stored in user SRAM and updated manually or 213 * by this code. 214 */ 215 ytmp = sreg & 0x03; 216 if (ytmp != y) { 217 /* shift according to difference */ 218 sreg += y - ytmp; 219 220 /* check if overflow happened */ 221 if (ytmp > y) 222 sreg += 4; 223 224 if ((err = iicbus_request_bus(sc->busdev, sc->dev, IIC_WAIT)) != 0) 225 return (err); 226 rtc8583_write1(sc, RTC8583_USERSRAM_REG, sreg); 227 iicbus_release_bus(sc->busdev, sc->dev); 228 } 229 230 if (!validbcd(tregs.msec)) 231 return (EINVAL); 232 233 /* The 'msec' reg is actually 1/100ths, in bcd. */ 234 bct.nsec = bcd2bin(tregs.msec) * 10 * 1000 * 1000; 235 bct.sec = tregs.sec; 236 bct.min = tregs.min; 237 bct.hour = tregs.hour & 0x3f; 238 bct.day = tregs.day & 0x3f; 239 bct.mon = tregs.month & 0x1f; 240 bct.year = bin2bcd(sreg % 100); 241 242 clock_dbgprint_bcd(sc->dev, CLOCK_DBG_READ, &bct); 243 return (clock_bcd_to_ts(&bct, ts, false)); 244 } 245 246 static int 247 rtc8583_settime(device_t dev, struct timespec *ts) 248 { 249 struct rtc8583_softc *sc; 250 struct bcd_clocktime bct; 251 struct time_regs tregs; 252 uint8_t sreg; 253 int err; 254 255 sc = device_get_softc(dev); 256 ts->tv_sec -= utc_offset(); 257 clock_ts_to_bcd(ts, &bct, false); 258 clock_dbgprint_bcd(sc->dev, CLOCK_DBG_WRITE, &bct); 259 260 /* The 'msec' reg is actually 1/100ths, in bcd. */ 261 tregs.msec = bin2bcd(ts->tv_nsec / (10 * 1000 * 1000)); 262 tregs.sec = bct.sec; 263 tregs.min = bct.min; 264 tregs.hour = bct.hour; 265 tregs.day = bct.day | (bct.year & 0x03 << 6); 266 tregs.month = bct.mon; 267 268 if ((err = iicbus_request_bus(sc->busdev, sc->dev, IIC_WAIT)) != 0) 269 return (err); 270 err = rtc8583_writeto(sc->dev, RTC8583_SC_REG, &tregs, 271 sizeof(tregs), IIC_WAIT); 272 sreg = bcd2bin(bct.year & 0xff); 273 /* save to year to sram */ 274 rtc8583_write1(sc, RTC8583_USERSRAM_REG, sreg); 275 iicbus_release_bus(sc->busdev, sc->dev); 276 277 return (err); 278 } 279 280 static device_method_t rtc8583_methods[] = { 281 /* device_if methods */ 282 DEVMETHOD(device_probe, rtc8583_probe), 283 DEVMETHOD(device_attach, rtc8583_attach), 284 DEVMETHOD(device_detach, rtc8583_detach), 285 286 /* clock_if methods */ 287 DEVMETHOD(clock_gettime, rtc8583_gettime), 288 DEVMETHOD(clock_settime, rtc8583_settime), 289 290 DEVMETHOD_END, 291 }; 292 293 static driver_t rtc8583_driver = { 294 "rtc8583", 295 rtc8583_methods, 296 sizeof(struct rtc8583_softc), 297 }; 298 299 DRIVER_MODULE(rtc8583, iicbus, rtc8583_driver, NULL, NULL); 300 MODULE_VERSION(rtc8583, 1); 301 MODULE_DEPEND(rtc8583, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 302 IICBUS_FDT_PNP_INFO(compat_data); 303