xref: /netbsd-src/sys/arch/mips/ingenic/jziic.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
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 
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_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_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
93 		    void *, size_t, int);
94 STATIC int jziic_i2c_exec_poll(struct jziic_softc *, i2c_op_t, i2c_addr_t,
95     const void *, size_t, void *, size_t, int);
96 STATIC int jziic_i2c_exec_intr(struct jziic_softc *, i2c_op_t, i2c_addr_t,
97     const void *, size_t, void *, size_t, int);
98 
99 STATIC int jziic_intr(void *);
100 
101 
102 /* ARGSUSED */
103 STATIC int
jziic_match(device_t parent,struct cfdata * match,void * aux)104 jziic_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 */
115 STATIC void
jziic_attach(device_t parent,device_t self,void * aux)116 jziic_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 
186 fail:
187 	if (ih) {
188 		evbmips_intr_disestablish(ih);
189 	}
190 	bus_space_unmap(sc->sc_memt, sc->sc_memh, 0x100);
191 }
192 
193 STATIC int
jziic_enable(struct jziic_softc * sc)194 jziic_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 
210 STATIC void
jziic_disable(struct jziic_softc * sc)211 jziic_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 
226 STATIC int
jziic_wait(struct jziic_softc * sc)227 jziic_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 
240 STATIC void
jziic_set_speed(struct jziic_softc * sc)241 jziic_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 
263 STATIC int
jziic_i2c_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * vcmd,size_t cmdlen,void * vbuf,size_t buflen,int flags)264 jziic_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 
298 STATIC int
jziic_i2c_exec_poll(struct jziic_softc * sc,i2c_op_t op,i2c_addr_t addr,const void * vcmd,size_t cmdlen,void * vbuf,size_t buflen,int flags)299 jziic_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);
416 bork:
417 	jziic_disable(sc);
418 	return ret;
419 }
420 
421 STATIC int
jziic_i2c_exec_intr(struct jziic_softc * sc,i2c_op_t op,i2c_addr_t addr,const void * vcmd,size_t cmdlen,void * vbuf,size_t buflen,int flags)422 jziic_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);
532 bork:
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 
539 STATIC int
jziic_intr(void * cookie)540 jziic_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