Home | History | Annotate | Line # | Download | only in sbmips
rtc.c revision 1.3
      1 /* $NetBSD: rtc.c,v 1.3 2025/09/07 21:45:13 thorpej Exp $ */
      2 
      3 /*
      4  * Copyright 2002 Wasabi Systems, Inc.
      5  * All rights reserved.
      6  *
      7  * Written by Simon Burge 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: rtc.c,v 1.3 2025/09/07 21:45:13 thorpej Exp $");
     40 
     41 #include <sys/param.h>
     42 #include <sys/device.h>
     43 #include <sys/kernel.h>
     44 #include <sys/systm.h>
     45 #include <sys/cpu.h>
     46 
     47 #include <dev/clock_subr.h>
     48 
     49 #include <evbmips/sbmips/swarm.h>
     50 #include <evbmips/sbmips/systemsw.h>
     51 
     52 #include <mips/locore.h>
     53 #include <mips/sibyte/dev/sbsmbusvar.h>
     54 
     55 #include <dev/smbus/m41t81reg.h>
     56 #include <dev/smbus/x1241reg.h>
     57 
     58 struct rtc_softc {
     59 	device_t		sc_dev;
     60 	int			sc_smbus_chan;
     61 	int			sc_smbus_addr;
     62 	int			sc_type;
     63 	struct todr_chip_handle	sc_ct;
     64 };
     65 
     66 /* "types" for RTCs we support */
     67 #define	SMB_1BYTE_ADDR	1
     68 #define	SMB_2BYTE_ADDR	2
     69 
     70 static int xirtc_match(device_t, cfdata_t , void *);
     71 static void xirtc_attach(device_t, device_t, void *);
     72 static int xirtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
     73 static int xirtc_settime(todr_chip_handle_t, struct clock_ymdhms *);
     74 
     75 static int strtc_match(device_t, cfdata_t , void *);
     76 static void strtc_attach(device_t, device_t, void *);
     77 static int strtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
     78 static int strtc_settime(todr_chip_handle_t, struct clock_ymdhms *);
     79 
     80 static void rtc_cal_timer(void);
     81 
     82 static void time_smbus_init(int);
     83 static int time_waitready(int);
     84 static int time_readrtc(int, int, int, int);
     85 static int time_writertc(int, int, int, int, int);
     86 
     87 #define	WRITERTC(sc, dev, val)	\
     88 	time_writertc((sc)->sc_smbus_chan, (sc)->sc_smbus_addr, (dev), (sc)->sc_type, (val))
     89 #define	READRTC(sc, dev)	\
     90 	time_readrtc((sc)->sc_smbus_chan, (sc)->sc_smbus_addr, (dev), (sc)->sc_type)
     91 
     92 
     93 CFATTACH_DECL_NEW(xirtc, sizeof(struct rtc_softc),
     94     xirtc_match, xirtc_attach, NULL, NULL);
     95 
     96 CFATTACH_DECL_NEW(m41t81rtc, sizeof(struct rtc_softc),
     97     strtc_match, strtc_attach, NULL, NULL);
     98 
     99 static int rtcfound = 0;
    100 struct rtc_softc *the_rtc;
    101 
    102 /*
    103  * Xicor X1241 RTC support.
    104  */
    105 static int
    106 xirtc_match(device_t parent, cfdata_t cf, void *aux)
    107 {
    108 	struct smbus_attach_args *sa = aux;
    109 	int ret;
    110 
    111 	time_smbus_init(sa->sa_interface);
    112 
    113 	if ((sa->sa_interface != X1241_SMBUS_CHAN) ||
    114 	    (sa->sa_device != X1241_RTC_SLAVEADDR))
    115 		return (0);
    116 
    117 	ret = time_readrtc(sa->sa_interface, sa->sa_device, SMB_2BYTE_ADDR, X1241REG_SC);
    118 	if (ret < 0)
    119 		return (0);
    120 
    121 	return (!rtcfound);
    122 }
    123 
    124 static void
    125 xirtc_attach(device_t parent, device_t self, void *aux)
    126 {
    127 	struct smbus_attach_args *sa = aux;
    128 	struct rtc_softc *sc = device_private(self);
    129 
    130 	rtcfound = 1;
    131 	the_rtc = sc;
    132 
    133 	sc->sc_dev = self;
    134 	sc->sc_smbus_chan = sa->sa_interface;
    135 	sc->sc_smbus_addr = sa->sa_device;
    136 	sc->sc_type = SMB_2BYTE_ADDR;	/* Two-byte register addresses on the Xicor */
    137 
    138 
    139 	/* Set up MI todr(9) stuff */
    140 	sc->sc_ct.todr_dev = self;
    141 	sc->sc_ct.todr_settime_ymdhms = xirtc_settime;
    142 	sc->sc_ct.todr_gettime_ymdhms = xirtc_gettime;
    143 
    144 	todr_attach(&sc->sc_ct);
    145 
    146 	aprint_normal("\n");
    147 	rtc_cal_timer();	/* XXX */
    148 }
    149 
    150 static int
    151 xirtc_settime(todr_chip_handle_t handle, struct clock_ymdhms *ymdhms)
    152 {
    153 	struct rtc_softc *sc = device_private(handle->todr_dev);
    154 	uint8_t year, y2k;
    155 
    156 	time_smbus_init(sc->sc_smbus_chan);
    157 
    158 	/* unlock writes to the CCR */
    159 	WRITERTC(sc, X1241REG_SR, X1241REG_SR_WEL);
    160 	WRITERTC(sc, X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL);
    161 
    162 	/* set the time */
    163 	WRITERTC(sc, X1241REG_HR, bintobcd(ymdhms->dt_hour) | X1241REG_HR_MIL);
    164 	WRITERTC(sc, X1241REG_MN, bintobcd(ymdhms->dt_min));
    165 	WRITERTC(sc, X1241REG_SC, bintobcd(ymdhms->dt_sec));
    166 
    167 	/* set the date */
    168 	y2k = (ymdhms->dt_year >= 2000) ? 0x20 : 0x19;
    169 	year = ymdhms->dt_year % 100;
    170 
    171 	WRITERTC(sc, X1241REG_MO, bintobcd(ymdhms->dt_mon));
    172 	WRITERTC(sc, X1241REG_DT, bintobcd(ymdhms->dt_day));
    173 	WRITERTC(sc, X1241REG_YR, bintobcd(year));
    174 	WRITERTC(sc, X1241REG_Y2K, bintobcd(y2k));
    175 
    176 	/* lock writes again */
    177 	WRITERTC(sc, X1241REG_SR, 0);
    178 
    179 	return (0);
    180 }
    181 
    182 static int
    183 xirtc_gettime(todr_chip_handle_t handle, struct clock_ymdhms *ymdhms)
    184 {
    185 	struct rtc_softc *sc = device_private(handle->todr_dev);
    186 	uint8_t hour, year, y2k;
    187 	uint8_t status;
    188 
    189 	time_smbus_init(sc->sc_smbus_chan);
    190 	ymdhms->dt_day = bcdtobin(READRTC(sc, X1241REG_DT));
    191 	ymdhms->dt_mon =  bcdtobin(READRTC(sc, X1241REG_MO));
    192 	year =  READRTC(sc, X1241REG_YR);
    193 	y2k = READRTC(sc, X1241REG_Y2K);
    194 	ymdhms->dt_year = bcdtobin(y2k) * 100 + bcdtobin(year);
    195 
    196 
    197 	ymdhms->dt_sec = bcdtobin(READRTC(sc, X1241REG_SC));
    198 	ymdhms->dt_min = bcdtobin(READRTC(sc, X1241REG_MN));
    199 	hour = READRTC(sc, X1241REG_HR);
    200 	ymdhms->dt_hour = bcdtobin(hour & ~X1241REG_HR_MIL);
    201 
    202 	status = READRTC(sc, X1241REG_SR);
    203 
    204 	if (status & X1241REG_SR_RTCF) {
    205 		printf("%s: battery has failed, clock setting is not accurate\n",
    206 		    device_xname(sc->sc_dev));
    207 		return (EIO);
    208 	}
    209 
    210 	return (0);
    211 }
    212 
    213 /*
    214  * ST M41T81 RTC support.
    215  */
    216 static int
    217 strtc_match(device_t parent, cfdata_t cf, void *aux)
    218 {
    219 	struct smbus_attach_args *sa = aux;
    220 	int ret;
    221 
    222 	if ((sa->sa_interface != M41T81_SMBUS_CHAN) ||
    223 	    (sa->sa_device != M41T81_SLAVEADDR))
    224 		return (0);
    225 
    226 	time_smbus_init(sa->sa_interface);
    227 
    228 	ret = time_readrtc(sa->sa_interface, sa->sa_device, SMB_1BYTE_ADDR, M41T81_SEC);
    229 	if (ret < 0)
    230 		return (0);
    231 
    232 	return (!rtcfound);
    233 }
    234 
    235 static void
    236 strtc_attach(device_t parent, device_t self, void *aux)
    237 {
    238 	struct smbus_attach_args *sa = aux;
    239 	struct rtc_softc *sc = device_private(self);
    240 
    241 	rtcfound = 1;
    242 	the_rtc = sc;
    243 
    244 	sc->sc_dev = self;
    245 	sc->sc_smbus_chan = sa->sa_interface;
    246 	sc->sc_smbus_addr = sa->sa_device;
    247 	sc->sc_type = SMB_1BYTE_ADDR;	/* One-byte register addresses on the ST */
    248 
    249 	/* Set up MI todr(9) stuff */
    250 	sc->sc_ct.todr_dev = self;
    251 	sc->sc_ct.todr_settime_ymdhms = strtc_settime;
    252 	sc->sc_ct.todr_gettime_ymdhms = strtc_gettime;
    253 
    254 	todr_attach(&sc->sc_ct);
    255 
    256 	aprint_normal("\n");
    257 	rtc_cal_timer();	/* XXX */
    258 }
    259 
    260 static int
    261 strtc_settime(todr_chip_handle_t handle, struct clock_ymdhms *ymdhms)
    262 {
    263 	struct rtc_softc *sc = device_private(handle->todr_dev);
    264 	uint8_t hour;
    265 
    266 	time_smbus_init(sc->sc_smbus_chan);
    267 
    268 	hour = bintobcd(ymdhms->dt_hour);
    269 	if (ymdhms->dt_year >= 2000)	/* Should be always true! */
    270 		hour |= M41T81_HOUR_CB | M41T81_HOUR_CEB;
    271 
    272 	/* set the time */
    273 	WRITERTC(sc, M41T81_SEC, bintobcd(ymdhms->dt_sec));
    274 	WRITERTC(sc, M41T81_MIN, bintobcd(ymdhms->dt_min));
    275 	WRITERTC(sc, M41T81_HOUR, hour);
    276 
    277 	/* set the date */
    278 	WRITERTC(sc, M41T81_DATE, bintobcd(ymdhms->dt_day));
    279 	WRITERTC(sc, M41T81_MON, bintobcd(ymdhms->dt_mon));
    280 	WRITERTC(sc, M41T81_YEAR, bintobcd(ymdhms->dt_year % 100));
    281 
    282 	return (0);
    283 }
    284 
    285 static int
    286 strtc_gettime(todr_chip_handle_t handle, struct clock_ymdhms *ymdhms)
    287 {
    288 	struct rtc_softc *sc = device_private(handle->todr_dev);
    289 	uint8_t hour;
    290 
    291 	time_smbus_init(sc->sc_smbus_chan);
    292 
    293 	ymdhms->dt_sec = bcdtobin(READRTC(sc, M41T81_SEC));
    294 	ymdhms->dt_min = bcdtobin(READRTC(sc, M41T81_MIN));
    295 	hour = READRTC(sc, M41T81_HOUR & M41T81_HOUR_MASK);
    296 	ymdhms->dt_hour = bcdtobin(hour & M41T81_HOUR_MASK);
    297 
    298 	ymdhms->dt_day = bcdtobin(READRTC(sc, M41T81_DATE));
    299 	ymdhms->dt_mon =  bcdtobin(READRTC(sc, M41T81_MON));
    300 	ymdhms->dt_year =  1900 + bcdtobin(READRTC(sc, M41T81_YEAR));
    301 	if (hour & M41T81_HOUR_CB)
    302 		ymdhms->dt_year += 100;
    303 
    304 	return (0);
    305 }
    306 
    307 #define	NITERS			3
    308 #define	RTC_SECONDS(rtc)	bcdtobin(READRTC((rtc), X1241REG_SC))
    309 
    310 /*
    311  * Since it takes so long to read the complete time/date values from
    312  * the RTC over the SMBus, we only read the seconds value.
    313  * Later versions of the SWARM will hopefully have the RTC interrupt
    314  * attached so we can do the clock calibration much more quickly and
    315  * with a higher resolution.
    316  */
    317 static void
    318 rtc_cal_timer(void)
    319 {
    320 	uint32_t ctrdiff[NITERS], startctr, endctr;
    321 	int sec, lastsec, i;
    322 
    323 	if (rtcfound == 0) {
    324 		printf("rtc_cal_timer before rtc attached\n");
    325 		return;
    326 	}
    327 return;	/* XXX XXX */
    328 
    329 	printf("%s: calibrating CPU clock", device_xname(the_rtc->sc_dev));
    330 
    331 	/*
    332 	 * Run the loop an extra time to wait for the second to tick over
    333 	 * and to prime the cache.
    334 	 */
    335 	time_smbus_init(the_rtc->sc_smbus_chan);
    336 	sec = RTC_SECONDS(the_rtc);
    337 	endctr = mips3_cp0_count_read();
    338 
    339 	for (i = 0; i < NITERS; i++) {
    340 		int diff;
    341 
    342  again:
    343 		lastsec = sec;
    344 		startctr = endctr;
    345 
    346 		/* Wait for the timer to tick over. */
    347 		do {
    348 			// time_smbus_init(the_rtc->sc_smbus_chan);
    349 			sec = RTC_SECONDS(the_rtc);
    350 		} while (lastsec == sec);
    351 		endctr = mips3_cp0_count_read();
    352 
    353 		diff = sec - lastsec;
    354 		if (diff < 0)
    355 			diff += 60;
    356 
    357 		/* Sometimes we appear to skip a second.  Clock jitter? */
    358 		if (diff > 1)
    359 			goto again;
    360 
    361 		if (endctr < startctr)
    362 			ctrdiff[i] = 0xffffffff - startctr + endctr;
    363 		else
    364 			ctrdiff[i] = endctr - startctr;
    365 	}
    366 	printf("\n");
    367 
    368 	/* Compute the number of cycles per second. */
    369 	curcpu()->ci_cpu_freq = ((ctrdiff[1] + ctrdiff[2]) / 2);
    370 
    371 	/* Compute the delay divisor. */
    372 	curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / 1000000;
    373 
    374 	/* Compute clock cycles per hz */
    375 	curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / hz;
    376 
    377 	printf("%s: timer calibration: %lu cycles/sec [(%u, %u)]\n",
    378 	    device_xname(the_rtc->sc_dev), curcpu()->ci_cpu_freq,
    379 	    ctrdiff[1], ctrdiff[2]);
    380 }
    381 #undef RTC_SECONDS
    382 
    383 /* XXX eville direct-access-to-the-device code follows... */
    384 
    385 /*
    386  * Copyright 2000,2001
    387  * Broadcom Corporation. All rights reserved.
    388  *
    389  * This software is furnished under license and may be used and copied only
    390  * in accordance with the following terms and conditions.  Subject to these
    391  * conditions, you may download, copy, install, use, modify and distribute
    392  * modified or unmodified copies of this software in source and/or binary
    393  * form. No title or ownership is transferred hereby.
    394  *
    395  * 1) Any source code used, modified or distributed must reproduce and
    396  *    retain this copyright notice and list of conditions as they appear in
    397  *    the source file.
    398  *
    399  * 2) No right is granted to use any trade name, trademark, or logo of
    400  *    Broadcom Corporation.  The "Broadcom Corporation" name may not be
    401  *    used to endorse or promote products derived from this software
    402  *    without the prior written permission of Broadcom Corporation.
    403  *
    404  * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
    405  *    WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
    406  *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
    407  *    NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
    408  *    FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
    409  *    LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    410  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    411  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    412  *    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    413  *    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    414  *    OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    415  */
    416 
    417 #include <mips/sibyte/include/sb1250_regs.h>
    418 #include <mips/sibyte/include/sb1250_smbus.h>
    419 
    420 #define	READ_REG(rp)		mips3_ld((register_t)(MIPS_PHYS_TO_KSEG1(rp)))
    421 #define	WRITE_REG(rp, val)	mips3_sd((register_t)(MIPS_PHYS_TO_KSEG1(rp)), (val))
    422 
    423 static void
    424 time_smbus_init(int chan)
    425 {
    426 	uint32_t reg;
    427 
    428 	reg = A_SMB_REGISTER(chan, R_SMB_FREQ);
    429 	WRITE_REG(reg, K_SMB_FREQ_100KHZ);
    430 	reg = A_SMB_REGISTER(chan, R_SMB_CONTROL);
    431 	WRITE_REG(reg, 0);	/* not in direct mode, no interrupts, will poll */
    432 }
    433 
    434 static int
    435 time_waitready(int chan)
    436 {
    437 	uint32_t reg;
    438 	uint64_t status;
    439 
    440 	reg = A_SMB_REGISTER(chan, R_SMB_STATUS);
    441 
    442 	for (;;) {
    443 		status = READ_REG(reg);
    444 		if (status & M_SMB_BUSY)
    445 			continue;
    446 		break;
    447 	}
    448 
    449 	if (status & M_SMB_ERROR) {
    450 		WRITE_REG(reg, (status & M_SMB_ERROR));
    451 		return (-1);
    452 	}
    453 	return (0);
    454 }
    455 
    456 static int
    457 time_readrtc(int chan, int slaveaddr, int devaddr, int type)
    458 {
    459 	uint32_t reg;
    460 	int err;
    461 
    462 	/*
    463 	 * Make sure the bus is idle (probably should
    464 	 * ignore error here)
    465 	 */
    466 
    467 	if (time_waitready(chan) < 0)
    468 		return (-1);
    469 
    470 	if (type == SMB_2BYTE_ADDR) {
    471 		/*
    472 		 * Write the device address to the controller. There are two
    473 		 * parts, the high part goes in the "CMD" field, and the
    474 		 * low part is the data field.
    475 		 */
    476 
    477 		reg = A_SMB_REGISTER(chan, R_SMB_CMD);
    478 		WRITE_REG(reg, (devaddr >> 8) & 0x7);
    479 
    480 		/*
    481 		 * Write the data to the controller
    482 		 */
    483 
    484 		reg = A_SMB_REGISTER(chan, R_SMB_DATA);
    485 		WRITE_REG(reg, (devaddr & 0xff) & 0xff);
    486 	} else { /* SMB_1BYTE_ADDR */
    487 		/*
    488 		 * Write the device address to the controller.
    489 		 */
    490 
    491 		reg = A_SMB_REGISTER(chan, R_SMB_CMD);
    492 		WRITE_REG(reg, devaddr & 0xff);
    493 	}
    494 
    495 	/*
    496 	 * Start the command
    497 	 */
    498 
    499 	reg = A_SMB_REGISTER(chan, R_SMB_START);
    500 	if (type == SMB_2BYTE_ADDR)
    501 		WRITE_REG(reg, V_SMB_TT(K_SMB_TT_WR2BYTE) | V_SMB_ADDR(slaveaddr));
    502 	else /* SMB_1BYTE_ADDR */
    503 		WRITE_REG(reg, V_SMB_TT(K_SMB_TT_WR1BYTE) | V_SMB_ADDR(slaveaddr));
    504 
    505 	/*
    506 	 * Wait till done
    507 	 */
    508 
    509 	err = time_waitready(chan);
    510 	if (err < 0)
    511 		return (err);
    512 
    513 	/*
    514 	 * Read the data byte
    515 	 */
    516 
    517 	WRITE_REG(reg, V_SMB_TT(K_SMB_TT_RD1BYTE) | V_SMB_ADDR(slaveaddr));
    518 
    519 	err = time_waitready(chan);
    520 	if (err < 0)
    521 		return (err);
    522 
    523 	reg = A_SMB_REGISTER(chan, R_SMB_DATA);
    524 	err = READ_REG(reg);
    525 
    526 	return (err & 0xff);
    527 }
    528 
    529 static int
    530 time_writertc(int chan, int slaveaddr, int devaddr, int type, int b)
    531 {
    532 	uint32_t reg;
    533 	int err, timer;
    534 
    535 	/*
    536 	 * Make sure the bus is idle (probably should
    537 	 * ignore error here)
    538 	 */
    539 
    540 	if (time_waitready(chan) < 0)
    541 		return (-1);
    542 
    543 	/*
    544 	 * Write the device address to the controller. There are two
    545 	 * parts, the high part goes in the "CMD" field, and the
    546 	 * low part is the data field.
    547 	 */
    548 
    549 	reg = A_SMB_REGISTER(chan, R_SMB_CMD);
    550 	if (type == SMB_2BYTE_ADDR)
    551 		WRITE_REG(reg, (devaddr >> 8) & 0x7);
    552 	else /* SMB_1BYTE_ADDR */
    553 		WRITE_REG(reg, devaddr & 0xff);
    554 
    555 	/*
    556 	 * Write the data to the controller
    557 	 */
    558 
    559 	reg = A_SMB_REGISTER(chan, R_SMB_DATA);
    560 	if (type == SMB_2BYTE_ADDR)
    561 		WRITE_REG(reg, (devaddr & 0xff) | ((b & 0xff) << 8));
    562 	else /* SMB_1BYTE_ADDR */
    563 		WRITE_REG(reg, b & 0xff);
    564 
    565 	/*
    566 	 * Start the command.  Keep pounding on the device until it
    567 	 * submits or the timer expires, whichever comes first.  The
    568 	 * datasheet says writes can take up to 10ms, so we'll give it 500.
    569 	 */
    570 
    571 	reg = A_SMB_REGISTER(chan, R_SMB_START);
    572 	if (type == SMB_2BYTE_ADDR)
    573 		WRITE_REG(reg, V_SMB_TT(K_SMB_TT_WR3BYTE) | V_SMB_ADDR(slaveaddr));
    574 	else /* SMB_1BYTE_ADDR */
    575 		WRITE_REG(reg, V_SMB_TT(K_SMB_TT_WR2BYTE) | V_SMB_ADDR(slaveaddr));
    576 
    577 	/*
    578 	 * Wait till the SMBus interface is done
    579 	 */
    580 
    581 	err = time_waitready(chan);
    582 	if (err < 0)
    583 		return (err);
    584 
    585 	/*
    586 	 * Pound on the device with a current address read
    587 	 * to poll for the write complete
    588 	 */
    589 
    590 	err = -1;
    591 	timer = 100000000;	/* XXX */
    592 
    593 	while (timer-- > 0) {
    594 		WRITE_REG(reg, V_SMB_TT(K_SMB_TT_RD1BYTE) | V_SMB_ADDR(slaveaddr));
    595 
    596 		err = time_waitready(chan);
    597 		if (err == 0)
    598 			break;
    599 	}
    600 
    601 	return (err);
    602 }
    603