Home | History | Annotate | Line # | Download | only in i2c
      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, &centi)))
    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