1 /* $NetBSD: pcf8583.c,v 1.22 2026/10/29 17:43:54 jdc 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 * Additional code written by Dave Tyson to support dual addressing 0x50/0x51 45 * and to select chip operating mode using optional flag in kernel config. 46 * Default with no flag set or flag 0 is existing TOD clock mode, flag 1 sets 47 * 50hz input (TOD clock), flag 2 sets counter mode, flag 3 sets test mode. 48 * 49 * Setting counter mode provides an envsys variable mapped to the counter and 50 * exposes a hw syctl variable which can set to 1 to zero the counter registers 51 * after the next envstat call. 52 */ 53 54 #include <sys/cdefs.h> 55 __KERNEL_RCSID(0, "$NetBSD: pcf8583.c,v 1.22 2026/10/29 17:43:54 jdc Exp $"); 56 57 #include <sys/param.h> 58 #include <sys/systm.h> 59 #include <sys/device.h> 60 #include <sys/kernel.h> 61 #include <sys/sysctl.h> 62 #include <sys/fcntl.h> 63 #include <sys/uio.h> 64 #include <sys/conf.h> 65 #include <sys/event.h> 66 67 #include <dev/clock_subr.h> 68 69 #include <dev/i2c/i2cvar.h> 70 #include <dev/i2c/pcf8583reg.h> 71 #include <dev/i2c/pcf8583var.h> 72 #include <dev/sysmon/sysmonvar.h> 73 74 #include "ioconf.h" 75 76 struct pcfrtc_softc { 77 device_t sc_dev; 78 i2c_tag_t sc_tag; 79 int sc_address; 80 int sc_open; 81 struct todr_chip_handle sc_todr; 82 struct sysmon_envsys *sc_sme; 83 envsys_data_t sc_counter; 84 struct sysctllog *sc_pcfrtclog; 85 int reset_counter; 86 }; 87 88 static int pcfrtc_match(device_t, cfdata_t, void *); 89 static void pcfrtc_attach(device_t, device_t, void *); 90 static int pcfrtc_sysctl_setup(struct pcfrtc_softc *sc); 91 92 CFATTACH_DECL_NEW(pcfrtc, sizeof(struct pcfrtc_softc), 93 pcfrtc_match, pcfrtc_attach, NULL, NULL); 94 95 dev_type_open(pcfrtc_open); 96 dev_type_close(pcfrtc_close); 97 dev_type_read(pcfrtc_read); 98 dev_type_write(pcfrtc_write); 99 100 const struct cdevsw pcfrtc_cdevsw = { 101 .d_open = pcfrtc_open, 102 .d_close = pcfrtc_close, 103 .d_read = pcfrtc_read, 104 .d_write = pcfrtc_write, 105 .d_ioctl = noioctl, 106 .d_stop = nostop, 107 .d_tty = notty, 108 .d_poll = nopoll, 109 .d_mmap = nommap, 110 .d_kqfilter = nokqfilter, 111 .d_discard = nodiscard, 112 .d_flag = D_OTHER 113 }; 114 115 static int pcfrtc_clock_read(struct pcfrtc_softc *, struct clock_ymdhms *, 116 uint8_t *); 117 static int pcfrtc_clock_write(struct pcfrtc_softc *, struct clock_ymdhms *, 118 uint8_t); 119 static int pcfrtc_gettime(struct todr_chip_handle *, struct timeval *); 120 static int pcfrtc_settime(struct todr_chip_handle *, struct timeval *); 121 static void pcfrtc_readcount(struct sysmon_envsys *, envsys_data_t *) ; 122 static int pcfrtc_sysctl_check(SYSCTLFN_ARGS); 123 124 int 125 pcfrtc_match(device_t parent, cfdata_t cf, void *aux) 126 { 127 struct i2c_attach_args *ia = aux; 128 129 if ((ia->ia_addr & PCF8583_ADDRMASK) == PCF8583_ADDR || 130 (ia->ia_addr & PCF8583_ADDRMASK) == PCF8583_ADDR2) 131 return (I2C_MATCH_ADDRESS_ONLY); 132 133 return (0); 134 } 135 136 void 137 pcfrtc_attach(device_t parent, device_t self, void *aux) 138 { 139 struct pcfrtc_softc *sc = device_private(self); 140 struct cfdata *cf = device_cfdata(self); 141 struct i2c_attach_args *ia = aux; 142 uint8_t cmdbuf[1], csr, mode; 143 int error; 144 145 sc->sc_tag = ia->ia_tag; 146 sc->sc_address = ia->ia_addr; 147 sc->sc_dev = self; 148 149 /* if flags set & !zero then need to change device mode */ 150 151 if (cf->cf_flags != 0) { 152 mode = cf->cf_flags << 4 & PCF8583_CSR_FN_MASK; 153 cmdbuf[0] = PCF8583_REG_CSR; 154 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, 155 cmdbuf, 1, &mode, 1, 0) != 0) { 156 aprint_error_dev(self, "unable to write CSR\n"); 157 return; 158 } 159 } 160 161 cmdbuf[0] = PCF8583_REG_CSR; 162 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address, 163 cmdbuf, 1, &csr, 1, 0) != 0) { 164 aprint_error_dev(self, "unable to read CSR\n"); 165 return; 166 } 167 168 switch (csr & PCF8583_CSR_FN_MASK) { 169 case PCF8583_CSR_FN_32768HZ: 170 aprint_naive(": Mode 0: 32768 Hz TOD Clock"); 171 aprint_normal(": PCF8583 Mode 0: 32768 Hz TOD Clock"); 172 break; 173 174 case PCF8583_CSR_FN_50HZ: 175 aprint_naive(": Mode 1: 50Hz TOD Clock"); 176 aprint_normal(": PCF8583 Mode 1: 50Hz TOD Clock"); 177 break; 178 179 case PCF8583_CSR_FN_EVENT: 180 aprint_naive(": Mode 2: Counter"); 181 aprint_normal(": PCF8583 Mode 2: Counter"); 182 break; 183 184 case PCF8583_CSR_FN_TEST: 185 aprint_naive(": Mode 3: Test mode"); 186 aprint_normal(": PCF8583 Mode 3: Test mode"); 187 break; 188 } 189 aprint_normal("\n"); 190 191 sc->sc_open = 0; 192 193 switch (csr & PCF8583_CSR_FN_MASK) { 194 195 case PCF8583_CSR_FN_32768HZ: 196 case PCF8583_CSR_FN_50HZ: 197 sc->sc_todr.todr_dev = self; 198 sc->sc_todr.todr_gettime = pcfrtc_gettime; 199 sc->sc_todr.todr_settime = pcfrtc_settime; 200 201 todr_attach(&sc->sc_todr); 202 break; 203 204 case PCF8583_CSR_FN_EVENT: 205 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) { 206 aprint_error_dev(sc->sc_dev, 207 "unable to create sysmon structure"); 208 sc->sc_sme = NULL; 209 return ; 210 } 211 sc->sc_counter.units=ENVSYS_INTEGER; 212 sc->sc_counter.state=ENVSYS_SINVALID; 213 strlcpy(sc->sc_counter.desc, "counter", 214 sizeof(sc->sc_counter.desc)); 215 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_counter)) { 216 sysmon_envsys_destroy(sc->sc_sme); 217 return; 218 } 219 220 sc->sc_sme->sme_name = device_xname(self) ; 221 sc->sc_sme->sme_refresh = pcfrtc_readcount; 222 sc->sc_sme->sme_cookie = sc; 223 224 if (sysmon_envsys_register(sc->sc_sme)) { 225 sysmon_envsys_destroy(sc->sc_sme); 226 return; 227 } 228 229 /* setup sysctl for resetting counter */ 230 231 if ((error = pcfrtc_sysctl_setup(sc)) !=0) { 232 aprint_error_dev(sc->sc_dev, "cannot setup sysctl tree (%d)\n", error); 233 sysmon_envsys_destroy(sc->sc_sme); 234 } 235 sc->reset_counter = 0; 236 break ; 237 } 238 } 239 240 /*ARGSUSED*/ 241 int 242 pcfrtc_open(dev_t dev, int flag, int fmt, struct lwp *l) 243 { 244 struct pcfrtc_softc *sc; 245 246 if ((sc = device_lookup_private(&pcfrtc_cd, minor(dev))) == NULL) 247 return (ENXIO); 248 249 /* XXX: Locking */ 250 251 if (sc->sc_open) 252 return (EBUSY); 253 254 sc->sc_open = 1; 255 return (0); 256 } 257 258 /*ARGSUSED*/ 259 int 260 pcfrtc_close(dev_t dev, int flag, int fmt, struct lwp *l) 261 { 262 struct pcfrtc_softc *sc; 263 264 if ((sc = device_lookup_private(&pcfrtc_cd, minor(dev))) == NULL) 265 return (ENXIO); 266 267 sc->sc_open = 0; 268 return (0); 269 } 270 271 /*ARGSUSED*/ 272 int 273 pcfrtc_read(dev_t dev, struct uio *uio, int flags) 274 { 275 struct pcfrtc_softc *sc; 276 u_int8_t ch, cmdbuf[1]; 277 int a, error; 278 279 if ((sc = device_lookup_private(&pcfrtc_cd, minor(dev))) == NULL) 280 return (ENXIO); 281 282 if (uio->uio_offset >= PCF8583_NVRAM_SIZE) 283 return (EINVAL); 284 285 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 286 return (error); 287 288 while (uio->uio_resid && uio->uio_offset < PCF8583_NVRAM_SIZE) { 289 a = (int)uio->uio_offset; 290 cmdbuf[0] = a + PCF8583_NVRAM_START; 291 if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 292 sc->sc_address, cmdbuf, 1, 293 &ch, 1, 0)) != 0) { 294 iic_release_bus(sc->sc_tag, 0); 295 aprint_error_dev(sc->sc_dev, 296 "pcfrtc_read: read failed at 0x%x\n", a); 297 return (error); 298 } 299 if ((error = uiomove(&ch, 1, uio)) != 0) { 300 iic_release_bus(sc->sc_tag, 0); 301 return (error); 302 } 303 } 304 305 iic_release_bus(sc->sc_tag, 0); 306 307 return (0); 308 } 309 310 /*ARGSUSED*/ 311 int 312 pcfrtc_write(dev_t dev, struct uio *uio, int flags) 313 { 314 struct pcfrtc_softc *sc; 315 u_int8_t cmdbuf[2]; 316 int a, error; 317 318 if ((sc = device_lookup_private(&pcfrtc_cd, minor(dev))) == NULL) 319 return (ENXIO); 320 321 if (uio->uio_offset >= PCF8583_NVRAM_SIZE) 322 return (EINVAL); 323 324 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 325 return (error); 326 327 while (uio->uio_resid && uio->uio_offset < PCF8583_NVRAM_SIZE) { 328 a = (int)uio->uio_offset; 329 cmdbuf[0] = a + PCF8583_NVRAM_START; 330 if ((error = uiomove(&cmdbuf[1], 1, uio)) != 0) 331 break; 332 333 if ((error = iic_exec(sc->sc_tag, 334 uio->uio_resid ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, 335 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, 0)) != 0) { 336 aprint_error_dev(sc->sc_dev, 337 "pcfrtc_write: write failed at 0x%x\n", a); 338 return (error); 339 } 340 } 341 342 iic_release_bus(sc->sc_tag, 0); 343 344 return (error); 345 } 346 347 static int 348 pcfrtc_gettime(struct todr_chip_handle *ch, struct timeval *tv) 349 { 350 struct pcfrtc_softc *sc = device_private(ch->todr_dev); 351 struct clock_ymdhms dt; 352 int err; 353 uint8_t centi; 354 355 if ((err = pcfrtc_clock_read(sc, &dt, ¢i))) 356 return err; 357 358 tv->tv_sec = clock_ymdhms_to_secs(&dt); 359 tv->tv_usec = centi * 10000; 360 361 return (0); 362 } 363 364 static int 365 pcfrtc_settime(struct todr_chip_handle *ch, struct timeval *tv) 366 { 367 struct pcfrtc_softc *sc = device_private(ch->todr_dev); 368 struct clock_ymdhms dt; 369 int err; 370 371 clock_secs_to_ymdhms(tv->tv_sec, &dt); 372 373 if ((err = pcfrtc_clock_write(sc, &dt, tv->tv_usec / 10000)) != 0) 374 return err; 375 376 return (0); 377 } 378 379 static const int pcf8583_rtc_offset[] = { 380 PCF8583_REG_CSR, 381 PCF8583_REG_CENTI, 382 PCF8583_REG_SEC, 383 PCF8583_REG_MIN, 384 PCF8583_REG_HOUR, 385 PCF8583_REG_YEARDATE, 386 PCF8583_REG_WKDYMON, 387 PCF8583_REG_TIMER, 388 0xc0, /* NVRAM -- year stored here */ 389 0xc1, /* NVRAM -- century stored here */ 390 }; 391 392 static int 393 pcfrtc_clock_read(struct pcfrtc_softc *sc, struct clock_ymdhms *dt, 394 uint8_t *centi) 395 { 396 u_int8_t bcd[10], cmdbuf[1]; 397 int i, err; 398 399 if ((err = iic_acquire_bus(sc->sc_tag, 0))) { 400 aprint_error_dev(sc->sc_dev, 401 "pcfrtc_clock_read: failed to acquire I2C bus\n"); 402 return err; 403 } 404 405 /* Read each timekeeping register in order. */ 406 for (i = 0; i < 10; i++) { 407 cmdbuf[0] = pcf8583_rtc_offset[i]; 408 409 if ((err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 410 sc->sc_address, cmdbuf, 1, 411 &bcd[i], 1, 0))) { 412 iic_release_bus(sc->sc_tag, 0); 413 aprint_error_dev(sc->sc_dev, 414 "pcfrtc_clock_read: failed to read rtc " 415 "at 0x%x\n", 416 pcf8583_rtc_offset[i]); 417 return err; 418 } 419 } 420 421 /* Done with I2C */ 422 iic_release_bus(sc->sc_tag, 0); 423 424 /* 425 * Convert the PCF8583's register values into something useable 426 */ 427 *centi = bcdtobin(bcd[PCF8583_REG_CENTI]); 428 dt->dt_sec = bcdtobin(bcd[PCF8583_REG_SEC]); 429 dt->dt_min = bcdtobin(bcd[PCF8583_REG_MIN]); 430 dt->dt_hour = bcdtobin(bcd[PCF8583_REG_HOUR] & PCF8583_HOUR_MASK); 431 if (bcd[PCF8583_REG_HOUR] & PCF8583_HOUR_12H) { 432 dt->dt_hour %= 12; /* 12AM -> 0, 12PM -> 12 */ 433 if (bcd[PCF8583_REG_HOUR] & PCF8583_HOUR_PM) 434 dt->dt_hour += 12; 435 } 436 437 dt->dt_day = bcdtobin(bcd[PCF8583_REG_YEARDATE] & PCF8583_DATE_MASK); 438 dt->dt_mon = bcdtobin(bcd[PCF8583_REG_WKDYMON] & PCF8583_MON_MASK); 439 440 dt->dt_year = bcd[8] + (bcd[9] * 100); 441 /* Try to notice if the year's rolled over. */ 442 if (bcd[PCF8583_REG_CSR] & PCF8583_CSR_MASK) 443 aprint_error_dev(sc->sc_dev, 444 "cannot check year in mask mode\n"); 445 else { 446 while (dt->dt_year % 4 != 447 (bcd[PCF8583_REG_YEARDATE] & 448 PCF8583_YEAR_MASK) >> PCF8583_YEAR_SHIFT) 449 dt->dt_year++; 450 } 451 452 return 0; 453 } 454 455 static int 456 pcfrtc_clock_write(struct pcfrtc_softc *sc, struct clock_ymdhms *dt, 457 uint8_t centi) 458 { 459 uint8_t bcd[10], cmdbuf[2]; 460 int i, err; 461 462 /* 463 * Convert our time representation into something the PCF8583 464 * can understand. 465 */ 466 bcd[PCF8583_REG_CENTI] = centi; 467 bcd[PCF8583_REG_SEC] = bintobcd(dt->dt_sec); 468 bcd[PCF8583_REG_MIN] = bintobcd(dt->dt_min); 469 bcd[PCF8583_REG_HOUR] = bintobcd(dt->dt_hour) & PCF8583_HOUR_MASK; 470 bcd[PCF8583_REG_YEARDATE] = bintobcd(dt->dt_day) | 471 ((dt->dt_year % 4) << PCF8583_YEAR_SHIFT); 472 bcd[PCF8583_REG_WKDYMON] = bintobcd(dt->dt_mon) | 473 ((dt->dt_wday % 4) << PCF8583_WKDY_SHIFT); 474 bcd[8] = dt->dt_year % 100; 475 bcd[9] = dt->dt_year / 100; 476 477 if ((err = iic_acquire_bus(sc->sc_tag, 0))) { 478 aprint_error_dev(sc->sc_dev, 479 "pcfrtc_clock_write: failed to acquire I2C bus\n"); 480 return err; 481 } 482 483 for (i = 1; i < 10; i++) { 484 cmdbuf[0] = pcf8583_rtc_offset[i]; 485 if ((err = iic_exec(sc->sc_tag, 486 i != 9 ? I2C_OP_WRITE : I2C_OP_WRITE_WITH_STOP, 487 sc->sc_address, cmdbuf, 1, 488 &bcd[i], 1, 0))) { 489 iic_release_bus(sc->sc_tag, 0); 490 aprint_error_dev(sc->sc_dev, 491 "pcfrtc_clock_write: failed to write rtc " 492 " at 0x%x\n", 493 pcf8583_rtc_offset[i]); 494 return err; 495 } 496 } 497 498 iic_release_bus(sc->sc_tag, 0); 499 500 return 0; 501 } 502 503 int 504 pcfrtc_bootstrap_read(i2c_tag_t tag, int i2caddr, int offset, 505 u_int8_t *rvp, size_t len) 506 { 507 u_int8_t cmdbuf[1]; 508 509 /* 510 * NOTE: "offset" is an absolute offset into the PCF8583 511 * address space, not relative to the NVRAM. 512 */ 513 514 if (len == 0) 515 return (0); 516 517 if (iic_acquire_bus(tag, 0) != 0) 518 return (-1); 519 520 while (len) { 521 /* Read a single byte. */ 522 cmdbuf[0] = offset; 523 if (iic_exec(tag, I2C_OP_READ_WITH_STOP, i2caddr, 524 cmdbuf, 1, rvp, 1, 0)) { 525 iic_release_bus(tag, 0); 526 return (-1); 527 } 528 529 len--; 530 rvp++; 531 offset++; 532 } 533 534 iic_release_bus(tag, 0); 535 return (0); 536 } 537 538 int 539 pcfrtc_bootstrap_write(i2c_tag_t tag, int i2caddr, int offset, 540 u_int8_t *rvp, size_t len) 541 { 542 u_int8_t cmdbuf[1]; 543 544 /* 545 * NOTE: "offset" is an absolute offset into the PCF8583 546 * address space, not relative to the NVRAM. 547 */ 548 549 if (len == 0) 550 return (0); 551 552 if (iic_acquire_bus(tag, 0) != 0) 553 return (-1); 554 555 while (len) { 556 /* Write a single byte. */ 557 cmdbuf[0] = offset; 558 if (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, i2caddr, 559 cmdbuf, 1, rvp, 1, 0)) { 560 iic_release_bus(tag, 0); 561 return (-1); 562 } 563 564 len--; 565 rvp++; 566 offset++; 567 } 568 569 iic_release_bus(tag, 0); 570 return (0); 571 } 572 573 int pcfrtc_sysctl_check(SYSCTLFN_ARGS) 574 { 575 struct sysctlnode node; 576 int t, error; 577 578 t = *(int *)rnode->sysctl_data; 579 580 node = *rnode; 581 node.sysctl_data = &t; 582 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 583 if (error || newp == NULL) 584 return (error); 585 586 if (t < 0 || t > 1) 587 return (EINVAL); 588 589 *(int *)rnode->sysctl_data = t; 590 return 0; 591 } 592 593 static int pcfrtc_sysctl_setup(struct pcfrtc_softc *sc) 594 { 595 int error; 596 const struct sysctlnode *cnode; 597 int sysctlroot_num; 598 599 if ((error = sysctl_createv(&sc->sc_pcfrtclog, 0, NULL, &cnode, 600 0, CTLTYPE_NODE, device_xname(sc->sc_dev), 601 SYSCTL_DESCR("pcfrtc counter reset"), NULL, 0, NULL, 0, 602 CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 603 return error; 604 sysctlroot_num = cnode->sysctl_num; 605 606 if ((error = sysctl_createv(&sc->sc_pcfrtclog, 0, NULL, &cnode, 607 CTLFLAG_READWRITE, CTLTYPE_INT, "counter_reset", 608 SYSCTL_DESCR("counter reset"), pcfrtc_sysctl_check, 0, 609 &sc->reset_counter, 0, CTL_HW, 610 sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0) 611 return error; 612 return 0; 613 } 614 615 static void pcfrtc_readcount(struct sysmon_envsys *sme, envsys_data_t *edata) 616 { 617 struct pcfrtc_softc *sc = sme->sme_cookie; 618 int err, i; 619 uint8_t bcd[3],cmdbuf[1]; 620 uint8_t zero=0; 621 622 if ((err = iic_acquire_bus(sc->sc_tag, 0))) { 623 aprint_error_dev(sc->sc_dev, 624 "pcfrtc_readcount: failed to acquire I2C bus\n"); 625 return; 626 } 627 628 for (i = PCF8583_COUNTER0; i <= PCF8583_COUNTER2; i++) { 629 cmdbuf[0] = i; 630 631 if ((err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 632 sc->sc_address, cmdbuf, 1, 633 &bcd[i-1], 1, 0))) { 634 iic_release_bus(sc->sc_tag, 0); 635 aprint_error_dev(sc->sc_dev, 636 "pcfrtc_readcount: failed to read register at %x\n", i); 637 return; 638 } 639 } 640 641 642 edata->value_cur = bcdtobin(bcd[0]) + bcdtobin(bcd[1])*100 + bcdtobin(bcd[2])*10000 ; 643 edata->state = ENVSYS_SVALID ; 644 645 /* if reset_counter = 1 then clear totals */ 646 647 if (sc->reset_counter != 0) { 648 for (i = PCF8583_COUNTER0; i <= PCF8583_COUNTER2; i++) { 649 cmdbuf[0] = i; 650 651 if ((err = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 652 sc->sc_address, cmdbuf, 1, &zero, 1, 0))) { 653 iic_release_bus(sc->sc_tag, 0); 654 aprint_error_dev(sc->sc_dev, 655 "pcfrtc_readcount: failed to write register at %x\n", i); 656 return; 657 } 658 } 659 660 sc->reset_counter = 0 ; 661 } 662 663 iic_release_bus(sc->sc_tag, 0); 664 } 665