1 /* $NetBSD: m41st84.c,v 1.19 2013/11/08 03:56:10 nisimura 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.19 2013/11/08 03:56:10 nisimura 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 strtc_open, strtc_close, strtc_read, strtc_write, noioctl, 82 nostop, notty, nopoll, nommap, nokqfilter, D_OTHER 83 }; 84 #endif 85 86 static int strtc_clock_read(struct strtc_softc *, struct clock_ymdhms *); 87 static int strtc_clock_write(struct strtc_softc *, struct clock_ymdhms *); 88 static int strtc_gettime(struct todr_chip_handle *, struct timeval *); 89 static int strtc_settime(struct todr_chip_handle *, struct timeval *); 90 91 static int 92 strtc_match(device_t parent, cfdata_t cf, void *arg) 93 { 94 struct i2c_attach_args *ia = arg; 95 96 if (ia->ia_name) { 97 /* direct config - check name */ 98 if (strcmp(ia->ia_name, "strtc") == 0) 99 return 1; 100 } else { 101 /* indirect config - check typical address */ 102 if (ia->ia_addr == M41ST84_ADDR) 103 return 1; 104 } 105 return 0; 106 } 107 108 static void 109 strtc_attach(device_t parent, device_t self, void *arg) 110 { 111 struct strtc_softc *sc = device_private(self); 112 struct i2c_attach_args *ia = arg; 113 114 #ifndef STRTC_NO_USERRAM 115 aprint_naive(": Real-time Clock/NVRAM\n"); 116 aprint_normal(": M41ST84 Real-time Clock/NVRAM\n"); 117 #else 118 aprint_naive(": Real-time Clock\n"); 119 aprint_normal(": M41T8x Real-time Clock\n"); 120 #endif 121 sc->sc_tag = ia->ia_tag; 122 sc->sc_address = ia->ia_addr; 123 sc->sc_dev = self; 124 sc->sc_open = 0; 125 sc->sc_todr.cookie = sc; 126 sc->sc_todr.todr_gettime = strtc_gettime; 127 sc->sc_todr.todr_settime = strtc_settime; 128 sc->sc_todr.todr_setwen = NULL; 129 130 todr_attach(&sc->sc_todr); 131 } 132 133 #ifndef STRTC_NO_USERRAM 134 /*ARGSUSED*/ 135 int 136 strtc_open(dev_t dev, int flag, int fmt, struct lwp *l) 137 { 138 struct strtc_softc *sc; 139 140 if ((sc = device_lookup_private(&strtc_cd, minor(dev))) == NULL) 141 return (ENXIO); 142 143 /* XXX: Locking */ 144 145 if (sc->sc_open) 146 return (EBUSY); 147 148 sc->sc_open = 1; 149 return (0); 150 } 151 152 /*ARGSUSED*/ 153 int 154 strtc_close(dev_t dev, int flag, int fmt, struct lwp *l) 155 { 156 struct strtc_softc *sc; 157 158 if ((sc = device_lookup_private(&strtc_cd, minor(dev))) == NULL) 159 return (ENXIO); 160 161 sc->sc_open = 0; 162 return (0); 163 } 164 165 /*ARGSUSED*/ 166 int 167 strtc_read(dev_t dev, struct uio *uio, int flags) 168 { 169 struct strtc_softc *sc; 170 u_int8_t ch, cmdbuf[1]; 171 int a, error; 172 173 if ((sc = device_lookup_private(&strtc_cd, minor(dev))) == NULL) 174 return (ENXIO); 175 176 if (uio->uio_offset >= M41ST84_USER_RAM_SIZE) 177 return (EINVAL); 178 179 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 180 return (error); 181 182 while (uio->uio_resid && uio->uio_offset < M41ST84_USER_RAM_SIZE) { 183 a = (int)uio->uio_offset; 184 cmdbuf[0] = a + M41ST84_USER_RAM; 185 if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 186 sc->sc_address, cmdbuf, 1, 187 &ch, 1, 0)) != 0) { 188 iic_release_bus(sc->sc_tag, 0); 189 aprint_error_dev(sc->sc_dev, 190 "strtc_read: read failed at 0x%x\n", a); 191 return (error); 192 } 193 if ((error = uiomove(&ch, 1, uio)) != 0) { 194 iic_release_bus(sc->sc_tag, 0); 195 return (error); 196 } 197 } 198 199 iic_release_bus(sc->sc_tag, 0); 200 201 return (0); 202 } 203 204 /*ARGSUSED*/ 205 int 206 strtc_write(dev_t dev, struct uio *uio, int flags) 207 { 208 struct strtc_softc *sc; 209 u_int8_t cmdbuf[2]; 210 int a, error; 211 212 if ((sc = device_lookup_private(&strtc_cd, minor(dev))) == NULL) 213 return (ENXIO); 214 215 if (uio->uio_offset >= M41ST84_USER_RAM_SIZE) 216 return (EINVAL); 217 218 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 219 return (error); 220 221 while (uio->uio_resid && uio->uio_offset < M41ST84_USER_RAM_SIZE) { 222 a = (int)uio->uio_offset; 223 cmdbuf[0] = a + M41ST84_USER_RAM; 224 if ((error = uiomove(&cmdbuf[1], 1, uio)) != 0) 225 break; 226 227 if ((error = iic_exec(sc->sc_tag, 228 uio->uio_resid ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, 229 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, 0)) != 0) { 230 aprint_error_dev(sc->sc_dev, 231 "strtc_write: write failed at 0x%x\n", a); 232 break; 233 } 234 } 235 236 iic_release_bus(sc->sc_tag, 0); 237 238 return (error); 239 } 240 #endif /* STRTC_NO_USERRAM */ 241 242 static int 243 strtc_gettime(struct todr_chip_handle *ch, struct timeval *tv) 244 { 245 struct strtc_softc *sc = ch->cookie; 246 struct clock_ymdhms dt, check; 247 int retries; 248 249 memset(&dt, 0, sizeof(dt)); 250 memset(&check, 0, sizeof(check)); 251 252 /* 253 * Since we don't support Burst Read, we have to read the clock twice 254 * until we get two consecutive identical results. 255 */ 256 retries = 5; 257 do { 258 strtc_clock_read(sc, &dt); 259 strtc_clock_read(sc, &check); 260 } while (memcmp(&dt, &check, sizeof(check)) != 0 && --retries); 261 262 tv->tv_sec = clock_ymdhms_to_secs(&dt); 263 tv->tv_usec = 0; 264 265 return (0); 266 } 267 268 static int 269 strtc_settime(struct todr_chip_handle *ch, struct timeval *tv) 270 { 271 struct strtc_softc *sc = ch->cookie; 272 struct clock_ymdhms dt; 273 274 clock_secs_to_ymdhms(tv->tv_sec, &dt); 275 276 if (strtc_clock_write(sc, &dt) == 0) 277 return (-1); 278 279 return (0); 280 } 281 282 static int 283 strtc_clock_read(struct strtc_softc *sc, struct clock_ymdhms *dt) 284 { 285 u_int8_t bcd[M41ST84_REG_DATE_BYTES], cmdbuf[2]; 286 int i; 287 288 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 289 aprint_error_dev(sc->sc_dev, 290 "strtc_clock_read: failed to acquire I2C bus\n"); 291 return (0); 292 } 293 294 /* 295 * Check for the HT bit -- if set, then clock lost power & stopped 296 * If that happened, then clear the bit so that the clock will have 297 * a chance to run again. 298 */ 299 cmdbuf[0] = M41ST84_REG_AL_HOUR; 300 if (iic_exec(sc->sc_tag, I2C_OP_READ, sc->sc_address, 301 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 302 iic_release_bus(sc->sc_tag, I2C_F_POLL); 303 aprint_error_dev(sc->sc_dev, 304 "strtc_clock_read: failed to read HT\n"); 305 return (0); 306 } 307 if (cmdbuf[1] & M41ST84_AL_HOUR_HT) { 308 cmdbuf[1] &= ~M41ST84_AL_HOUR_HT; 309 if (iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address, 310 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 311 iic_release_bus(sc->sc_tag, I2C_F_POLL); 312 aprint_error_dev(sc->sc_dev, 313 "strtc_clock_read: failed to reset HT\n"); 314 return (0); 315 } 316 } 317 318 /* Read each RTC register in order. */ 319 for (i = M41ST84_REG_CSEC; i < M41ST84_REG_DATE_BYTES; i++) { 320 cmdbuf[0] = i; 321 322 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 323 sc->sc_address, cmdbuf, 1, 324 &bcd[i], 1, I2C_F_POLL)) { 325 iic_release_bus(sc->sc_tag, I2C_F_POLL); 326 aprint_error_dev(sc->sc_dev, 327 "strtc_clock_read: failed to read rtc " 328 "at 0x%x\n", i); 329 return (0); 330 } 331 } 332 333 /* Done with I2C */ 334 iic_release_bus(sc->sc_tag, I2C_F_POLL); 335 336 /* 337 * Convert the M41ST84's register values into something useable 338 */ 339 dt->dt_sec = FROMBCD(bcd[M41ST84_REG_SEC] & M41ST84_SEC_MASK); 340 dt->dt_min = FROMBCD(bcd[M41ST84_REG_MIN] & M41ST84_MIN_MASK); 341 dt->dt_hour = FROMBCD(bcd[M41ST84_REG_CENHR] & M41ST84_HOUR_MASK); 342 dt->dt_day = FROMBCD(bcd[M41ST84_REG_DATE] & M41ST84_DATE_MASK); 343 dt->dt_mon = FROMBCD(bcd[M41ST84_REG_MONTH] & M41ST84_MONTH_MASK); 344 345 /* XXX: Should be an MD way to specify EPOCH used by BIOS/Firmware */ 346 dt->dt_year = FROMBCD(bcd[M41ST84_REG_YEAR]) + POSIX_BASE_YEAR; 347 348 return (1); 349 } 350 351 static int 352 strtc_clock_write(struct strtc_softc *sc, struct clock_ymdhms *dt) 353 { 354 uint8_t bcd[M41ST84_REG_DATE_BYTES], cmdbuf[2]; 355 int i; 356 357 /* 358 * Convert our time representation into something the M41ST84 359 * can understand. 360 */ 361 bcd[M41ST84_REG_CSEC] = TOBCD(0); /* must always write as 0 */ 362 bcd[M41ST84_REG_SEC] = TOBCD(dt->dt_sec); 363 bcd[M41ST84_REG_MIN] = TOBCD(dt->dt_min); 364 bcd[M41ST84_REG_CENHR] = TOBCD(dt->dt_hour); 365 bcd[M41ST84_REG_DATE] = TOBCD(dt->dt_day); 366 bcd[M41ST84_REG_DAY] = TOBCD(dt->dt_wday); 367 bcd[M41ST84_REG_MONTH] = TOBCD(dt->dt_mon); 368 bcd[M41ST84_REG_YEAR] = TOBCD((dt->dt_year - POSIX_BASE_YEAR) % 100); 369 370 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 371 aprint_error_dev(sc->sc_dev, 372 "strtc_clock_write: failed to acquire I2C bus\n"); 373 return (0); 374 } 375 376 /* Stop the clock */ 377 cmdbuf[0] = M41ST84_REG_SEC; 378 cmdbuf[1] = M41ST84_SEC_ST; 379 380 if (iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address, 381 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 382 iic_release_bus(sc->sc_tag, I2C_F_POLL); 383 aprint_error_dev(sc->sc_dev, 384 "strtc_clock_write: failed to Hold Clock\n"); 385 return (0); 386 } 387 388 /* 389 * Check for the HT bit -- if set, then clock lost power & stopped 390 * If that happened, then clear the bit so that the clock will have 391 * a chance to run again. 392 */ 393 cmdbuf[0] = M41ST84_REG_AL_HOUR; 394 if (iic_exec(sc->sc_tag, I2C_OP_READ, sc->sc_address, 395 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 396 iic_release_bus(sc->sc_tag, I2C_F_POLL); 397 aprint_error_dev(sc->sc_dev, 398 "strtc_clock_write: failed to read HT\n"); 399 return (0); 400 } 401 if (cmdbuf[1] & M41ST84_AL_HOUR_HT) { 402 cmdbuf[1] &= ~M41ST84_AL_HOUR_HT; 403 if (iic_exec(sc->sc_tag, I2C_OP_WRITE, sc->sc_address, 404 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 405 iic_release_bus(sc->sc_tag, I2C_F_POLL); 406 aprint_error_dev(sc->sc_dev, 407 "strtc_clock_write: failed to reset HT\n"); 408 return (0); 409 } 410 } 411 412 /* 413 * Write registers in reverse order. The last write (to the Seconds 414 * register) will undo the Clock Hold, above. 415 */ 416 for (i = M41ST84_REG_DATE_BYTES - 1; i >= 0; i--) { 417 cmdbuf[0] = i; 418 if (iic_exec(sc->sc_tag, 419 i ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, 420 sc->sc_address, cmdbuf, 1, &bcd[i], 1, 421 I2C_F_POLL)) { 422 iic_release_bus(sc->sc_tag, I2C_F_POLL); 423 aprint_error_dev(sc->sc_dev, 424 "strtc_clock_write: failed to write rtc " 425 " at 0x%x\n", i); 426 /* XXX: Clock Hold is likely still asserted! */ 427 return (0); 428 } 429 } 430 431 iic_release_bus(sc->sc_tag, I2C_F_POLL); 432 433 return (1); 434 } 435 436 #ifndef STRTC_NO_WATCHDOG 437 void 438 strtc_wdog_config(void *arg, uint8_t wd) 439 { 440 struct strtc_softc *sc = arg; 441 uint8_t cmdbuf[2]; 442 443 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 444 aprint_error_dev(sc->sc_dev, 445 "strtc_wdog_config: failed to acquire I2C bus\n"); 446 return; 447 } 448 449 cmdbuf[0] = M41ST84_REG_WATCHDOG; 450 cmdbuf[1] = wd; 451 452 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, 453 cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL)) { 454 aprint_error_dev(sc->sc_dev, 455 "strtc_wdog_config: failed to write watchdog\n"); 456 return; 457 } 458 459 iic_release_bus(sc->sc_tag, I2C_F_POLL); 460 } 461 #endif /* STRTC_NO_WATCHDOG */ 462