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 #if defined(FDT) && !defined(__powerpc64__) 44 #include <dev/clk/clk.h> 45 #include <dev/ofw/ofw_bus.h> 46 #include <dev/ofw/ofw_bus_subr.h> 47 #endif 48 49 #include <dev/iicbus/iiconf.h> 50 #include <dev/iicbus/iicbus.h> 51 52 #include "clock_if.h" 53 #include "iicbus_if.h" 54 55 /* Registers */ 56 #define HYM8563_CTRL1 0x00 57 #define HYM8563_CTRL1_TEST (1 << 7) 58 #define HYM8563_CTRL1_STOP (1 << 5) 59 #define HYM8563_CTRL1_TESTC (1 << 3) 60 61 #define HYM8563_CTRL2 0x01 62 #define HYM8563_CTRL2_TI_TP (1 << 4) 63 #define HYM8563_CTRL2_AF (1 << 3) 64 #define HYM8563_CTRL2_TF (1 << 2) 65 #define HYM8563_CTRL2_AIE (1 << 1) 66 #define HYM8563_CTRL2_TIE (1 << 0) 67 68 #define HYM8563_SEC 0x02 /* plus battery low bit */ 69 #define HYM8563_SEC_VL (1 << 7) 70 71 #define HYM8563_MIN 0x03 72 #define HYM8563_HOUR 0x04 73 #define HYM8563_DAY 0x05 74 #define HYM8563_WEEKDAY 0x06 75 #define HYM8563_MONTH 0x07 /* plus 1 bit for century */ 76 #define HYM8563_MONTH_CENTURY (1 << 7) 77 #define HYM8563_YEAR 0x08 78 79 #define HYM8563_CLKOUT 0x0D 80 #define HYM8563_CLKOUT_ENABLE (1 << 7) 81 #define HYM8563_CLKOUT_32768 0 82 #define HYM8563_CLKOUT_1024 1 83 #define HYM8563_CLKOUT_32 2 84 #define HYM8563_CLKOUT_1 3 85 #define HYM8563_CLKOUT_MASK 3 86 87 struct hym8563_softc { 88 device_t dev; 89 struct intr_config_hook init_hook; 90 }; 91 92 #if defined(FDT) && !defined(__powerpc64__) 93 /* Clock class and method */ 94 struct hym8563_clk_sc { 95 device_t base_dev; 96 }; 97 98 99 static struct ofw_compat_data compat_data[] = { 100 {"haoyu,hym8563", 1}, 101 {NULL, 0}, 102 }; 103 #endif 104 105 106 static inline int 107 hym8563_read_buf(device_t dev, uint8_t reg, uint8_t *buf, uint16_t buflen) 108 { 109 110 return (iicdev_readfrom(dev, reg, buf, buflen, IIC_WAIT)); 111 } 112 113 static inline int 114 hym8563_write_buf(device_t dev, uint8_t reg, uint8_t *buf, uint16_t buflen) 115 { 116 117 return (iicdev_writeto(dev, reg, buf, buflen, IIC_WAIT)); 118 } 119 120 static inline int 121 hym8563_read_1(device_t dev, uint8_t reg, uint8_t *data) 122 { 123 124 return (iicdev_readfrom(dev, reg, data, 1, IIC_WAIT)); 125 } 126 127 static inline int 128 hym8563_write_1(device_t dev, uint8_t reg, uint8_t val) 129 { 130 131 return (iicdev_writeto(dev, reg, &val, 1, IIC_WAIT)); 132 } 133 134 #if defined(FDT) && !defined(__powerpc64__) 135 static int 136 hym8563_clk_set_gate(struct clknode *clk, bool enable) 137 { 138 struct hym8563_clk_sc *sc; 139 uint8_t val; 140 int rv; 141 142 sc = clknode_get_softc(clk); 143 144 rv = hym8563_read_1(sc->base_dev, HYM8563_CLKOUT, &val); 145 if (rv != 0) { 146 device_printf(sc->base_dev, 147 "Cannot read CLKOUT registers: %d\n", rv); 148 return (rv); 149 } 150 if (enable) 151 val |= HYM8563_CLKOUT_ENABLE; 152 else 153 val &= ~HYM8563_CLKOUT_ENABLE; 154 hym8563_write_1(sc->base_dev, HYM8563_CLKOUT, val); 155 if (rv != 0) { 156 device_printf(sc->base_dev, 157 "Cannot write CLKOUT registers: %d\n", rv); 158 return (rv); 159 } 160 return (0); 161 } 162 163 static int 164 hym8563_clk_recalc(struct clknode *clk, uint64_t *freq) 165 { 166 struct hym8563_clk_sc *sc; 167 uint8_t val; 168 int rv; 169 170 sc = clknode_get_softc(clk); 171 172 rv = hym8563_read_1(sc->base_dev, HYM8563_CLKOUT, &val); 173 if (rv != 0) { 174 device_printf(sc->base_dev, 175 "Cannot read CLKOUT registers: %d\n", rv); 176 return (rv); 177 } 178 179 switch (val & HYM8563_CLKOUT_MASK) { 180 case HYM8563_CLKOUT_32768: 181 *freq = 32768; 182 break; 183 case HYM8563_CLKOUT_1024: 184 *freq = 1024; 185 break; 186 case HYM8563_CLKOUT_32: 187 *freq = 32; 188 break; 189 case HYM8563_CLKOUT_1: 190 *freq = 1; 191 break; 192 default: 193 return (EINVAL); 194 } 195 return (0); 196 } 197 static int 198 hym8563_clk_set(struct clknode *clk, uint64_t fparent, uint64_t *fout, 199 int flags, int *stop) 200 { 201 struct hym8563_clk_sc *sc; 202 uint8_t val, tmp; 203 int rv; 204 205 sc = clknode_get_softc(clk); 206 207 switch (*fout) { 208 case 32768: 209 tmp = HYM8563_CLKOUT_32768; 210 break; 211 case 1024: 212 tmp = HYM8563_CLKOUT_1024; 213 break; 214 case 32: 215 tmp = HYM8563_CLKOUT_32; 216 break; 217 case 1: 218 tmp = HYM8563_CLKOUT_1; 219 break; 220 default: 221 *stop = 1; 222 return (EINVAL); 223 } 224 225 rv = hym8563_read_1(sc->base_dev, HYM8563_CLKOUT, &val); 226 if (rv != 0) { 227 device_printf(sc->base_dev, 228 "Cannot read CLKOUT registers: %d\n", rv); 229 return (rv); 230 } 231 232 val &= ~HYM8563_CLKOUT_MASK; 233 val |= tmp; 234 rv = hym8563_write_1(sc->base_dev, HYM8563_CLKOUT, val); 235 if (rv != 0) { 236 device_printf(sc->base_dev, 237 "Cannot write CLKOUT registers: %d\n", rv); 238 return (rv); 239 } 240 241 return (0); 242 } 243 244 static clknode_method_t hym8563_clk_clknode_methods[] = { 245 CLKNODEMETHOD(clknode_recalc_freq, hym8563_clk_recalc), 246 CLKNODEMETHOD(clknode_set_freq, hym8563_clk_set), 247 CLKNODEMETHOD(clknode_set_gate, hym8563_clk_set_gate), 248 CLKNODEMETHOD_END 249 }; 250 251 DEFINE_CLASS_1(hym8563_clk_clknode, hym8563_clk_clknode_class, 252 hym8563_clk_clknode_methods, sizeof(struct hym8563_clk_sc), 253 clknode_class); 254 255 256 static int 257 hym8563_attach_clocks(struct hym8563_softc *sc) 258 { 259 struct clkdom *clkdom; 260 struct clknode_init_def clkidef; 261 struct clknode *clk; 262 struct hym8563_clk_sc *clksc; 263 const char **clknames; 264 phandle_t node; 265 int nclks, rv; 266 267 node = ofw_bus_get_node(sc->dev); 268 269 /* clock-output-names are optional. Could use them for clkidef.name. */ 270 nclks = ofw_bus_string_list_to_array(node, "clock-output-names", 271 &clknames); 272 273 clkdom = clkdom_create(sc->dev); 274 275 memset(&clkidef, 0, sizeof(clkidef)); 276 clkidef.id = 1; 277 clkidef.name = (nclks == 1) ? clknames[0] : "hym8563-clkout"; 278 clk = clknode_create(clkdom, &hym8563_clk_clknode_class, &clkidef); 279 if (clk == NULL) { 280 device_printf(sc->dev, "Cannot create '%s'.\n", clkidef.name); 281 return (ENXIO); 282 } 283 clksc = clknode_get_softc(clk); 284 clksc->base_dev = sc->dev; 285 clknode_register(clkdom, clk); 286 287 rv = clkdom_finit(clkdom); 288 if (rv != 0) { 289 device_printf(sc->dev, "Cannot finalize clkdom initialization: " 290 "%d\n", rv); 291 return (ENXIO); 292 } 293 294 if (bootverbose) 295 clkdom_dump(clkdom); 296 297 return (0); 298 } 299 #endif 300 301 static int 302 hym8563_gettime(device_t dev, struct timespec *ts) 303 { 304 struct hym8563_softc *sc; 305 struct bcd_clocktime bct; 306 uint8_t buf[7]; 307 int rv; 308 309 sc = device_get_softc(dev); 310 311 /* Read all RTC data */ 312 rv = hym8563_read_buf(sc->dev, HYM8563_SEC, buf, sizeof(buf)); 313 if (rv != 0) { 314 device_printf(sc->dev, "Cannot read time registers: %d\n", rv); 315 return (rv); 316 } 317 318 /* Check for low voltage flag */ 319 if (buf[0] & HYM8563_SEC_VL) 320 { 321 device_printf(sc->dev, 322 "WARNING: RTC battery failed; time is invalid\n"); 323 return (EINVAL); 324 } 325 326 bzero(&bct, sizeof(bct)); 327 bct.sec = buf[0] & 0x7F; 328 bct.min = buf[1] & 0x7F; 329 bct.hour = buf[2] & 0x3f; 330 bct.day = buf[3] & 0x3f; 331 /* buf[4] is weekday */ 332 bct.mon = buf[5] & 0x1f; 333 bct.year = buf[6] & 0xff; 334 if (buf[5] & HYM8563_MONTH_CENTURY) 335 bct.year += 0x100; 336 337 clock_dbgprint_bcd(sc->dev, CLOCK_DBG_READ, &bct); 338 return (clock_bcd_to_ts(&bct, ts, false)); 339 } 340 341 static int 342 hym8563_settime(device_t dev, struct timespec *ts) 343 { 344 struct hym8563_softc *sc; 345 struct bcd_clocktime bct; 346 uint8_t buf[7]; 347 int rv; 348 349 sc = device_get_softc(dev); 350 ts->tv_sec -= utc_offset(); 351 clock_ts_to_bcd(ts, &bct, false); 352 clock_dbgprint_bcd(sc->dev, CLOCK_DBG_WRITE, &bct); 353 354 buf[0] = bct.sec; /* Also clear VL flag */ 355 buf[1] = bct.min; 356 buf[2] = bct.hour; 357 buf[3] = bct.day; 358 buf[4] = bct.dow; 359 buf[5] = bct.mon; 360 buf[6] = bct.year & 0xFF; 361 if (bct.year > 0x99) 362 buf[5] |= HYM8563_MONTH_CENTURY; 363 364 /* Stop RTC */ 365 rv = hym8563_write_1(sc->dev, HYM8563_CTRL1, HYM8563_CTRL1_STOP); 366 if (rv != 0) { 367 device_printf(sc->dev, "Cannot write CTRL1 register: %d\n", rv); 368 return (rv); 369 } 370 371 /* Write all RTC data */ 372 rv = hym8563_write_buf(sc->dev, HYM8563_SEC, buf, sizeof(buf)); 373 if (rv != 0) { 374 device_printf(sc->dev, "Cannot write time registers: %d\n", rv); 375 return (rv); 376 } 377 return (rv); 378 379 /* Start RTC again */ 380 rv = hym8563_write_1(sc->dev, HYM8563_CTRL1, 0); 381 if (rv != 0) { 382 device_printf(sc->dev, "Cannot write CTRL1 register: %d\n", rv); 383 return (rv); 384 } 385 386 return (0); 387 } 388 389 static void 390 hym8563_init(void *arg) 391 { 392 struct hym8563_softc *sc; 393 uint8_t reg; 394 int rv; 395 396 sc = (struct hym8563_softc*)arg; 397 config_intrhook_disestablish(&sc->init_hook); 398 399 /* Clear CTL1 register (stop and test bits) */ 400 rv = hym8563_write_1(sc->dev, HYM8563_CTRL1, 0); 401 if (rv != 0) { 402 device_printf(sc->dev, "Cannot init CTRL1 register: %d\n", rv); 403 return; 404 } 405 406 /* Disable interrupts and alarms */ 407 rv = hym8563_read_1(sc->dev, HYM8563_CTRL2, ®); 408 if (rv != 0) { 409 device_printf(sc->dev, "Cannot read CTRL2 register: %d\n", rv); 410 return; 411 } 412 rv &= ~HYM8563_CTRL2_TI_TP; 413 rv &= ~HYM8563_CTRL2_AF; 414 rv &= ~HYM8563_CTRL2_TF; 415 rv = hym8563_write_1(sc->dev, HYM8563_CTRL2, 0); 416 if (rv != 0) { 417 device_printf(sc->dev, "Cannot write CTRL2 register: %d\n", rv); 418 return; 419 } 420 421 /* 422 * Register as a system realtime clock. 423 */ 424 clock_register_flags(sc->dev, 1000000, 0); 425 clock_schedule(sc->dev, 1); 426 return; 427 } 428 429 static int 430 hym8563_probe(device_t dev) 431 { 432 433 #if defined(FDT) && !defined(__powerpc64__) 434 if (!ofw_bus_status_okay(dev)) 435 return (ENXIO); 436 437 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 438 device_set_desc(dev, "HYM8694 RTC"); 439 return (BUS_PROBE_DEFAULT); 440 } 441 #endif 442 return (ENXIO); 443 } 444 445 static int 446 hym8563_attach(device_t dev) 447 { 448 struct hym8563_softc *sc; 449 450 sc = device_get_softc(dev); 451 sc->dev = dev; 452 453 #if defined(FDT) && !defined(__powerpc64__) 454 if (hym8563_attach_clocks(sc) != 0) 455 return(ENXIO); 456 #endif 457 458 /* 459 * Chip init must wait until interrupts are enabled. Often i2c access 460 * works only when the interrupts are available. 461 */ 462 sc->init_hook.ich_func = hym8563_init; 463 sc->init_hook.ich_arg = sc; 464 if (config_intrhook_establish(&sc->init_hook) != 0) 465 return (ENOMEM); 466 467 return (0); 468 } 469 470 static int 471 hym8563_detach(device_t dev) 472 { 473 474 clock_unregister(dev); 475 return (0); 476 } 477 478 static device_method_t hym8563_methods[] = { 479 /* device_if methods */ 480 DEVMETHOD(device_probe, hym8563_probe), 481 DEVMETHOD(device_attach, hym8563_attach), 482 DEVMETHOD(device_detach, hym8563_detach), 483 484 /* clock_if methods */ 485 DEVMETHOD(clock_gettime, hym8563_gettime), 486 DEVMETHOD(clock_settime, hym8563_settime), 487 488 DEVMETHOD_END, 489 }; 490 491 static DEFINE_CLASS_0(hym8563_rtc, hym8563_driver, hym8563_methods, 492 sizeof(struct hym8563_softc)); 493 EARLY_DRIVER_MODULE(hym8563, iicbus, hym8563_driver, NULL, NULL, 494 BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_FIRST); 495 MODULE_VERSION(hym8563, 1); 496 MODULE_DEPEND(hym8563, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 497 #if defined(FDT) && !defined(__powerpc64__) 498 IICBUS_FDT_PNP_INFO(compat_data); 499 #endif