Home | History | Annotate | Line # | Download | only in ingenic
jziic.c revision 1.6
      1 /*	$NetBSD: jziic.c,v 1.6 2019/12/22 23:23:31 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2015 Michael Lorenz
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: jziic.c,v 1.6 2019/12/22 23:23:31 thorpej Exp $");
     31 
     32 /*
     33  * a preliminary driver for JZ4780's on-chip SMBus controllers
     34  * - needs more error handling and interrupt support
     35  * - transfers can't be more than the chip's FIFO, supposedly 16 bytes per
     36  *   direction
     37  * so, good enough for RTCs but not much else yet
     38  */
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/kernel.h>
     43 #include <sys/device.h>
     44 #include <sys/mutex.h>
     45 #include <sys/bus.h>
     46 #include <sys/mutex.h>
     47 #include <sys/condvar.h>
     48 
     49 #include <mips/ingenic/ingenic_var.h>
     50 #include <mips/ingenic/ingenic_regs.h>
     51 
     52 #include <dev/i2c/i2cvar.h>
     53 
     54 #include "opt_ingenic.h"
     55 
     56 #ifdef JZIIC_DEBUG
     57 #define DPRINTF aprint_error
     58 #define STATIC /* */
     59 #else
     60 #define DPRINTF while (0) printf
     61 #define STATIC static
     62 #endif
     63 
     64 STATIC int jziic_match(device_t, struct cfdata *, void *);
     65 STATIC void jziic_attach(device_t, device_t, void *);
     66 
     67 struct jziic_softc {
     68 	device_t 		sc_dev;
     69 	bus_space_tag_t 	sc_memt;
     70 	bus_space_handle_t 	sc_memh;
     71 	struct i2c_controller 	sc_i2c;
     72 	kmutex_t		sc_cvlock;
     73 	uint32_t		sc_pclk;
     74 	/* stuff used for interrupt-driven transfers */
     75 	const uint8_t		*sc_cmd;
     76 	uint8_t			*sc_buf;
     77 	uint32_t		sc_cmdlen, sc_buflen;
     78 	uint32_t		sc_cmdptr, sc_bufptr, sc_rds;
     79 	uint32_t		sc_abort;
     80 	kcondvar_t		sc_ping;
     81 	uint8_t			sc_txbuf[256];
     82 	boolean_t		sc_reading;
     83 };
     84 
     85 CFATTACH_DECL_NEW(jziic, sizeof(struct jziic_softc),
     86     jziic_match, jziic_attach, NULL, NULL);
     87 
     88 STATIC int jziic_enable(struct jziic_softc *);
     89 STATIC void jziic_disable(struct jziic_softc *);
     90 STATIC int jziic_wait(struct jziic_softc *);
     91 STATIC void jziic_set_speed(struct jziic_softc *);
     92 STATIC int jziic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
     93 		    void *, size_t, int);
     94 STATIC int jziic_i2c_exec_poll(struct jziic_softc *, i2c_op_t, i2c_addr_t,
     95     const void *, size_t, void *, size_t, int);
     96 STATIC int jziic_i2c_exec_intr(struct jziic_softc *, i2c_op_t, i2c_addr_t,
     97     const void *, size_t, void *, size_t, int);
     98 
     99 STATIC int jziic_intr(void *);
    100 
    101 
    102 /* ARGSUSED */
    103 STATIC int
    104 jziic_match(device_t parent, struct cfdata *match, void *aux)
    105 {
    106 	struct apbus_attach_args *aa = aux;
    107 
    108 	if (strcmp(aa->aa_name, "jziic") != 0)
    109 		return 0;
    110 
    111 	return 1;
    112 }
    113 
    114 /* ARGSUSED */
    115 STATIC void
    116 jziic_attach(device_t parent, device_t self, void *aux)
    117 {
    118 	struct jziic_softc *sc = device_private(self);
    119 	struct apbus_attach_args *aa = aux;
    120 	struct i2cbus_attach_args iba;
    121 	int error;
    122 	void *ih;
    123 #ifdef JZIIC_DEBUG
    124 	int i;
    125 	uint8_t in[1] = {0}, out[16];
    126 #endif
    127 
    128 	sc->sc_dev = self;
    129 	sc->sc_pclk = aa->aa_pclk;
    130 	sc->sc_memt = aa->aa_bst;
    131 
    132 	error = bus_space_map(aa->aa_bst, aa->aa_addr, 0x100, 0, &sc->sc_memh);
    133 	if (error) {
    134 		aprint_error_dev(self,
    135 		    "can't map registers for %s: %d\n", aa->aa_name, error);
    136 		return;
    137 	}
    138 
    139 	mutex_init(&sc->sc_cvlock, MUTEX_DEFAULT, IPL_NONE);
    140 	cv_init(&sc->sc_ping, device_xname(self));
    141 
    142 	aprint_naive(": SMBus controller\n");
    143 	aprint_normal(": SMBus controller\n");
    144 
    145 	ih = evbmips_intr_establish(aa->aa_irq, jziic_intr, sc);
    146 
    147 	if (ih == NULL) {
    148 		aprint_error_dev(self, "failed to establish interrupt %d\n",
    149 		     aa->aa_irq);
    150 		goto fail;
    151 	}
    152 
    153 #ifdef JZIIC_DEBUG
    154 	if (jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP, 0x51, in, 1, out, 9, 0)
    155 	    >= 0) {
    156 		for (i = 0; i < 9; i++)
    157 			printf(" %02x", out[i]);
    158 		printf("\n");
    159 		delay(1000000);
    160 		jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP,
    161 		    0x51, in, 1, out, 9, 0);
    162 		for (i = 0; i < 9; i++)
    163 			printf(" %02x", out[i]);
    164 		printf("\n");
    165 		delay(1000000);
    166 		jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP,
    167 		    0x51, in, 1, out, 9, 0);
    168 		for (i = 0; i < 9; i++)
    169 			printf(" %02x", out[i]);
    170 		printf("\n");
    171 	}
    172 #endif
    173 
    174 	/* fill in the i2c tag */
    175 	iic_tag_init(&sc->sc_i2c);
    176 	sc->sc_i2c.ic_cookie = sc;
    177 	sc->sc_i2c.ic_exec = jziic_i2c_exec;
    178 
    179 	memset(&iba, 0, sizeof(iba));
    180 	iba.iba_tag = &sc->sc_i2c;
    181 	(void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
    182 
    183 
    184 	return;
    185 
    186 fail:
    187 	if (ih) {
    188 		evbmips_intr_disestablish(ih);
    189 	}
    190 	bus_space_unmap(sc->sc_memt, sc->sc_memh, 0x100);
    191 }
    192 
    193 STATIC int
    194 jziic_enable(struct jziic_softc *sc)
    195 {
    196 	int bail = 100000;
    197 	uint32_t reg;
    198 
    199 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, JZ_ENABLE);
    200 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    201 	DPRINTF("status: %02x\n", reg);
    202 	while ((bail > 0) && (reg == 0)) {
    203 		bail--;
    204 		reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    205 	}
    206 	DPRINTF("bail: %d\n", bail);
    207 	return (reg != 0);
    208 }
    209 
    210 STATIC void
    211 jziic_disable(struct jziic_softc *sc)
    212 {
    213 	int bail = 100000;
    214 	uint32_t reg;
    215 
    216 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, 0);
    217 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    218 	DPRINTF("status: %02x\n", reg);
    219 	while ((bail > 0) && (reg != 0)) {
    220 		bail--;
    221 		reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    222 	}
    223 	DPRINTF("bail: %d\n", bail);
    224 }
    225 
    226 STATIC int
    227 jziic_wait(struct jziic_softc *sc)
    228 {
    229 	uint32_t reg;
    230 	int bail = 10000;
    231 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST);
    232 	while ((reg & JZ_MSTACT) && (bail > 0)) {
    233 		delay(100);
    234 		reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST);
    235 		bail--;
    236 	}
    237 	return ((reg & JZ_MSTACT) == 0);
    238 }
    239 
    240 STATIC void
    241 jziic_set_speed(struct jziic_softc *sc)
    242 {
    243 	int ticks, hcnt, lcnt, hold, setup;
    244 
    245 	/* PCLK ticks per SMBus cycle */
    246 	ticks = sc->sc_pclk / 100; /* assuming 100kHz for now */
    247 	hcnt = (ticks * 40 / (40 + 47)) - 8;
    248 	lcnt = (ticks * 47 / (40 + 47)) - 1;
    249 	hold = sc->sc_pclk * 4 / 10000 - 1; /* ... * 400 / 1000000 ... */
    250 	hold = uimax(1, hold);
    251 	hold |= JZ_HDENB;
    252 	setup = sc->sc_pclk * 3 / 10000 + 1; /* ... * 300 / 1000000 ... */
    253 	DPRINTF("hcnt %d lcnt %d hold %d\n", hcnt, lcnt, hold);
    254 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSHCNT, hcnt);
    255 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSLCNT, lcnt);
    256 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDAHD, hold);
    257 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDASU, setup);
    258 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON,
    259 	    JZ_SLVDIS | JZ_STPHLD | JZ_REST | JZ_SPD_100KB | JZ_MD);
    260 	(void)bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT);
    261 }
    262 
    263 STATIC int
    264 jziic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
    265     size_t cmdlen, void *vbuf, size_t buflen, int flags)
    266 {
    267 	struct jziic_softc *sc = cookie;
    268 
    269 	if (cold || (flags & I2C_F_POLL)) {
    270 		return jziic_i2c_exec_poll(sc, op, addr, vcmd, cmdlen, vbuf,
    271 		    buflen, flags);
    272 	} else {
    273 #ifdef JZIIC_DEBUG
    274 		uint8_t *b = vbuf;
    275 		int i, ret;
    276 
    277 		memset(vbuf, 0, buflen);
    278 		jziic_i2c_exec_intr(sc, op, addr, vcmd, cmdlen, vbuf,
    279 		    buflen, flags);
    280 		for (i = 0; i < buflen; i++) {
    281 			printf(" %02x", b[i]);
    282 		}
    283 		printf("\n");
    284 		ret = jziic_i2c_exec_poll(sc, op, addr, vcmd, cmdlen, vbuf,
    285 		    buflen, flags);
    286 		for (i = 0; i < buflen; i++) {
    287 			printf(" %02x", b[i]);
    288 		}
    289 		printf("\n");
    290 		return ret;
    291 #else
    292 		return jziic_i2c_exec_intr(sc, op, addr, vcmd, cmdlen, vbuf,
    293 		    buflen, flags);
    294 #endif
    295 	}
    296 }
    297 
    298 STATIC int
    299 jziic_i2c_exec_poll(struct jziic_softc *sc, i2c_op_t op, i2c_addr_t addr,
    300     const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
    301 {
    302 	int i, bail = 10000, ret = 0;
    303 	uint32_t abort;
    304 	uint8_t *rx, data;
    305 	const uint8_t *tx;
    306 
    307 	tx = vcmd;
    308 	rx = vbuf;
    309 
    310 	DPRINTF("%s: 0x%02x %d %d\n", __func__, addr, cmdlen, buflen);
    311 
    312 	jziic_disable(sc);
    313 
    314 	/* we're polling, so disable interrupts */
    315 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    316 
    317 	jziic_set_speed(sc);
    318 	jziic_wait(sc);
    319 	/* try to talk... */
    320 
    321 	if (!jziic_enable(sc)) {
    322 		ret = -1;
    323 		goto bork;
    324 	}
    325 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    326 
    327 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTAR, addr);
    328 	jziic_wait(sc);
    329 	DPRINTF("st: %02x\n",
    330 	    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST));
    331 	DPRINTF("wr int: %02x\n",
    332 	    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST));
    333 	abort = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC);
    334 	DPRINTF("abort: %02x\n", abort);
    335 	if ((abort != 0)) {
    336 		ret = -1;
    337 		goto bork;
    338 	}
    339 
    340 	do {
    341 		bail--;
    342 		delay(100);
    343 	} while (((bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST) &
    344 	           JZ_TFE) == 0) && (bail > 0));
    345 
    346 	if (cmdlen != 0) {
    347 		for (i = 0; i < cmdlen; i++) {
    348 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    349 			    JZ_SMBDC, *tx);
    350 			tx++;
    351 		}
    352 	}
    353 
    354 	if (I2C_OP_READ_P(op)) {
    355 		/* now read */
    356 		for (i = 0; i < (buflen + 1); i++) {
    357 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    358 			    JZ_SMBDC, JZ_CMD);
    359 		}
    360 		wbflush();
    361 		DPRINTF("rd st: %02x\n",
    362 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST));
    363 		DPRINTF("rd int: %02x\n",
    364 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST));
    365 		DPRINTF("abort: %02x\n",
    366 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC));
    367 		for (i = 0; i < buflen; i++) {
    368 			bail = 10000;
    369 			while (((bus_space_read_4(sc->sc_memt, sc->sc_memh,
    370 				  JZ_SMBST) & JZ_RFNE) == 0) && (bail > 0)) {
    371 				bail--;
    372 				delay(100);
    373 			}
    374 			if (bail == 0) {
    375 				ret = -1;
    376 				goto bork;
    377 			}
    378 			data = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    379 			    JZ_SMBDC);
    380 			DPRINTF("rd st: %02x %d\n",
    381 			  bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST),
    382 			  bail);
    383 			DPRINTF("rd int: %02x\n",
    384 			  bus_space_read_4(sc->sc_memt, sc->sc_memh,
    385 			   JZ_SMBINTST));
    386 			DPRINTF("abort: %02x\n", abort);
    387 			DPRINTF("rd data: %02x\n", data);
    388 			*rx = data;
    389 			rx++;
    390 		}
    391 	} else {
    392 		tx = vbuf;
    393 		for (i = 0; i < buflen; i++) {
    394 			DPRINTF("wr data: %02x\n", *tx);
    395 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    396 			    JZ_SMBDC, *tx);
    397 			wbflush();
    398 			tx++;
    399 		}
    400 		jziic_wait(sc);
    401 		abort = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    402 		    JZ_SMBABTSRC);
    403 		DPRINTF("abort: %02x\n", abort);
    404 		if ((abort != 0)) {
    405 			ret = -1;
    406 			goto bork;
    407 		}
    408 
    409 		DPRINTF("st: %02x %d\n",
    410 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST), bail);
    411 		DPRINTF("wr int: %02x\n",
    412 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST));
    413 	}
    414 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON,
    415 	    JZ_SLVDIS | JZ_REST | JZ_SPD_100KB | JZ_MD);
    416 bork:
    417 	jziic_disable(sc);
    418 	return ret;
    419 }
    420 
    421 STATIC int
    422 jziic_i2c_exec_intr(struct jziic_softc *sc, i2c_op_t op, i2c_addr_t addr,
    423     const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
    424 {
    425 	int i, ret = 0, bail;
    426 
    427 	DPRINTF("%s: 0x%02x %d %d\n", __func__, addr, cmdlen, buflen);
    428 
    429 	jziic_disable(sc);
    430 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    431 
    432 	mutex_enter(&sc->sc_cvlock);
    433 
    434 	sc->sc_reading = FALSE;
    435 
    436 	if (I2C_OP_READ_P(op)) {
    437 		sc->sc_cmd = vcmd;
    438 		sc->sc_cmdlen = cmdlen;
    439 		sc->sc_buf = vbuf;
    440 		sc->sc_buflen = buflen;
    441 		memset(vbuf, 0, buflen);
    442 	} else {
    443 		if ((cmdlen + buflen) > 256)
    444 			return -1;
    445 		memcpy(sc->sc_txbuf, vcmd, cmdlen);
    446 		memcpy(sc->sc_txbuf + cmdlen, vbuf, buflen);
    447 		sc->sc_cmd = sc->sc_txbuf;
    448 		sc->sc_cmdlen = cmdlen + buflen;
    449 		sc->sc_buf = NULL;
    450 		sc->sc_buflen = 0;
    451 	}
    452 	sc->sc_cmdptr = 0;
    453 	sc->sc_bufptr = 0;
    454 	sc->sc_rds = 0;
    455 	sc->sc_abort = 0;
    456 
    457 	jziic_set_speed(sc);
    458 	jziic_wait(sc);
    459 
    460 	/* set FIFO levels */
    461 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTXTL, 4);
    462 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBRXTL, 0
    463 	    /*min(7, max(0, buflen - 2 ))*/);
    464 
    465 	/* try to talk... */
    466 
    467 	if (!jziic_enable(sc)) {
    468 		ret = -1;
    469 		goto bork;
    470 	}
    471 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    472 
    473 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTAR, addr);
    474 	jziic_wait(sc);
    475 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT, JZ_CLEARALL);
    476 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM,
    477 	    JZ_TXABT | JZ_TXEMP);
    478 
    479 	bail = 100 * sc->sc_cmdlen;
    480 	while ((sc->sc_cmdptr < sc->sc_cmdlen) && (bail > 0)) {
    481 		cv_timedwait(&sc->sc_ping, &sc->sc_cvlock, 1);
    482 		if (sc->sc_abort) {
    483 			/* we received an abort interrupt -> bailout */
    484 		    	DPRINTF("abort: %x\n", sc->sc_abort);
    485 		    	ret = -1;
    486 		    	goto bork;
    487 		}
    488 	    	bail--;
    489 	}
    490 
    491 	if (sc->sc_cmdptr < sc->sc_cmdlen) {
    492 		/* we didn't send everything? */
    493 	    	DPRINTF("sent %d of %d\n", sc->sc_cmdptr, sc->sc_cmdlen);
    494 	    	ret = -1;
    495 	    	goto bork;
    496 	}
    497 
    498 	if (I2C_OP_READ_P(op)) {
    499 		/* now read */
    500 		sc->sc_reading = TRUE;
    501 		bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM,
    502 		    JZ_TXABT | JZ_RXFL | JZ_TXEMP);
    503 
    504 		for (i = 0; i < uimin((buflen + 1), 4); i++) {
    505 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    506 			    JZ_SMBDC, JZ_CMD);
    507 			wbflush();
    508 		}
    509 		sc->sc_rds = i;
    510 
    511 		bail = 10 * sc->sc_buflen; /* 10 ticks per byte should be ok */
    512 		while ((sc->sc_bufptr < sc->sc_buflen) && (bail > 0)) {
    513 			cv_timedwait(&sc->sc_ping, &sc->sc_cvlock, 1);
    514 			if (sc->sc_abort) {
    515 				/* we received an abort interrupt -> bailout */
    516 		  	  	DPRINTF("rx abort: %x\n", sc->sc_abort);
    517 			    	ret = -1;
    518 			    	goto bork;
    519 			}
    520 			bail--;
    521 		}
    522 
    523 		if (sc->sc_bufptr < sc->sc_buflen) {
    524 			/* we didn't get everything? */
    525 		    	DPRINTF("rcvd %d of %d\n", sc->sc_bufptr, sc->sc_buflen);
    526 		    	ret = -1;
    527 		    	goto bork;
    528 		}
    529 	}
    530 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON,
    531 	    JZ_SLVDIS | JZ_REST | JZ_SPD_100KB | JZ_MD);
    532 bork:
    533 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    534 	jziic_disable(sc);
    535 	mutex_exit(&sc->sc_cvlock);
    536 	return ret;
    537 }
    538 
    539 STATIC int
    540 jziic_intr(void *cookie)
    541 {
    542 	struct jziic_softc *sc = cookie;
    543 	uint32_t stat, data, rstat;
    544 	int i;
    545 
    546 	stat = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST);
    547 	if (stat & JZ_TXEMP) {
    548 		if (sc->sc_reading) {
    549 			if (sc->sc_rds < (sc->sc_buflen + 1)) {
    550 				for (i = 0;
    551 				     i < uimin(4, (sc->sc_buflen + 1) -
    552 				                 sc->sc_rds);
    553 				     i++) {
    554 					bus_space_write_4( sc->sc_memt,
    555 					    sc->sc_memh,
    556 					    JZ_SMBDC, JZ_CMD);
    557 					wbflush();
    558 				}
    559 				sc->sc_rds += i;
    560 			} else {
    561 				/* we're done, so turn TX FIFO interrupt off */
    562 				bus_space_write_4(sc->sc_memt, sc->sc_memh,
    563 				    JZ_SMBINTM,
    564 				    JZ_TXABT | JZ_RXFL);
    565 			}
    566 		} else {
    567 			rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    568 			    JZ_SMBST);
    569 			while ((rstat & JZ_TFNF) &&
    570 			         (sc->sc_cmdptr < sc->sc_cmdlen)) {
    571 				data = *sc->sc_cmd;
    572 				sc->sc_cmd++;
    573 				sc->sc_cmdptr++;
    574 				bus_space_write_4(sc->sc_memt, sc->sc_memh,
    575 				    JZ_SMBDC, data & 0xff);
    576 				rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    577 				    JZ_SMBST);
    578 			};
    579 			/* no need to clear this one */
    580 			if (sc->sc_cmdptr >= sc->sc_cmdlen) {
    581 				cv_signal(&sc->sc_ping);
    582 				bus_space_write_4(sc->sc_memt, sc->sc_memh,
    583 				    JZ_SMBINTM, JZ_TXABT);
    584 			}
    585 		}
    586 	}
    587 	if (stat & JZ_RXFL) {
    588 		rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST);
    589 		while ((rstat & JZ_RFNE) && (sc->sc_bufptr < sc->sc_buflen)) {
    590 			data = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    591 			   JZ_SMBDC);
    592 			*sc->sc_buf = (uint8_t)(data & 0xff);
    593 			sc->sc_buf++;
    594 			sc->sc_bufptr++;
    595 			rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    596 			    JZ_SMBST);
    597 		}
    598 		if (sc->sc_bufptr >= sc->sc_buflen)
    599 			cv_signal(&sc->sc_ping);
    600 	}
    601 	if (stat & JZ_TXABT) {
    602 		sc->sc_abort = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    603 		    JZ_SMBABTSRC);
    604 		cv_signal(&sc->sc_ping);
    605 		bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT,
    606 		    JZ_CLEARALL);
    607 		bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    608 	}
    609 	return 0;
    610 }
    611