jziic.c revision 1.9
1/*	$NetBSD: jziic.c,v 1.9 2021/08/07 16:18:59 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.9 2021/08/07 16:18:59 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
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_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_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
93		    void *, size_t, int);
94STATIC int jziic_i2c_exec_poll(struct jziic_softc *, i2c_op_t, i2c_addr_t,
95    const void *, size_t, void *, size_t, int);
96STATIC int jziic_i2c_exec_intr(struct jziic_softc *, i2c_op_t, i2c_addr_t,
97    const void *, size_t, void *, size_t, int);
98
99STATIC int jziic_intr(void *);
100
101
102/* ARGSUSED */
103STATIC int
104jziic_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 */
115STATIC void
116jziic_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	config_found(sc->sc_dev, &iba, iicbus_print, CFARGS_NONE);
182
183
184	return;
185
186fail:
187	if (ih) {
188		evbmips_intr_disestablish(ih);
189	}
190	bus_space_unmap(sc->sc_memt, sc->sc_memh, 0x100);
191}
192
193STATIC int
194jziic_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
210STATIC void
211jziic_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
226STATIC int
227jziic_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
240STATIC void
241jziic_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
263STATIC int
264jziic_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 (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
298STATIC int
299jziic_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);
416bork:
417	jziic_disable(sc);
418	return ret;
419}
420
421STATIC int
422jziic_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);
532bork:
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
539STATIC int
540jziic_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