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 __FBSDID("$FreeBSD$"); 30 31 /* 32 * Driver for realtime clock HAOYU HYM8563 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 /* Registers */ 57 #define HYM8563_CTRL1 0x00 58 #define HYM8563_CTRL1_TEST (1 << 7) 59 #define HYM8563_CTRL1_STOP (1 << 5) 60 #define HYM8563_CTRL1_TESTC (1 << 3) 61 62 #define HYM8563_CTRL2 0x01 63 #define HYM8563_CTRL2_TI_TP (1 << 4) 64 #define HYM8563_CTRL2_AF (1 << 3) 65 #define HYM8563_CTRL2_TF (1 << 2) 66 #define HYM8563_CTRL2_AIE (1 << 1) 67 #define HYM8563_CTRL2_TIE (1 << 0) 68 69 #define HYM8563_SEC 0x02 /* plus battery low bit */ 70 #define HYM8563_SEC_VL (1 << 7) 71 72 #define HYM8563_MIN 0x03 73 #define HYM8563_HOUR 0x04 74 #define HYM8563_DAY 0x05 75 #define HYM8563_WEEKDAY 0x06 76 #define HYM8563_MONTH 0x07 /* plus 1 bit for century */ 77 #define HYM8563_MONTH_CENTURY (1 << 7) 78 #define HYM8563_YEAR 0x08 79 80 struct hym8563_softc { 81 device_t dev; 82 struct intr_config_hook init_hook; 83 }; 84 85 #ifdef FDT 86 static struct ofw_compat_data compat_data[] = { 87 {"haoyu,hym8563", 1}, 88 {NULL, 0}, 89 }; 90 #endif 91 92 93 static inline int 94 hym8563_read_buf(struct hym8563_softc *sc, uint8_t reg, uint8_t *buf, 95 uint16_t buflen) 96 { 97 98 return (iicdev_readfrom(sc->dev, reg, buf, buflen, IIC_WAIT)); 99 } 100 101 static inline int 102 hym8563_write_buf(struct hym8563_softc *sc, uint8_t reg, uint8_t *buf, 103 uint16_t buflen) 104 { 105 106 return (iicdev_writeto(sc->dev, reg, buf, buflen, IIC_WAIT)); 107 } 108 109 static inline int 110 hym8563_read_1(struct hym8563_softc *sc, uint8_t reg, uint8_t *data) 111 { 112 113 return (iicdev_readfrom(sc->dev, reg, data, 1, IIC_WAIT)); 114 } 115 116 static inline int 117 hym8563_write_1(struct hym8563_softc *sc, uint8_t reg, uint8_t val) 118 { 119 120 return (iicdev_writeto(sc->dev, reg, &val, 1, IIC_WAIT)); 121 } 122 123 static int 124 hym8563_gettime(device_t dev, struct timespec *ts) 125 { 126 struct hym8563_softc *sc; 127 struct bcd_clocktime bct; 128 uint8_t buf[7]; 129 int rv; 130 131 sc = device_get_softc(dev); 132 133 /* Read all RTC data */ 134 rv = hym8563_read_buf(sc, HYM8563_SEC, buf, sizeof(buf)); 135 if (rv != 0) { 136 device_printf(sc->dev, "Cannot read time registers: %d\n", rv); 137 return (rv); 138 } 139 140 /* Check for low voltage flag */ 141 if (buf[0] & HYM8563_SEC_VL) 142 { 143 device_printf(sc->dev, 144 "WARNING: RTC battery failed; time is invalid\n"); 145 return (EINVAL); 146 } 147 148 bzero(&bct, sizeof(bct)); 149 bct.sec = buf[0] & 0x7F; 150 bct.min = buf[1] & 0x7F; 151 bct.hour = buf[2] & 0x3f; 152 bct.day = buf[3] & 0x3f; 153 /* buf[4] is weekday */ 154 bct.mon = buf[5] & 0x1f; 155 bct.year = buf[6] & 0xff; 156 if (buf[5] & HYM8563_MONTH_CENTURY) 157 bct.year += 0x100; 158 159 clock_dbgprint_bcd(sc->dev, CLOCK_DBG_READ, &bct); 160 return (clock_bcd_to_ts(&bct, ts, false)); 161 } 162 163 static int 164 hym8563_settime(device_t dev, struct timespec *ts) 165 { 166 struct hym8563_softc *sc; 167 struct bcd_clocktime bct; 168 uint8_t buf[7]; 169 int rv; 170 171 sc = device_get_softc(dev); 172 ts->tv_sec -= utc_offset(); 173 clock_ts_to_bcd(ts, &bct, false); 174 clock_dbgprint_bcd(sc->dev, CLOCK_DBG_WRITE, &bct); 175 176 buf[0] = bct.sec; /* Also clear VL flag */ 177 buf[1] = bct.min; 178 buf[2] = bct.hour; 179 buf[3] = bct.day; 180 buf[4] = bct.dow; 181 buf[5] = bct.mon; 182 buf[6] = bct.year & 0xFF; 183 if (bct.year > 0x99) 184 buf[5] |= HYM8563_MONTH_CENTURY; 185 186 /* Stop RTC */ 187 rv = hym8563_write_1(sc, HYM8563_CTRL1, HYM8563_CTRL1_STOP); 188 if (rv != 0) { 189 device_printf(sc->dev, "Cannot write CTRL1 register: %d\n", rv); 190 return (rv); 191 } 192 193 /* Write all RTC data */ 194 rv = hym8563_write_buf(sc, HYM8563_SEC, buf, sizeof(buf)); 195 if (rv != 0) { 196 device_printf(sc->dev, "Cannot write time registers: %d\n", rv); 197 return (rv); 198 } 199 return (rv); 200 201 /* Start RTC again */ 202 rv = hym8563_write_1(sc, HYM8563_CTRL1, 0); 203 if (rv != 0) { 204 device_printf(sc->dev, "Cannot write CTRL1 register: %d\n", rv); 205 return (rv); 206 } 207 208 return (0); 209 } 210 211 static void 212 hym8563_init(void *arg) 213 { 214 struct hym8563_softc *sc; 215 uint8_t reg; 216 int rv; 217 218 sc = (struct hym8563_softc*)arg; 219 config_intrhook_disestablish(&sc->init_hook); 220 221 /* Clear CTL1 register (stop and test bits) */ 222 rv = hym8563_write_1(sc, HYM8563_CTRL1, 0); 223 if (rv != 0) { 224 device_printf(sc->dev, "Cannot init CTRL1 register: %d\n", rv); 225 return; 226 } 227 228 /* Disable interrupts and alarms */ 229 rv = hym8563_read_1(sc, HYM8563_CTRL2, ®); 230 if (rv != 0) { 231 device_printf(sc->dev, "Cannot read CTRL2 register: %d\n", rv); 232 return; 233 } 234 rv &= ~HYM8563_CTRL2_TI_TP; 235 rv &= ~HYM8563_CTRL2_AF; 236 rv &= ~HYM8563_CTRL2_TF; 237 rv = hym8563_write_1(sc, HYM8563_CTRL2, 0); 238 if (rv != 0) { 239 device_printf(sc->dev, "Cannot write CTRL2 register: %d\n", rv); 240 return; 241 } 242 243 /* 244 * Register as a system realtime clock. 245 */ 246 clock_register_flags(sc->dev, 1000000, 0); 247 clock_schedule(sc->dev, 1); 248 return; 249 } 250 251 static int 252 hym8563_probe(device_t dev) 253 { 254 255 #ifdef FDT 256 if (!ofw_bus_status_okay(dev)) 257 return (ENXIO); 258 259 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 260 device_set_desc(dev, "HYM8694 RTC"); 261 return (BUS_PROBE_DEFAULT); 262 } 263 #endif 264 return (ENXIO); 265 } 266 267 static int 268 hym8563_attach(device_t dev) 269 { 270 struct hym8563_softc *sc; 271 272 sc = device_get_softc(dev); 273 sc->dev = dev; 274 275 /* 276 * Chip init must wait until interrupts are enabled. Often i2c access 277 * works only when the interrupts are available. 278 */ 279 sc->init_hook.ich_func = hym8563_init; 280 sc->init_hook.ich_arg = sc; 281 if (config_intrhook_establish(&sc->init_hook) != 0) 282 return (ENOMEM); 283 284 return (0); 285 } 286 287 static int 288 hym8563_detach(device_t dev) 289 { 290 291 clock_unregister(dev); 292 return (0); 293 } 294 295 static device_method_t hym8563_methods[] = { 296 /* device_if methods */ 297 DEVMETHOD(device_probe, hym8563_probe), 298 DEVMETHOD(device_attach, hym8563_attach), 299 DEVMETHOD(device_detach, hym8563_detach), 300 301 /* clock_if methods */ 302 DEVMETHOD(clock_gettime, hym8563_gettime), 303 DEVMETHOD(clock_settime, hym8563_settime), 304 305 DEVMETHOD_END, 306 }; 307 308 static DEFINE_CLASS_0(hym8563_rtc, hym8563_driver, hym8563_methods, 309 sizeof(struct hym8563_softc)); 310 DRIVER_MODULE(hym8563, iicbus, hym8563_driver, NULL, NULL); 311 MODULE_VERSION(hym8563, 1); 312 MODULE_DEPEND(hym8563, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 313 IICBUS_FDT_PNP_INFO(compat_data); 314