1 /*- 2 * Copyright (c) 2017 Hiroki Mori. All rights reserved. 3 * Copyright (c) 2017 Ian Lepore. 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 ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * This code base on isl12xx.c 26 */ 27 28 #include <sys/cdefs.h> 29 /* 30 * Driver for realtime clock HAOYU HYM8563 31 */ 32 33 #include "opt_platform.h" 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/bus.h> 38 #include <sys/clock.h> 39 #include <sys/kernel.h> 40 #include <sys/lock.h> 41 #include <sys/module.h> 42 43 #ifdef FDT 44 #include <dev/ofw/ofw_bus.h> 45 #include <dev/ofw/ofw_bus_subr.h> 46 #endif 47 48 #include <dev/iicbus/iiconf.h> 49 #include <dev/iicbus/iicbus.h> 50 51 #include "clock_if.h" 52 #include "iicbus_if.h" 53 54 /* Registers */ 55 #define HYM8563_CTRL1 0x00 56 #define HYM8563_CTRL1_TEST (1 << 7) 57 #define HYM8563_CTRL1_STOP (1 << 5) 58 #define HYM8563_CTRL1_TESTC (1 << 3) 59 60 #define HYM8563_CTRL2 0x01 61 #define HYM8563_CTRL2_TI_TP (1 << 4) 62 #define HYM8563_CTRL2_AF (1 << 3) 63 #define HYM8563_CTRL2_TF (1 << 2) 64 #define HYM8563_CTRL2_AIE (1 << 1) 65 #define HYM8563_CTRL2_TIE (1 << 0) 66 67 #define HYM8563_SEC 0x02 /* plus battery low bit */ 68 #define HYM8563_SEC_VL (1 << 7) 69 70 #define HYM8563_MIN 0x03 71 #define HYM8563_HOUR 0x04 72 #define HYM8563_DAY 0x05 73 #define HYM8563_WEEKDAY 0x06 74 #define HYM8563_MONTH 0x07 /* plus 1 bit for century */ 75 #define HYM8563_MONTH_CENTURY (1 << 7) 76 #define HYM8563_YEAR 0x08 77 78 struct hym8563_softc { 79 device_t dev; 80 struct intr_config_hook init_hook; 81 }; 82 83 #ifdef FDT 84 static struct ofw_compat_data compat_data[] = { 85 {"haoyu,hym8563", 1}, 86 {NULL, 0}, 87 }; 88 #endif 89 90 91 static inline int 92 hym8563_read_buf(struct hym8563_softc *sc, uint8_t reg, uint8_t *buf, 93 uint16_t buflen) 94 { 95 96 return (iicdev_readfrom(sc->dev, reg, buf, buflen, IIC_WAIT)); 97 } 98 99 static inline int 100 hym8563_write_buf(struct hym8563_softc *sc, uint8_t reg, uint8_t *buf, 101 uint16_t buflen) 102 { 103 104 return (iicdev_writeto(sc->dev, reg, buf, buflen, IIC_WAIT)); 105 } 106 107 static inline int 108 hym8563_read_1(struct hym8563_softc *sc, uint8_t reg, uint8_t *data) 109 { 110 111 return (iicdev_readfrom(sc->dev, reg, data, 1, IIC_WAIT)); 112 } 113 114 static inline int 115 hym8563_write_1(struct hym8563_softc *sc, uint8_t reg, uint8_t val) 116 { 117 118 return (iicdev_writeto(sc->dev, reg, &val, 1, IIC_WAIT)); 119 } 120 121 static int 122 hym8563_gettime(device_t dev, struct timespec *ts) 123 { 124 struct hym8563_softc *sc; 125 struct bcd_clocktime bct; 126 uint8_t buf[7]; 127 int rv; 128 129 sc = device_get_softc(dev); 130 131 /* Read all RTC data */ 132 rv = hym8563_read_buf(sc, HYM8563_SEC, buf, sizeof(buf)); 133 if (rv != 0) { 134 device_printf(sc->dev, "Cannot read time registers: %d\n", rv); 135 return (rv); 136 } 137 138 /* Check for low voltage flag */ 139 if (buf[0] & HYM8563_SEC_VL) 140 { 141 device_printf(sc->dev, 142 "WARNING: RTC battery failed; time is invalid\n"); 143 return (EINVAL); 144 } 145 146 bzero(&bct, sizeof(bct)); 147 bct.sec = buf[0] & 0x7F; 148 bct.min = buf[1] & 0x7F; 149 bct.hour = buf[2] & 0x3f; 150 bct.day = buf[3] & 0x3f; 151 /* buf[4] is weekday */ 152 bct.mon = buf[5] & 0x1f; 153 bct.year = buf[6] & 0xff; 154 if (buf[5] & HYM8563_MONTH_CENTURY) 155 bct.year += 0x100; 156 157 clock_dbgprint_bcd(sc->dev, CLOCK_DBG_READ, &bct); 158 return (clock_bcd_to_ts(&bct, ts, false)); 159 } 160 161 static int 162 hym8563_settime(device_t dev, struct timespec *ts) 163 { 164 struct hym8563_softc *sc; 165 struct bcd_clocktime bct; 166 uint8_t buf[7]; 167 int rv; 168 169 sc = device_get_softc(dev); 170 ts->tv_sec -= utc_offset(); 171 clock_ts_to_bcd(ts, &bct, false); 172 clock_dbgprint_bcd(sc->dev, CLOCK_DBG_WRITE, &bct); 173 174 buf[0] = bct.sec; /* Also clear VL flag */ 175 buf[1] = bct.min; 176 buf[2] = bct.hour; 177 buf[3] = bct.day; 178 buf[4] = bct.dow; 179 buf[5] = bct.mon; 180 buf[6] = bct.year & 0xFF; 181 if (bct.year > 0x99) 182 buf[5] |= HYM8563_MONTH_CENTURY; 183 184 /* Stop RTC */ 185 rv = hym8563_write_1(sc, HYM8563_CTRL1, HYM8563_CTRL1_STOP); 186 if (rv != 0) { 187 device_printf(sc->dev, "Cannot write CTRL1 register: %d\n", rv); 188 return (rv); 189 } 190 191 /* Write all RTC data */ 192 rv = hym8563_write_buf(sc, HYM8563_SEC, buf, sizeof(buf)); 193 if (rv != 0) { 194 device_printf(sc->dev, "Cannot write time registers: %d\n", rv); 195 return (rv); 196 } 197 return (rv); 198 199 /* Start RTC again */ 200 rv = hym8563_write_1(sc, HYM8563_CTRL1, 0); 201 if (rv != 0) { 202 device_printf(sc->dev, "Cannot write CTRL1 register: %d\n", rv); 203 return (rv); 204 } 205 206 return (0); 207 } 208 209 static void 210 hym8563_init(void *arg) 211 { 212 struct hym8563_softc *sc; 213 uint8_t reg; 214 int rv; 215 216 sc = (struct hym8563_softc*)arg; 217 config_intrhook_disestablish(&sc->init_hook); 218 219 /* Clear CTL1 register (stop and test bits) */ 220 rv = hym8563_write_1(sc, HYM8563_CTRL1, 0); 221 if (rv != 0) { 222 device_printf(sc->dev, "Cannot init CTRL1 register: %d\n", rv); 223 return; 224 } 225 226 /* Disable interrupts and alarms */ 227 rv = hym8563_read_1(sc, HYM8563_CTRL2, ®); 228 if (rv != 0) { 229 device_printf(sc->dev, "Cannot read CTRL2 register: %d\n", rv); 230 return; 231 } 232 rv &= ~HYM8563_CTRL2_TI_TP; 233 rv &= ~HYM8563_CTRL2_AF; 234 rv &= ~HYM8563_CTRL2_TF; 235 rv = hym8563_write_1(sc, HYM8563_CTRL2, 0); 236 if (rv != 0) { 237 device_printf(sc->dev, "Cannot write CTRL2 register: %d\n", rv); 238 return; 239 } 240 241 /* 242 * Register as a system realtime clock. 243 */ 244 clock_register_flags(sc->dev, 1000000, 0); 245 clock_schedule(sc->dev, 1); 246 return; 247 } 248 249 static int 250 hym8563_probe(device_t dev) 251 { 252 253 #ifdef FDT 254 if (!ofw_bus_status_okay(dev)) 255 return (ENXIO); 256 257 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 258 device_set_desc(dev, "HYM8694 RTC"); 259 return (BUS_PROBE_DEFAULT); 260 } 261 #endif 262 return (ENXIO); 263 } 264 265 static int 266 hym8563_attach(device_t dev) 267 { 268 struct hym8563_softc *sc; 269 270 sc = device_get_softc(dev); 271 sc->dev = dev; 272 273 /* 274 * Chip init must wait until interrupts are enabled. Often i2c access 275 * works only when the interrupts are available. 276 */ 277 sc->init_hook.ich_func = hym8563_init; 278 sc->init_hook.ich_arg = sc; 279 if (config_intrhook_establish(&sc->init_hook) != 0) 280 return (ENOMEM); 281 282 return (0); 283 } 284 285 static int 286 hym8563_detach(device_t dev) 287 { 288 289 clock_unregister(dev); 290 return (0); 291 } 292 293 static device_method_t hym8563_methods[] = { 294 /* device_if methods */ 295 DEVMETHOD(device_probe, hym8563_probe), 296 DEVMETHOD(device_attach, hym8563_attach), 297 DEVMETHOD(device_detach, hym8563_detach), 298 299 /* clock_if methods */ 300 DEVMETHOD(clock_gettime, hym8563_gettime), 301 DEVMETHOD(clock_settime, hym8563_settime), 302 303 DEVMETHOD_END, 304 }; 305 306 static DEFINE_CLASS_0(hym8563_rtc, hym8563_driver, hym8563_methods, 307 sizeof(struct hym8563_softc)); 308 DRIVER_MODULE(hym8563, iicbus, hym8563_driver, NULL, NULL); 309 MODULE_VERSION(hym8563, 1); 310 MODULE_DEPEND(hym8563, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 311 IICBUS_FDT_PNP_INFO(compat_data); 312