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