xref: /netbsd-src/sys/arch/mips/ingenic/jziic.c (revision c38e7cc395b1472a774ff828e46123de44c628e9)
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