jziic.c revision 1.3
1/*	$NetBSD: jziic.c,v 1.3 2015/12/14 23:21:23 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.3 2015/12/14 23:21:23 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	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
195fail:
196	if (ih) {
197		evbmips_intr_disestablish(ih);
198	}
199	bus_space_unmap(sc->sc_memt, sc->sc_memh, 0x100);
200}
201
202STATIC int
203jziic_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
219STATIC void
220jziic_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
235STATIC int
236jziic_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
244STATIC void
245jziic_i2c_release_bus(void *cookie, int flags)
246{
247	struct jziic_softc *sc = cookie;
248
249	mutex_exit(&sc->sc_buslock);
250}
251
252STATIC int
253jziic_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
266STATIC void
267jziic_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
289STATIC int
290jziic_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
324STATIC int
325jziic_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);
442bork:
443	jziic_disable(sc);
444	return ret;
445}
446
447STATIC int
448jziic_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);
558bork:
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
565STATIC int
566jziic_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