Home | History | Annotate | Line # | Download | only in ingenic
jziic.c revision 1.4
      1 /*	$NetBSD: jziic.c,v 1.4 2017/05/19 07:43:31 skrll 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.4 2017/05/19 07:43:31 skrll 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_buslock, 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_acquire_bus(void *, int);
     93 STATIC void jziic_i2c_release_bus(void *, int);
     94 STATIC int jziic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
     95 		    void *, size_t, int);
     96 STATIC int jziic_i2c_exec_poll(struct jziic_softc *, i2c_op_t, i2c_addr_t,
     97     const void *, size_t, void *, size_t, int);
     98 STATIC int jziic_i2c_exec_intr(struct jziic_softc *, i2c_op_t, i2c_addr_t,
     99     const void *, size_t, void *, size_t, int);
    100 
    101 STATIC int jziic_intr(void *);
    102 
    103 
    104 /* ARGSUSED */
    105 STATIC int
    106 jziic_match(device_t parent, struct cfdata *match, void *aux)
    107 {
    108 	struct apbus_attach_args *aa = aux;
    109 
    110 	if (strcmp(aa->aa_name, "jziic") != 0)
    111 		return 0;
    112 
    113 	return 1;
    114 }
    115 
    116 /* ARGSUSED */
    117 STATIC void
    118 jziic_attach(device_t parent, device_t self, void *aux)
    119 {
    120 	struct jziic_softc *sc = device_private(self);
    121 	struct apbus_attach_args *aa = aux;
    122 	struct i2cbus_attach_args iba;
    123 	int error;
    124 	void *ih;
    125 #ifdef JZIIC_DEBUG
    126 	int i;
    127 	uint8_t in[1] = {0}, out[16];
    128 #endif
    129 
    130 	sc->sc_dev = self;
    131 	sc->sc_pclk = aa->aa_pclk;
    132 	sc->sc_memt = aa->aa_bst;
    133 
    134 	error = bus_space_map(aa->aa_bst, aa->aa_addr, 0x100, 0, &sc->sc_memh);
    135 	if (error) {
    136 		aprint_error_dev(self,
    137 		    "can't map registers for %s: %d\n", aa->aa_name, error);
    138 		return;
    139 	}
    140 
    141 	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
    142 	mutex_init(&sc->sc_cvlock, MUTEX_DEFAULT, IPL_NONE);
    143 	cv_init(&sc->sc_ping, device_xname(self));
    144 
    145 	aprint_naive(": SMBus controller\n");
    146 	aprint_normal(": SMBus controller\n");
    147 
    148 	ih = evbmips_intr_establish(aa->aa_irq, jziic_intr, sc);
    149 
    150 	if (ih == NULL) {
    151 		aprint_error_dev(self, "failed to establish interrupt %d\n",
    152 		     aa->aa_irq);
    153 		goto fail;
    154 	}
    155 
    156 #ifdef JZIIC_DEBUG
    157 	if (jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP, 0x51, in, 1, out, 9, 0)
    158 	    >= 0) {
    159 		for (i = 0; i < 9; i++)
    160 			printf(" %02x", out[i]);
    161 		printf("\n");
    162 		delay(1000000);
    163 		jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP,
    164 		    0x51, in, 1, out, 9, 0);
    165 		for (i = 0; i < 9; i++)
    166 			printf(" %02x", out[i]);
    167 		printf("\n");
    168 		delay(1000000);
    169 		jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP,
    170 		    0x51, in, 1, out, 9, 0);
    171 		for (i = 0; i < 9; i++)
    172 			printf(" %02x", out[i]);
    173 		printf("\n");
    174 	}
    175 #endif
    176 
    177 	/* fill in the i2c tag */
    178 	sc->sc_i2c.ic_cookie = sc;
    179 	sc->sc_i2c.ic_acquire_bus = jziic_i2c_acquire_bus;
    180 	sc->sc_i2c.ic_release_bus = jziic_i2c_release_bus;
    181 	sc->sc_i2c.ic_send_start = NULL;
    182 	sc->sc_i2c.ic_send_stop = NULL;
    183 	sc->sc_i2c.ic_initiate_xfer = NULL;
    184 	sc->sc_i2c.ic_read_byte = NULL;
    185 	sc->sc_i2c.ic_write_byte = NULL;
    186 	sc->sc_i2c.ic_exec = jziic_i2c_exec;
    187 
    188 	memset(&iba, 0, sizeof(iba));
    189 	iba.iba_tag = &sc->sc_i2c;
    190 	(void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
    191 
    192 
    193 	return;
    194 
    195 fail:
    196 	if (ih) {
    197 		evbmips_intr_disestablish(ih);
    198 	}
    199 	bus_space_unmap(sc->sc_memt, sc->sc_memh, 0x100);
    200 }
    201 
    202 STATIC int
    203 jziic_enable(struct jziic_softc *sc)
    204 {
    205 	int bail = 100000;
    206 	uint32_t reg;
    207 
    208 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, JZ_ENABLE);
    209 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    210 	DPRINTF("status: %02x\n", reg);
    211 	while ((bail > 0) && (reg == 0)) {
    212 		bail--;
    213 		reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    214 	}
    215 	DPRINTF("bail: %d\n", bail);
    216 	return (reg != 0);
    217 }
    218 
    219 STATIC void
    220 jziic_disable(struct jziic_softc *sc)
    221 {
    222 	int bail = 100000;
    223 	uint32_t reg;
    224 
    225 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, 0);
    226 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    227 	DPRINTF("status: %02x\n", reg);
    228 	while ((bail > 0) && (reg != 0)) {
    229 		bail--;
    230 		reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    231 	}
    232 	DPRINTF("bail: %d\n", bail);
    233 }
    234 
    235 STATIC int
    236 jziic_i2c_acquire_bus(void *cookie, int flags)
    237 {
    238 	struct jziic_softc *sc = cookie;
    239 
    240 	mutex_enter(&sc->sc_buslock);
    241 	return 0;
    242 }
    243 
    244 STATIC void
    245 jziic_i2c_release_bus(void *cookie, int flags)
    246 {
    247 	struct jziic_softc *sc = cookie;
    248 
    249 	mutex_exit(&sc->sc_buslock);
    250 }
    251 
    252 STATIC int
    253 jziic_wait(struct jziic_softc *sc)
    254 {
    255 	uint32_t reg;
    256 	int bail = 10000;
    257 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST);
    258 	while ((reg & JZ_MSTACT) && (bail > 0)) {
    259 		delay(100);
    260 		reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST);
    261 		bail--;
    262 	}
    263 	return ((reg & JZ_MSTACT) == 0);
    264 }
    265 
    266 STATIC void
    267 jziic_set_speed(struct jziic_softc *sc)
    268 {
    269 	int ticks, hcnt, lcnt, hold, setup;
    270 
    271 	/* PCLK ticks per SMBus cycle */
    272 	ticks = sc->sc_pclk / 100; /* assuming 100kHz for now */
    273 	hcnt = (ticks * 40 / (40 + 47)) - 8;
    274 	lcnt = (ticks * 47 / (40 + 47)) - 1;
    275 	hold = sc->sc_pclk * 4 / 10000 - 1; /* ... * 400 / 1000000 ... */
    276 	hold = max(1, hold);
    277 	hold |= JZ_HDENB;
    278 	setup = sc->sc_pclk * 3 / 10000 + 1; /* ... * 300 / 1000000 ... */
    279 	DPRINTF("hcnt %d lcnt %d hold %d\n", hcnt, lcnt, hold);
    280 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSHCNT, hcnt);
    281 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSLCNT, lcnt);
    282 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDAHD, hold);
    283 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDASU, setup);
    284 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON,
    285 	    JZ_SLVDIS | JZ_STPHLD | JZ_REST | JZ_SPD_100KB | JZ_MD);
    286 	(void)bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT);
    287 }
    288 
    289 STATIC int
    290 jziic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
    291     size_t cmdlen, void *vbuf, size_t buflen, int flags)
    292 {
    293 	struct jziic_softc *sc = cookie;
    294 
    295 	if (cold || (flags & I2C_F_POLL)) {
    296 		return jziic_i2c_exec_poll(sc, op, addr, vcmd, cmdlen, vbuf,
    297 		    buflen, flags);
    298 	} else {
    299 #ifdef JZIIC_DEBUG
    300 		uint8_t *b = vbuf;
    301 		int i, ret;
    302 
    303 		memset(vbuf, 0, buflen);
    304 		jziic_i2c_exec_intr(sc, op, addr, vcmd, cmdlen, vbuf,
    305 		    buflen, flags);
    306 		for (i = 0; i < buflen; i++) {
    307 			printf(" %02x", b[i]);
    308 		}
    309 		printf("\n");
    310 		ret = jziic_i2c_exec_poll(sc, op, addr, vcmd, cmdlen, vbuf,
    311 		    buflen, flags);
    312 		for (i = 0; i < buflen; i++) {
    313 			printf(" %02x", b[i]);
    314 		}
    315 		printf("\n");
    316 		return ret;
    317 #else
    318 		return jziic_i2c_exec_intr(sc, op, addr, vcmd, cmdlen, vbuf,
    319 		    buflen, flags);
    320 #endif
    321 	}
    322 }
    323 
    324 STATIC int
    325 jziic_i2c_exec_poll(struct jziic_softc *sc, i2c_op_t op, i2c_addr_t addr,
    326     const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
    327 {
    328 	int i, bail = 10000, ret = 0;
    329 	uint32_t abort;
    330 	uint8_t *rx, data;
    331 	const uint8_t *tx;
    332 
    333 	tx = vcmd;
    334 	rx = vbuf;
    335 
    336 	DPRINTF("%s: 0x%02x %d %d\n", __func__, addr, cmdlen, buflen);
    337 
    338 	jziic_disable(sc);
    339 
    340 	/* we're polling, so disable interrupts */
    341 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    342 
    343 	jziic_set_speed(sc);
    344 	jziic_wait(sc);
    345 	/* try to talk... */
    346 
    347 	if (!jziic_enable(sc)) {
    348 		ret = -1;
    349 		goto bork;
    350 	}
    351 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    352 
    353 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTAR, addr);
    354 	jziic_wait(sc);
    355 	DPRINTF("st: %02x\n",
    356 	    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST));
    357 	DPRINTF("wr int: %02x\n",
    358 	    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST));
    359 	abort = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC);
    360 	DPRINTF("abort: %02x\n", abort);
    361 	if ((abort != 0)) {
    362 		ret = -1;
    363 		goto bork;
    364 	}
    365 
    366 	do {
    367 		bail--;
    368 		delay(100);
    369 	} while (((bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST) &
    370 	           JZ_TFE) == 0) && (bail > 0));
    371 
    372 	if (cmdlen != 0) {
    373 		for (i = 0; i < cmdlen; i++) {
    374 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    375 			    JZ_SMBDC, *tx);
    376 			tx++;
    377 		}
    378 	}
    379 
    380 	if (I2C_OP_READ_P(op)) {
    381 		/* now read */
    382 		for (i = 0; i < (buflen + 1); i++) {
    383 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    384 			    JZ_SMBDC, JZ_CMD);
    385 		}
    386 		wbflush();
    387 		DPRINTF("rd st: %02x\n",
    388 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST));
    389 		DPRINTF("rd int: %02x\n",
    390 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST));
    391 		DPRINTF("abort: %02x\n",
    392 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC));
    393 		for (i = 0; i < buflen; i++) {
    394 			bail = 10000;
    395 			while (((bus_space_read_4(sc->sc_memt, sc->sc_memh,
    396 				  JZ_SMBST) & JZ_RFNE) == 0) && (bail > 0)) {
    397 				bail--;
    398 				delay(100);
    399 			}
    400 			if (bail == 0) {
    401 				ret = -1;
    402 				goto bork;
    403 			}
    404 			data = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    405 			    JZ_SMBDC);
    406 			DPRINTF("rd st: %02x %d\n",
    407 			  bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST),
    408 			  bail);
    409 			DPRINTF("rd int: %02x\n",
    410 			  bus_space_read_4(sc->sc_memt, sc->sc_memh,
    411 			   JZ_SMBINTST));
    412 			DPRINTF("abort: %02x\n", abort);
    413 			DPRINTF("rd data: %02x\n", data);
    414 			*rx = data;
    415 			rx++;
    416 		}
    417 	} else {
    418 		tx = vbuf;
    419 		for (i = 0; i < buflen; i++) {
    420 			DPRINTF("wr data: %02x\n", *tx);
    421 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    422 			    JZ_SMBDC, *tx);
    423 			wbflush();
    424 			tx++;
    425 		}
    426 		jziic_wait(sc);
    427 		abort = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    428 		    JZ_SMBABTSRC);
    429 		DPRINTF("abort: %02x\n", abort);
    430 		if ((abort != 0)) {
    431 			ret = -1;
    432 			goto bork;
    433 		}
    434 
    435 		DPRINTF("st: %02x %d\n",
    436 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST), bail);
    437 		DPRINTF("wr int: %02x\n",
    438 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST));
    439 	}
    440 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON,
    441 	    JZ_SLVDIS | JZ_REST | JZ_SPD_100KB | JZ_MD);
    442 bork:
    443 	jziic_disable(sc);
    444 	return ret;
    445 }
    446 
    447 STATIC int
    448 jziic_i2c_exec_intr(struct jziic_softc *sc, i2c_op_t op, i2c_addr_t addr,
    449     const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
    450 {
    451 	int i, ret = 0, bail;
    452 
    453 	DPRINTF("%s: 0x%02x %d %d\n", __func__, addr, cmdlen, buflen);
    454 
    455 	jziic_disable(sc);
    456 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    457 
    458 	mutex_enter(&sc->sc_cvlock);
    459 
    460 	sc->sc_reading = FALSE;
    461 
    462 	if (I2C_OP_READ_P(op)) {
    463 		sc->sc_cmd = vcmd;
    464 		sc->sc_cmdlen = cmdlen;
    465 		sc->sc_buf = vbuf;
    466 		sc->sc_buflen = buflen;
    467 		memset(vbuf, 0, buflen);
    468 	} else {
    469 		if ((cmdlen + buflen) > 256)
    470 			return -1;
    471 		memcpy(sc->sc_txbuf, vcmd, cmdlen);
    472 		memcpy(sc->sc_txbuf + cmdlen, vbuf, buflen);
    473 		sc->sc_cmd = sc->sc_txbuf;
    474 		sc->sc_cmdlen = cmdlen + buflen;
    475 		sc->sc_buf = NULL;
    476 		sc->sc_buflen = 0;
    477 	}
    478 	sc->sc_cmdptr = 0;
    479 	sc->sc_bufptr = 0;
    480 	sc->sc_rds = 0;
    481 	sc->sc_abort = 0;
    482 
    483 	jziic_set_speed(sc);
    484 	jziic_wait(sc);
    485 
    486 	/* set FIFO levels */
    487 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTXTL, 4);
    488 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBRXTL, 0
    489 	    /*min(7, max(0, buflen - 2 ))*/);
    490 
    491 	/* try to talk... */
    492 
    493 	if (!jziic_enable(sc)) {
    494 		ret = -1;
    495 		goto bork;
    496 	}
    497 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    498 
    499 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTAR, addr);
    500 	jziic_wait(sc);
    501 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT, JZ_CLEARALL);
    502 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM,
    503 	    JZ_TXABT | JZ_TXEMP);
    504 
    505 	bail = 100 * sc->sc_cmdlen;
    506 	while ((sc->sc_cmdptr < sc->sc_cmdlen) && (bail > 0)) {
    507 		cv_timedwait(&sc->sc_ping, &sc->sc_cvlock, 1);
    508 		if (sc->sc_abort) {
    509 			/* we received an abort interrupt -> bailout */
    510 		    	DPRINTF("abort: %x\n", sc->sc_abort);
    511 		    	ret = -1;
    512 		    	goto bork;
    513 		}
    514 	    	bail--;
    515 	}
    516 
    517 	if (sc->sc_cmdptr < sc->sc_cmdlen) {
    518 		/* we didn't send everything? */
    519 	    	DPRINTF("sent %d of %d\n", sc->sc_cmdptr, sc->sc_cmdlen);
    520 	    	ret = -1;
    521 	    	goto bork;
    522 	}
    523 
    524 	if (I2C_OP_READ_P(op)) {
    525 		/* now read */
    526 		sc->sc_reading = TRUE;
    527 		bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM,
    528 		    JZ_TXABT | JZ_RXFL | JZ_TXEMP);
    529 
    530 		for (i = 0; i < min((buflen + 1), 4); i++) {
    531 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    532 			    JZ_SMBDC, JZ_CMD);
    533 			wbflush();
    534 		}
    535 		sc->sc_rds = i;
    536 
    537 		bail = 10 * sc->sc_buflen; /* 10 ticks per byte should be ok */
    538 		while ((sc->sc_bufptr < sc->sc_buflen) && (bail > 0)) {
    539 			cv_timedwait(&sc->sc_ping, &sc->sc_cvlock, 1);
    540 			if (sc->sc_abort) {
    541 				/* we received an abort interrupt -> bailout */
    542 		  	  	DPRINTF("rx abort: %x\n", sc->sc_abort);
    543 			    	ret = -1;
    544 			    	goto bork;
    545 			}
    546 			bail--;
    547 		}
    548 
    549 		if (sc->sc_bufptr < sc->sc_buflen) {
    550 			/* we didn't get everything? */
    551 		    	DPRINTF("rcvd %d of %d\n", sc->sc_bufptr, sc->sc_buflen);
    552 		    	ret = -1;
    553 		    	goto bork;
    554 		}
    555 	}
    556 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON,
    557 	    JZ_SLVDIS | JZ_REST | JZ_SPD_100KB | JZ_MD);
    558 bork:
    559 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    560 	jziic_disable(sc);
    561 	mutex_exit(&sc->sc_cvlock);
    562 	return ret;
    563 }
    564 
    565 STATIC int
    566 jziic_intr(void *cookie)
    567 {
    568 	struct jziic_softc *sc = cookie;
    569 	uint32_t stat, data, rstat;
    570 	int i;
    571 
    572 	stat = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST);
    573 	if (stat & JZ_TXEMP) {
    574 		if (sc->sc_reading) {
    575 			if (sc->sc_rds < (sc->sc_buflen + 1)) {
    576 				for (i = 0;
    577 				     i < min(4, (sc->sc_buflen + 1) -
    578 				                 sc->sc_rds);
    579 				     i++) {
    580 					bus_space_write_4( sc->sc_memt,
    581 					    sc->sc_memh,
    582 					    JZ_SMBDC, JZ_CMD);
    583 					wbflush();
    584 				}
    585 				sc->sc_rds += i;
    586 			} else {
    587 				/* we're done, so turn TX FIFO interrupt off */
    588 				bus_space_write_4(sc->sc_memt, sc->sc_memh,
    589 				    JZ_SMBINTM,
    590 				    JZ_TXABT | JZ_RXFL);
    591 			}
    592 		} else {
    593 			rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    594 			    JZ_SMBST);
    595 			while ((rstat & JZ_TFNF) &&
    596 			         (sc->sc_cmdptr < sc->sc_cmdlen)) {
    597 				data = *sc->sc_cmd;
    598 				sc->sc_cmd++;
    599 				sc->sc_cmdptr++;
    600 				bus_space_write_4(sc->sc_memt, sc->sc_memh,
    601 				    JZ_SMBDC, data & 0xff);
    602 				rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    603 				    JZ_SMBST);
    604 			};
    605 			/* no need to clear this one */
    606 			if (sc->sc_cmdptr >= sc->sc_cmdlen) {
    607 				cv_signal(&sc->sc_ping);
    608 				bus_space_write_4(sc->sc_memt, sc->sc_memh,
    609 				    JZ_SMBINTM, JZ_TXABT);
    610 			}
    611 		}
    612 	}
    613 	if (stat & JZ_RXFL) {
    614 		rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST);
    615 		while ((rstat & JZ_RFNE) && (sc->sc_bufptr < sc->sc_buflen)) {
    616 			data = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    617 			   JZ_SMBDC);
    618 			*sc->sc_buf = (uint8_t)(data & 0xff);
    619 			sc->sc_buf++;
    620 			sc->sc_bufptr++;
    621 			rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    622 			    JZ_SMBST);
    623 		}
    624 		if (sc->sc_bufptr >= sc->sc_buflen)
    625 			cv_signal(&sc->sc_ping);
    626 	}
    627 	if (stat & JZ_TXABT) {
    628 		sc->sc_abort = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    629 		    JZ_SMBABTSRC);
    630 		cv_signal(&sc->sc_ping);
    631 		bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT,
    632 		    JZ_CLEARALL);
    633 		bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    634 	}
    635 	return 0;
    636 }
    637