1 /* $NetBSD: m41st84.c,v 1.22 2014/11/20 16:34:26 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Steve C. Woodford and Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: m41st84.c,v 1.22 2014/11/20 16:34:26 christos Exp $"); 40 41 #include "opt_strtc.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/device.h> 46 #include <sys/kernel.h> 47 #include <sys/fcntl.h> 48 #include <sys/uio.h> 49 #include <sys/conf.h> 50 #include <sys/event.h> 51 52 #include <dev/clock_subr.h> 53 54 #include <dev/i2c/i2cvar.h> 55 #include <dev/i2c/m41st84reg.h> 56 #include <dev/i2c/m41st84var.h> 57 58 struct strtc_softc { 59 device_t sc_dev; 60 i2c_tag_t sc_tag; 61 int sc_address; 62 int sc_open; 63 struct todr_chip_handle sc_todr; 64 }; 65 66 static void strtc_attach(device_t, device_t, void *); 67 static int strtc_match(device_t, cfdata_t, void *); 68 69 CFATTACH_DECL_NEW(strtc, sizeof(struct strtc_softc), 70 strtc_match, strtc_attach, NULL, NULL); 71 72 #ifndef STRTC_NO_USERRAM 73 extern struct cfdriver strtc_cd; 74 75 dev_type_open(strtc_open); 76 dev_type_close(strtc_close); 77 dev_type_read(strtc_read); 78 dev_type_write(strtc_write); 79 80 const struct cdevsw strtc_cdevsw = { 81 .d_open = strtc_open, 82 .d_close = strtc_close, 83 .d_read = strtc_read, 84 .d_write = strtc_write, 85 .d_ioctl = noioctl, 86 .d_stop = nostop, 87 .d_tty = notty, 88 .d_poll = nopoll, 89 .d_mmap = nommap, 90 .d_kqfilter = nokqfilter, 91 .d_discard = nodiscard, 92 .d_flag = D_OTHER 93 }; 94 #endif 95 96 static int strtc_clock_read(struct strtc_softc *, struct clock_ymdhms *); 97 static int strtc_clock_write(struct strtc_softc *, struct clock_ymdhms *); 98 static int strtc_gettime(struct todr_chip_handle *, struct timeval *); 99 static int strtc_settime(struct todr_chip_handle *, struct timeval *); 100 101 static int 102 strtc_match(device_t parent, cfdata_t cf, void *arg) 103 { 104 struct i2c_attach_args *ia = arg; 105 106 if (ia->ia_name) { 107 /* direct config - check name */ 108 if (strcmp(ia->ia_name, "strtc") == 0) 109 return 1; 110 } else { 111 /* indirect config - check typical address */ 112 if (ia->ia_addr == M41ST84_ADDR) 113 return 1; 114 } 115 return 0; 116 } 117 118 static void 119 strtc_attach(device_t parent, device_t self, void *arg) 120 { 121 struct strtc_softc *sc = device_private(self); 122 struct i2c_attach_args *ia = arg; 123 124 #ifndef STRTC_NO_USERRAM 125 aprint_naive(": Real-time Clock/NVRAM\n"); 126 aprint_normal(": M41ST84 Real-time Clock/NVRAM\n"); 127 #else 128 aprint_naive(": Real-time Clock\n"); 129 aprint_normal(": M41T8x Real-time Clock\n"); 130 #endif 131 sc->sc_tag = ia->ia_tag; 132 sc->sc_address = ia->ia_addr; 133 sc->sc_dev = self; 134 sc->sc_open = 0; 135 sc->sc_todr.cookie = sc; 136 sc->sc_todr.todr_gettime = strtc_gettime; 137 sc->sc_todr.todr_settime = strtc_settime; 138 sc->sc_todr.todr_setwen = NULL; 139 140 todr_attach(&sc->sc_todr); 141 } 142 143 #ifndef STRTC_NO_USERRAM 144 /*ARGSUSED*/ 145 int 146 strtc_open(dev_t dev, int flag, int fmt, struct lwp *l) 147 { 148 struct strtc_softc *sc; 149 150 if ((sc = device_lookup_private(&strtc_cd, minor(dev))) == NULL) 151 return (ENXIO); 152 153 /* XXX: Locking */ 154 155 if (sc->sc_open) 156 return (EBUSY); 157 158 sc->sc_open = 1; 159 return (0); 160 } 161 162 /*ARGSUSED*/ 163 int 164 strtc_close(dev_t dev, int flag, int fmt, struct lwp *l) 165 { 166 struct strtc_softc *sc; 167 168 if ((sc = device_lookup_private(&strtc_cd, minor(dev))) == NULL) 169 return (ENXIO); 170 171 sc->sc_open = 0; 172 return (0); 173 } 174 175 /*ARGSUSED*/ 176 int 177 strtc_read(dev_t dev, struct uio *uio, int flags) 178 { 179 struct strtc_softc *sc; 180 u_int8_t ch, cmdbuf[1]; 181 int a, error; 182 183 if ((sc = device_lookup_private(&strtc_cd, minor(dev))) == NULL) 184 return (ENXIO); 185 186 if (uio->uio_offset >= M41ST84_USER_RAM_SIZE) 187 return (EINVAL); 188 189 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 190 return (error); 191 192 while (uio->uio_resid && uio->uio_offset < M41ST84_USER_RAM_SIZE) { 193 a = (int)uio->uio_offset; 194 cmdbuf[0] = a + M41ST84_USER_RAM; 195 if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 196 sc->sc_address, cmdbuf, 1, 197 &ch, 1, 0)) != 0) { 198 iic_release_bus(sc->sc_tag, 0); 199 aprint_error_dev(sc->sc_dev, 200 "strtc_read: read failed at 0x%x\n", a); 201 return (error); 202 } 203 if ((error = uiomove(&ch, 1, uio)) != 0) { 204 iic_release_bus(sc->sc_tag, 0); 205 return (error); 206 } 207 } 208 209 iic_release_bus(sc->sc_tag, 0); 210 211 return (0); 212 } 213 214 /*ARGSUSED*/ 215 int 216 strtc_write(dev_t dev, struct uio *uio, int flags) 217 { 218 struct strtc_softc *sc; 219 u_int8_t cmdbuf[2]; 220 int a, error; 221 222 if ((sc = device_lookup_private(&strtc_cd, minor(dev))) == NULL) 223 return (ENXIO); 224 225 if (uio->uio_offset >= M41ST84_USER_RAM_SIZE) 226 return (EINVAL); 227 228 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 229 return (error); 230 231 while (uio->uio_resid && uio->uio_offset < M41ST84_USER_RAM_SIZE) { 232 a = (int)uio->uio_offset; 233 cmdbuf[0] = a + M41ST84_USER_RAM; 234 if ((error = uiomove(&cmdbuf[1], 1, uio)) != 0) 235 break; 236 237 if ((error = iic_exec(sc->sc_tag, 238 uio->uio_resid ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, 239 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, 0)) != 0) { 240 aprint_error_dev(sc->sc_dev, 241 "strtc_write: write failed at 0x%x\n", a); 242 break; 243 } 244 } 245 246 iic_release_bus(sc->sc_tag, 0); 247 248 return (error); 249 } 250 #endif /* STRTC_NO_USERRAM */ 251 252 static int 253 strtc_gettime(struct todr_chip_handle *ch, struct timeval *tv) 254 { 255 struct strtc_softc *sc = ch->cookie; 256 struct clock_ymdhms dt, check; 257 int retries; 258 259 memset(&dt, 0, sizeof(dt)); 260 memset(&check, 0, sizeof(check)); 261 262 /* 263 * Since we don't support Burst Read, we have to read the clock twice 264 * until we get two consecutive identical results. 265 */ 266 retries = 5; 267 do { 268 strtc_clock_read(sc, &dt); 269 strtc_clock_read(sc, &check); 270 } while (memcmp(&dt, &check, sizeof(check)) != 0 && --retries); 271 272 tv->tv_sec = clock_ymdhms_to_secs(&dt); 273 tv->tv_usec = 0; 274 275 return (0); 276 } 277 278 static int 279 strtc_settime(struct todr_chip_handle *ch, struct timeval *tv) 280 { 281 struct strtc_softc *sc = ch->cookie; 282 struct clock_ymdhms dt; 283 284 clock_secs_to_ymdhms(tv->tv_sec, &dt); 285 286 if (strtc_clock_write(sc, &dt) == 0) 287 return (-1); 288 289 return (0); 290 } 291 292 static int 293 strtc_clock_read(struct strtc_softc *sc, struct clock_ymdhms *dt) 294 { 295 u_int8_t bcd[M41ST84_REG_DATE_BYTES], cmdbuf[2]; 296 int i; 297 298 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 299 aprint_error_dev(sc->sc_dev, 300 "strtc_clock_read: failed to acquire I2C bus\n"); 301 return (0); 302 } 303 304 /* 305 * Check for the HT bit -- if set, then clock lost power & stopped 306 * If that happened, then clear the bit so that the clock will have 307 * a chance to run again. 308 */ 309 cmdbuf[0] = M41ST84_REG_AL_HOUR; 310 if (iic_exec(sc->sc_tag, I2C_OP_READ, sc->sc_address, 311 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 312 iic_release_bus(sc->sc_tag, I2C_F_POLL); 313 aprint_error_dev(sc->sc_dev, 314 "strtc_clock_read: failed to read HT\n"); 315 return (0); 316 } 317 if (cmdbuf[1] & M41ST84_AL_HOUR_HT) { 318 cmdbuf[1] &= ~M41ST84_AL_HOUR_HT; 319 if (iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address, 320 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 321 iic_release_bus(sc->sc_tag, I2C_F_POLL); 322 aprint_error_dev(sc->sc_dev, 323 "strtc_clock_read: failed to reset HT\n"); 324 return (0); 325 } 326 } 327 328 /* Read each RTC register in order. */ 329 for (i = M41ST84_REG_CSEC; i < M41ST84_REG_DATE_BYTES; i++) { 330 cmdbuf[0] = i; 331 332 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 333 sc->sc_address, cmdbuf, 1, 334 &bcd[i], 1, I2C_F_POLL)) { 335 iic_release_bus(sc->sc_tag, I2C_F_POLL); 336 aprint_error_dev(sc->sc_dev, 337 "strtc_clock_read: failed to read rtc " 338 "at 0x%x\n", i); 339 return (0); 340 } 341 } 342 343 /* Done with I2C */ 344 iic_release_bus(sc->sc_tag, I2C_F_POLL); 345 346 /* 347 * Convert the M41ST84's register values into something useable 348 */ 349 dt->dt_sec = bcdtobin(bcd[M41ST84_REG_SEC] & M41ST84_SEC_MASK); 350 dt->dt_min = bcdtobin(bcd[M41ST84_REG_MIN] & M41ST84_MIN_MASK); 351 dt->dt_hour = bcdtobin(bcd[M41ST84_REG_CENHR] & M41ST84_HOUR_MASK); 352 dt->dt_day = bcdtobin(bcd[M41ST84_REG_DATE] & M41ST84_DATE_MASK); 353 dt->dt_mon = bcdtobin(bcd[M41ST84_REG_MONTH] & M41ST84_MONTH_MASK); 354 355 /* XXX: Should be an MD way to specify EPOCH used by BIOS/Firmware */ 356 dt->dt_year = bcdtobin(bcd[M41ST84_REG_YEAR]) + POSIX_BASE_YEAR; 357 358 return (1); 359 } 360 361 static int 362 strtc_clock_write(struct strtc_softc *sc, struct clock_ymdhms *dt) 363 { 364 uint8_t bcd[M41ST84_REG_DATE_BYTES], cmdbuf[2]; 365 int i; 366 367 /* 368 * Convert our time representation into something the M41ST84 369 * can understand. 370 */ 371 bcd[M41ST84_REG_CSEC] = bintobcd(0); /* must always write as 0 */ 372 bcd[M41ST84_REG_SEC] = bintobcd(dt->dt_sec); 373 bcd[M41ST84_REG_MIN] = bintobcd(dt->dt_min); 374 bcd[M41ST84_REG_CENHR] = bintobcd(dt->dt_hour); 375 bcd[M41ST84_REG_DATE] = bintobcd(dt->dt_day); 376 bcd[M41ST84_REG_DAY] = bintobcd(dt->dt_wday); 377 bcd[M41ST84_REG_MONTH] = bintobcd(dt->dt_mon); 378 bcd[M41ST84_REG_YEAR] = bintobcd((dt->dt_year - POSIX_BASE_YEAR) % 100); 379 380 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 381 aprint_error_dev(sc->sc_dev, 382 "strtc_clock_write: failed to acquire I2C bus\n"); 383 return (0); 384 } 385 386 /* Stop the clock */ 387 cmdbuf[0] = M41ST84_REG_SEC; 388 cmdbuf[1] = M41ST84_SEC_ST; 389 390 if (iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address, 391 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 392 iic_release_bus(sc->sc_tag, I2C_F_POLL); 393 aprint_error_dev(sc->sc_dev, 394 "strtc_clock_write: failed to Hold Clock\n"); 395 return (0); 396 } 397 398 /* 399 * Check for the HT bit -- if set, then clock lost power & stopped 400 * If that happened, then clear the bit so that the clock will have 401 * a chance to run again. 402 */ 403 cmdbuf[0] = M41ST84_REG_AL_HOUR; 404 if (iic_exec(sc->sc_tag, I2C_OP_READ, sc->sc_address, 405 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 406 iic_release_bus(sc->sc_tag, I2C_F_POLL); 407 aprint_error_dev(sc->sc_dev, 408 "strtc_clock_write: failed to read HT\n"); 409 return (0); 410 } 411 if (cmdbuf[1] & M41ST84_AL_HOUR_HT) { 412 cmdbuf[1] &= ~M41ST84_AL_HOUR_HT; 413 if (iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address, 414 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 415 iic_release_bus(sc->sc_tag, I2C_F_POLL); 416 aprint_error_dev(sc->sc_dev, 417 "strtc_clock_write: failed to reset HT\n"); 418 return (0); 419 } 420 } 421 422 /* 423 * Write registers in reverse order. The last write (to the Seconds 424 * register) will undo the Clock Hold, above. 425 */ 426 for (i = M41ST84_REG_DATE_BYTES - 1; i >= 0; i--) { 427 cmdbuf[0] = i; 428 if (iic_exec(sc->sc_tag, 429 i ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, 430 sc->sc_address, cmdbuf, 1, &bcd[i], 1, 431 I2C_F_POLL)) { 432 iic_release_bus(sc->sc_tag, I2C_F_POLL); 433 aprint_error_dev(sc->sc_dev, 434 "strtc_clock_write: failed to write rtc " 435 " at 0x%x\n", i); 436 /* XXX: Clock Hold is likely still asserted! */ 437 return (0); 438 } 439 } 440 441 iic_release_bus(sc->sc_tag, I2C_F_POLL); 442 443 return (1); 444 } 445 446 #ifndef STRTC_NO_WATCHDOG 447 void 448 strtc_wdog_config(void *arg, uint8_t wd) 449 { 450 struct strtc_softc *sc = arg; 451 uint8_t cmdbuf[2]; 452 453 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 454 aprint_error_dev(sc->sc_dev, 455 "strtc_wdog_config: failed to acquire I2C bus\n"); 456 return; 457 } 458 459 cmdbuf[0] = M41ST84_REG_WATCHDOG; 460 cmdbuf[1] = wd; 461 462 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, 463 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 464 aprint_error_dev(sc->sc_dev, 465 "strtc_wdog_config: failed to write watchdog\n"); 466 return; 467 } 468 469 iic_release_bus(sc->sc_tag, I2C_F_POLL); 470 } 471 #endif /* STRTC_NO_WATCHDOG */ 472