1 /* $NetBSD: pcf8583.c,v 1.16 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 /* 39 * Driver for the Philips PCF8583 Real Time Clock. 40 * 41 * This driver is partially derived from Ben Harris's PCF8583 driver 42 * for NetBSD/acorn26. 43 */ 44 45 #include <sys/cdefs.h> 46 __KERNEL_RCSID(0, "$NetBSD: pcf8583.c,v 1.16 2014/11/20 16:34:26 christos Exp $"); 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/device.h> 51 #include <sys/kernel.h> 52 #include <sys/fcntl.h> 53 #include <sys/uio.h> 54 #include <sys/conf.h> 55 #include <sys/event.h> 56 57 #include <dev/clock_subr.h> 58 59 #include <dev/i2c/i2cvar.h> 60 #include <dev/i2c/pcf8583reg.h> 61 #include <dev/i2c/pcf8583var.h> 62 63 struct pcfrtc_softc { 64 device_t sc_dev; 65 i2c_tag_t sc_tag; 66 int sc_address; 67 int sc_open; 68 struct todr_chip_handle sc_todr; 69 }; 70 71 static int pcfrtc_match(device_t, cfdata_t, void *); 72 static void pcfrtc_attach(device_t, device_t, void *); 73 74 CFATTACH_DECL_NEW(pcfrtc, sizeof(struct pcfrtc_softc), 75 pcfrtc_match, pcfrtc_attach, NULL, NULL); 76 extern struct cfdriver pcfrtc_cd; 77 78 dev_type_open(pcfrtc_open); 79 dev_type_close(pcfrtc_close); 80 dev_type_read(pcfrtc_read); 81 dev_type_write(pcfrtc_write); 82 83 const struct cdevsw pcfrtc_cdevsw = { 84 .d_open = pcfrtc_open, 85 .d_close = pcfrtc_close, 86 .d_read = pcfrtc_read, 87 .d_write = pcfrtc_write, 88 .d_ioctl = noioctl, 89 .d_stop = nostop, 90 .d_tty = notty, 91 .d_poll = nopoll, 92 .d_mmap = nommap, 93 .d_kqfilter = nokqfilter, 94 .d_discard = nodiscard, 95 .d_flag = D_OTHER 96 }; 97 98 static int pcfrtc_clock_read(struct pcfrtc_softc *, struct clock_ymdhms *, 99 uint8_t *); 100 static int pcfrtc_clock_write(struct pcfrtc_softc *, struct clock_ymdhms *, 101 uint8_t); 102 static int pcfrtc_gettime(struct todr_chip_handle *, struct timeval *); 103 static int pcfrtc_settime(struct todr_chip_handle *, struct timeval *); 104 105 int 106 pcfrtc_match(device_t parent, cfdata_t cf, void *aux) 107 { 108 struct i2c_attach_args *ia = aux; 109 110 if ((ia->ia_addr & PCF8583_ADDRMASK) == PCF8583_ADDR) 111 return (1); 112 113 return (0); 114 } 115 116 void 117 pcfrtc_attach(device_t parent, device_t self, void *aux) 118 { 119 struct pcfrtc_softc *sc = device_private(self); 120 struct i2c_attach_args *ia = aux; 121 uint8_t cmdbuf[1], csr; 122 123 sc->sc_tag = ia->ia_tag; 124 sc->sc_address = ia->ia_addr; 125 sc->sc_dev = self; 126 127 aprint_naive(": Real-time Clock/NVRAM\n"); 128 aprint_normal(": PCF8583 Real-time Clock/NVRAM\n"); 129 130 cmdbuf[0] = PCF8583_REG_CSR; 131 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address, 132 cmdbuf, 1, &csr, 1, 0) != 0) { 133 aprint_error_dev(self, "unable to read CSR\n"); 134 return; 135 } 136 aprint_normal_dev(sc->sc_dev, ""); 137 switch (csr & PCF8583_CSR_FN_MASK) { 138 case PCF8583_CSR_FN_32768HZ: 139 aprint_normal(" 32.768 kHz clock"); 140 break; 141 142 case PCF8583_CSR_FN_50HZ: 143 aprint_normal(" 50 Hz clock"); 144 break; 145 146 case PCF8583_CSR_FN_EVENT: 147 aprint_normal(" event counter"); 148 break; 149 150 case PCF8583_CSR_FN_TEST: 151 aprint_normal(" test mode"); 152 break; 153 } 154 if (csr & PCF8583_CSR_STOP) 155 aprint_normal(", stopped"); 156 if (csr & PCF8583_CSR_ALARMENABLE) 157 aprint_normal(", alarm enabled"); 158 aprint_normal("\n"); 159 160 sc->sc_open = 0; 161 162 sc->sc_todr.cookie = sc; 163 sc->sc_todr.todr_gettime = pcfrtc_gettime; 164 sc->sc_todr.todr_settime = pcfrtc_settime; 165 sc->sc_todr.todr_setwen = NULL; 166 167 todr_attach(&sc->sc_todr); 168 } 169 170 /*ARGSUSED*/ 171 int 172 pcfrtc_open(dev_t dev, int flag, int fmt, struct lwp *l) 173 { 174 struct pcfrtc_softc *sc; 175 176 if ((sc = device_lookup_private(&pcfrtc_cd, minor(dev))) == NULL) 177 return (ENXIO); 178 179 /* XXX: Locking */ 180 181 if (sc->sc_open) 182 return (EBUSY); 183 184 sc->sc_open = 1; 185 return (0); 186 } 187 188 /*ARGSUSED*/ 189 int 190 pcfrtc_close(dev_t dev, int flag, int fmt, struct lwp *l) 191 { 192 struct pcfrtc_softc *sc; 193 194 if ((sc = device_lookup_private(&pcfrtc_cd, minor(dev))) == NULL) 195 return (ENXIO); 196 197 sc->sc_open = 0; 198 return (0); 199 } 200 201 /*ARGSUSED*/ 202 int 203 pcfrtc_read(dev_t dev, struct uio *uio, int flags) 204 { 205 struct pcfrtc_softc *sc; 206 u_int8_t ch, cmdbuf[1]; 207 int a, error; 208 209 if ((sc = device_lookup_private(&pcfrtc_cd, minor(dev))) == NULL) 210 return (ENXIO); 211 212 if (uio->uio_offset >= PCF8583_NVRAM_SIZE) 213 return (EINVAL); 214 215 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 216 return (error); 217 218 while (uio->uio_resid && uio->uio_offset < PCF8583_NVRAM_SIZE) { 219 a = (int)uio->uio_offset; 220 cmdbuf[0] = a + PCF8583_NVRAM_START; 221 if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 222 sc->sc_address, cmdbuf, 1, 223 &ch, 1, 0)) != 0) { 224 iic_release_bus(sc->sc_tag, 0); 225 aprint_error_dev(sc->sc_dev, 226 "pcfrtc_read: read failed at 0x%x\n", a); 227 return (error); 228 } 229 if ((error = uiomove(&ch, 1, uio)) != 0) { 230 iic_release_bus(sc->sc_tag, 0); 231 return (error); 232 } 233 } 234 235 iic_release_bus(sc->sc_tag, 0); 236 237 return (0); 238 } 239 240 /*ARGSUSED*/ 241 int 242 pcfrtc_write(dev_t dev, struct uio *uio, int flags) 243 { 244 struct pcfrtc_softc *sc; 245 u_int8_t cmdbuf[2]; 246 int a, error; 247 248 if ((sc = device_lookup_private(&pcfrtc_cd, minor(dev))) == NULL) 249 return (ENXIO); 250 251 if (uio->uio_offset >= PCF8583_NVRAM_SIZE) 252 return (EINVAL); 253 254 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 255 return (error); 256 257 while (uio->uio_resid && uio->uio_offset < PCF8583_NVRAM_SIZE) { 258 a = (int)uio->uio_offset; 259 cmdbuf[0] = a + PCF8583_NVRAM_START; 260 if ((error = uiomove(&cmdbuf[1], 1, uio)) != 0) 261 break; 262 263 if ((error = iic_exec(sc->sc_tag, 264 uio->uio_resid ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, 265 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, 0)) != 0) { 266 aprint_error_dev(sc->sc_dev, 267 "pcfrtc_write: write failed at 0x%x\n", a); 268 return (error); 269 } 270 } 271 272 iic_release_bus(sc->sc_tag, 0); 273 274 return (error); 275 } 276 277 static int 278 pcfrtc_gettime(struct todr_chip_handle *ch, struct timeval *tv) 279 { 280 struct pcfrtc_softc *sc = ch->cookie; 281 struct clock_ymdhms dt; 282 int err; 283 uint8_t centi; 284 285 if ((err = pcfrtc_clock_read(sc, &dt, ¢i))) 286 return err; 287 288 tv->tv_sec = clock_ymdhms_to_secs(&dt); 289 tv->tv_usec = centi * 10000; 290 291 return (0); 292 } 293 294 static int 295 pcfrtc_settime(struct todr_chip_handle *ch, struct timeval *tv) 296 { 297 struct pcfrtc_softc *sc = ch->cookie; 298 struct clock_ymdhms dt; 299 int err; 300 301 clock_secs_to_ymdhms(tv->tv_sec, &dt); 302 303 if ((err = pcfrtc_clock_write(sc, &dt, tv->tv_usec / 10000)) != 0) 304 return err; 305 306 return (0); 307 } 308 309 static const int pcf8583_rtc_offset[] = { 310 PCF8583_REG_CSR, 311 PCF8583_REG_CENTI, 312 PCF8583_REG_SEC, 313 PCF8583_REG_MIN, 314 PCF8583_REG_HOUR, 315 PCF8583_REG_YEARDATE, 316 PCF8583_REG_WKDYMON, 317 PCF8583_REG_TIMER, 318 0xc0, /* NVRAM -- year stored here */ 319 0xc1, /* NVRAM -- century stored here */ 320 }; 321 322 static int 323 pcfrtc_clock_read(struct pcfrtc_softc *sc, struct clock_ymdhms *dt, 324 uint8_t *centi) 325 { 326 u_int8_t bcd[10], cmdbuf[1]; 327 int i, err; 328 329 if ((err = iic_acquire_bus(sc->sc_tag, I2C_F_POLL))) { 330 aprint_error_dev(sc->sc_dev, 331 "pcfrtc_clock_read: failed to acquire I2C bus\n"); 332 return err; 333 } 334 335 /* Read each timekeeping register in order. */ 336 for (i = 0; i < 10; i++) { 337 cmdbuf[0] = pcf8583_rtc_offset[i]; 338 339 if ((err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 340 sc->sc_address, cmdbuf, 1, 341 &bcd[i], 1, I2C_F_POLL))) { 342 iic_release_bus(sc->sc_tag, I2C_F_POLL); 343 aprint_error_dev(sc->sc_dev, 344 "pcfrtc_clock_read: failed to read rtc " 345 "at 0x%x\n", 346 pcf8583_rtc_offset[i]); 347 return err; 348 } 349 } 350 351 /* Done with I2C */ 352 iic_release_bus(sc->sc_tag, I2C_F_POLL); 353 354 /* 355 * Convert the PCF8583's register values into something useable 356 */ 357 *centi = bcdtobin(bcd[PCF8583_REG_CENTI]); 358 dt->dt_sec = bcdtobin(bcd[PCF8583_REG_SEC]); 359 dt->dt_min = bcdtobin(bcd[PCF8583_REG_MIN]); 360 dt->dt_hour = bcdtobin(bcd[PCF8583_REG_HOUR] & PCF8583_HOUR_MASK); 361 if (bcd[PCF8583_REG_HOUR] & PCF8583_HOUR_12H) { 362 dt->dt_hour %= 12; /* 12AM -> 0, 12PM -> 12 */ 363 if (bcd[PCF8583_REG_HOUR] & PCF8583_HOUR_PM) 364 dt->dt_hour += 12; 365 } 366 367 dt->dt_day = bcdtobin(bcd[PCF8583_REG_YEARDATE] & PCF8583_DATE_MASK); 368 dt->dt_mon = bcdtobin(bcd[PCF8583_REG_WKDYMON] & PCF8583_MON_MASK); 369 370 dt->dt_year = bcd[8] + (bcd[9] * 100); 371 /* Try to notice if the year's rolled over. */ 372 if (bcd[PCF8583_REG_CSR] & PCF8583_CSR_MASK) 373 aprint_error_dev(sc->sc_dev, 374 "cannot check year in mask mode\n"); 375 else { 376 while (dt->dt_year % 4 != 377 (bcd[PCF8583_REG_YEARDATE] & 378 PCF8583_YEAR_MASK) >> PCF8583_YEAR_SHIFT) 379 dt->dt_year++; 380 } 381 382 return 0; 383 } 384 385 static int 386 pcfrtc_clock_write(struct pcfrtc_softc *sc, struct clock_ymdhms *dt, 387 uint8_t centi) 388 { 389 uint8_t bcd[10], cmdbuf[2]; 390 int i, err; 391 392 /* 393 * Convert our time representation into something the PCF8583 394 * can understand. 395 */ 396 bcd[PCF8583_REG_CENTI] = centi; 397 bcd[PCF8583_REG_SEC] = bintobcd(dt->dt_sec); 398 bcd[PCF8583_REG_MIN] = bintobcd(dt->dt_min); 399 bcd[PCF8583_REG_HOUR] = bintobcd(dt->dt_hour) & PCF8583_HOUR_MASK; 400 bcd[PCF8583_REG_YEARDATE] = bintobcd(dt->dt_day) | 401 ((dt->dt_year % 4) << PCF8583_YEAR_SHIFT); 402 bcd[PCF8583_REG_WKDYMON] = bintobcd(dt->dt_mon) | 403 ((dt->dt_wday % 4) << PCF8583_WKDY_SHIFT); 404 bcd[8] = dt->dt_year % 100; 405 bcd[9] = dt->dt_year / 100; 406 407 if ((err = iic_acquire_bus(sc->sc_tag, I2C_F_POLL))) { 408 aprint_error_dev(sc->sc_dev, 409 "pcfrtc_clock_write: failed to acquire I2C bus\n"); 410 return err; 411 } 412 413 for (i = 1; i < 10; i++) { 414 cmdbuf[0] = pcf8583_rtc_offset[i]; 415 if ((err = iic_exec(sc->sc_tag, 416 i != 9 ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, 417 sc->sc_address, cmdbuf, 1, 418 &bcd[i], 1, I2C_F_POLL))) { 419 iic_release_bus(sc->sc_tag, I2C_F_POLL); 420 aprint_error_dev(sc->sc_dev, 421 "pcfrtc_clock_write: failed to write rtc " 422 " at 0x%x\n", 423 pcf8583_rtc_offset[i]); 424 return err; 425 } 426 } 427 428 iic_release_bus(sc->sc_tag, I2C_F_POLL); 429 430 return 0; 431 } 432 433 int 434 pcfrtc_bootstrap_read(i2c_tag_t tag, int i2caddr, int offset, 435 u_int8_t *rvp, size_t len) 436 { 437 u_int8_t cmdbuf[1]; 438 439 /* 440 * NOTE: "offset" is an absolute offset into the PCF8583 441 * address space, not relative to the NVRAM. 442 */ 443 444 if (len == 0) 445 return (0); 446 447 if (iic_acquire_bus(tag, I2C_F_POLL) != 0) 448 return (-1); 449 450 while (len) { 451 /* Read a single byte. */ 452 cmdbuf[0] = offset; 453 if (iic_exec(tag, I2C_OP_READ_WITH_STOP, i2caddr, 454 cmdbuf, 1, rvp, 1, I2C_F_POLL)) { 455 iic_release_bus(tag, I2C_F_POLL); 456 return (-1); 457 } 458 459 len--; 460 rvp++; 461 offset++; 462 } 463 464 iic_release_bus(tag, I2C_F_POLL); 465 return (0); 466 } 467 468 int 469 pcfrtc_bootstrap_write(i2c_tag_t tag, int i2caddr, int offset, 470 u_int8_t *rvp, size_t len) 471 { 472 u_int8_t cmdbuf[1]; 473 474 /* 475 * NOTE: "offset" is an absolute offset into the PCF8583 476 * address space, not relative to the NVRAM. 477 */ 478 479 if (len == 0) 480 return (0); 481 482 if (iic_acquire_bus(tag, I2C_F_POLL) != 0) 483 return (-1); 484 485 while (len) { 486 /* Write a single byte. */ 487 cmdbuf[0] = offset; 488 if (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, i2caddr, 489 cmdbuf, 1, rvp, 1, I2C_F_POLL)) { 490 iic_release_bus(tag, I2C_F_POLL); 491 return (-1); 492 } 493 494 len--; 495 rvp++; 496 offset++; 497 } 498 499 iic_release_bus(tag, I2C_F_POLL); 500 return (0); 501 } 502