Home | History | Annotate | Line # | Download | only in ingenic
      1  1.10   thorpej /*	$NetBSD: jziic.c,v 1.10 2025/09/15 13:23:02 thorpej Exp $ */
      2   1.1  macallan 
      3   1.1  macallan /*-
      4   1.1  macallan  * Copyright (c) 2015 Michael Lorenz
      5   1.1  macallan  * All rights reserved.
      6   1.1  macallan  *
      7   1.1  macallan  * Redistribution and use in source and binary forms, with or without
      8   1.1  macallan  * modification, are permitted provided that the following conditions
      9   1.1  macallan  * are met:
     10   1.1  macallan  * 1. Redistributions of source code must retain the above copyright
     11   1.1  macallan  *    notice, this list of conditions and the following disclaimer.
     12   1.1  macallan  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1  macallan  *    notice, this list of conditions and the following disclaimer in the
     14   1.1  macallan  *    documentation and/or other materials provided with the distribution.
     15   1.1  macallan  *
     16   1.1  macallan  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17   1.1  macallan  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18   1.1  macallan  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19   1.1  macallan  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20   1.1  macallan  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21   1.1  macallan  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22   1.1  macallan  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23   1.1  macallan  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24   1.1  macallan  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25   1.1  macallan  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26   1.1  macallan  * POSSIBILITY OF SUCH DAMAGE.
     27   1.1  macallan  */
     28   1.1  macallan 
     29   1.1  macallan #include <sys/cdefs.h>
     30  1.10   thorpej __KERNEL_RCSID(0, "$NetBSD: jziic.c,v 1.10 2025/09/15 13:23:02 thorpej Exp $");
     31   1.1  macallan 
     32   1.1  macallan /*
     33   1.1  macallan  * a preliminary driver for JZ4780's on-chip SMBus controllers
     34   1.1  macallan  * - needs more error handling and interrupt support
     35   1.4     skrll  * - transfers can't be more than the chip's FIFO, supposedly 16 bytes per
     36   1.1  macallan  *   direction
     37   1.1  macallan  * so, good enough for RTCs but not much else yet
     38   1.1  macallan  */
     39   1.1  macallan 
     40   1.1  macallan #include <sys/param.h>
     41   1.1  macallan #include <sys/systm.h>
     42   1.2  macallan #include <sys/kernel.h>
     43   1.1  macallan #include <sys/device.h>
     44   1.1  macallan #include <sys/mutex.h>
     45   1.1  macallan #include <sys/bus.h>
     46   1.1  macallan #include <sys/mutex.h>
     47   1.2  macallan #include <sys/condvar.h>
     48   1.1  macallan 
     49   1.1  macallan #include <mips/ingenic/ingenic_var.h>
     50   1.1  macallan #include <mips/ingenic/ingenic_regs.h>
     51   1.1  macallan 
     52   1.1  macallan #include <dev/i2c/i2cvar.h>
     53   1.1  macallan 
     54   1.1  macallan #include "opt_ingenic.h"
     55   1.1  macallan 
     56   1.1  macallan #ifdef JZIIC_DEBUG
     57   1.1  macallan #define DPRINTF aprint_error
     58   1.2  macallan #define STATIC /* */
     59   1.1  macallan #else
     60   1.1  macallan #define DPRINTF while (0) printf
     61   1.2  macallan #define STATIC static
     62   1.1  macallan #endif
     63   1.2  macallan 
     64   1.2  macallan STATIC int jziic_match(device_t, struct cfdata *, void *);
     65   1.2  macallan STATIC void jziic_attach(device_t, device_t, void *);
     66   1.1  macallan 
     67   1.1  macallan struct jziic_softc {
     68   1.1  macallan 	device_t 		sc_dev;
     69   1.1  macallan 	bus_space_tag_t 	sc_memt;
     70   1.1  macallan 	bus_space_handle_t 	sc_memh;
     71   1.1  macallan 	struct i2c_controller 	sc_i2c;
     72   1.6   thorpej 	kmutex_t		sc_cvlock;
     73   1.1  macallan 	uint32_t		sc_pclk;
     74   1.2  macallan 	/* stuff used for interrupt-driven transfers */
     75   1.2  macallan 	const uint8_t		*sc_cmd;
     76   1.2  macallan 	uint8_t			*sc_buf;
     77   1.2  macallan 	uint32_t		sc_cmdlen, sc_buflen;
     78   1.2  macallan 	uint32_t		sc_cmdptr, sc_bufptr, sc_rds;
     79   1.2  macallan 	uint32_t		sc_abort;
     80   1.2  macallan 	kcondvar_t		sc_ping;
     81   1.2  macallan 	uint8_t			sc_txbuf[256];
     82   1.2  macallan 	boolean_t		sc_reading;
     83   1.1  macallan };
     84   1.1  macallan 
     85   1.1  macallan CFATTACH_DECL_NEW(jziic, sizeof(struct jziic_softc),
     86   1.1  macallan     jziic_match, jziic_attach, NULL, NULL);
     87   1.1  macallan 
     88   1.2  macallan STATIC int jziic_enable(struct jziic_softc *);
     89   1.2  macallan STATIC void jziic_disable(struct jziic_softc *);
     90   1.2  macallan STATIC int jziic_wait(struct jziic_softc *);
     91   1.2  macallan STATIC void jziic_set_speed(struct jziic_softc *);
     92   1.2  macallan STATIC int jziic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
     93   1.1  macallan 		    void *, size_t, int);
     94   1.2  macallan STATIC int jziic_i2c_exec_poll(struct jziic_softc *, i2c_op_t, i2c_addr_t,
     95   1.2  macallan     const void *, size_t, void *, size_t, int);
     96   1.2  macallan STATIC int jziic_i2c_exec_intr(struct jziic_softc *, i2c_op_t, i2c_addr_t,
     97   1.2  macallan     const void *, size_t, void *, size_t, int);
     98   1.2  macallan 
     99   1.2  macallan STATIC int jziic_intr(void *);
    100   1.1  macallan 
    101   1.1  macallan 
    102   1.1  macallan /* ARGSUSED */
    103   1.2  macallan STATIC int
    104   1.1  macallan jziic_match(device_t parent, struct cfdata *match, void *aux)
    105   1.1  macallan {
    106   1.1  macallan 	struct apbus_attach_args *aa = aux;
    107   1.1  macallan 
    108   1.1  macallan 	if (strcmp(aa->aa_name, "jziic") != 0)
    109   1.1  macallan 		return 0;
    110   1.1  macallan 
    111   1.1  macallan 	return 1;
    112   1.1  macallan }
    113   1.1  macallan 
    114   1.1  macallan /* ARGSUSED */
    115   1.2  macallan STATIC void
    116   1.1  macallan jziic_attach(device_t parent, device_t self, void *aux)
    117   1.1  macallan {
    118   1.1  macallan 	struct jziic_softc *sc = device_private(self);
    119   1.1  macallan 	struct apbus_attach_args *aa = aux;
    120   1.1  macallan 	int error;
    121   1.2  macallan 	void *ih;
    122   1.1  macallan #ifdef JZIIC_DEBUG
    123   1.1  macallan 	int i;
    124   1.1  macallan 	uint8_t in[1] = {0}, out[16];
    125   1.1  macallan #endif
    126   1.1  macallan 
    127   1.1  macallan 	sc->sc_dev = self;
    128   1.1  macallan 	sc->sc_pclk = aa->aa_pclk;
    129   1.1  macallan 	sc->sc_memt = aa->aa_bst;
    130   1.1  macallan 
    131   1.1  macallan 	error = bus_space_map(aa->aa_bst, aa->aa_addr, 0x100, 0, &sc->sc_memh);
    132   1.1  macallan 	if (error) {
    133   1.1  macallan 		aprint_error_dev(self,
    134   1.1  macallan 		    "can't map registers for %s: %d\n", aa->aa_name, error);
    135   1.1  macallan 		return;
    136   1.1  macallan 	}
    137   1.1  macallan 
    138   1.2  macallan 	mutex_init(&sc->sc_cvlock, MUTEX_DEFAULT, IPL_NONE);
    139   1.2  macallan 	cv_init(&sc->sc_ping, device_xname(self));
    140   1.1  macallan 
    141   1.1  macallan 	aprint_naive(": SMBus controller\n");
    142   1.1  macallan 	aprint_normal(": SMBus controller\n");
    143   1.1  macallan 
    144   1.2  macallan 	ih = evbmips_intr_establish(aa->aa_irq, jziic_intr, sc);
    145   1.1  macallan 
    146   1.1  macallan 	if (ih == NULL) {
    147   1.1  macallan 		aprint_error_dev(self, "failed to establish interrupt %d\n",
    148   1.1  macallan 		     aa->aa_irq);
    149   1.1  macallan 		goto fail;
    150   1.1  macallan 	}
    151   1.1  macallan 
    152   1.1  macallan #ifdef JZIIC_DEBUG
    153   1.1  macallan 	if (jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP, 0x51, in, 1, out, 9, 0)
    154   1.1  macallan 	    >= 0) {
    155   1.1  macallan 		for (i = 0; i < 9; i++)
    156   1.1  macallan 			printf(" %02x", out[i]);
    157   1.1  macallan 		printf("\n");
    158   1.1  macallan 		delay(1000000);
    159   1.1  macallan 		jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP,
    160   1.1  macallan 		    0x51, in, 1, out, 9, 0);
    161   1.1  macallan 		for (i = 0; i < 9; i++)
    162   1.1  macallan 			printf(" %02x", out[i]);
    163   1.1  macallan 		printf("\n");
    164   1.1  macallan 		delay(1000000);
    165   1.1  macallan 		jziic_i2c_exec(sc, I2C_OP_READ_WITH_STOP,
    166   1.1  macallan 		    0x51, in, 1, out, 9, 0);
    167   1.1  macallan 		for (i = 0; i < 9; i++)
    168   1.1  macallan 			printf(" %02x", out[i]);
    169   1.1  macallan 		printf("\n");
    170   1.1  macallan 	}
    171   1.1  macallan #endif
    172   1.1  macallan 
    173   1.1  macallan 	/* fill in the i2c tag */
    174   1.6   thorpej 	iic_tag_init(&sc->sc_i2c);
    175   1.1  macallan 	sc->sc_i2c.ic_cookie = sc;
    176   1.1  macallan 	sc->sc_i2c.ic_exec = jziic_i2c_exec;
    177   1.1  macallan 
    178  1.10   thorpej 	iicbus_attach(sc->sc_dev, &sc->sc_i2c);
    179   1.1  macallan 
    180   1.1  macallan 	return;
    181   1.1  macallan 
    182   1.1  macallan fail:
    183   1.1  macallan 	if (ih) {
    184   1.1  macallan 		evbmips_intr_disestablish(ih);
    185   1.1  macallan 	}
    186   1.1  macallan 	bus_space_unmap(sc->sc_memt, sc->sc_memh, 0x100);
    187   1.1  macallan }
    188   1.1  macallan 
    189   1.2  macallan STATIC int
    190   1.1  macallan jziic_enable(struct jziic_softc *sc)
    191   1.1  macallan {
    192   1.1  macallan 	int bail = 100000;
    193   1.1  macallan 	uint32_t reg;
    194   1.1  macallan 
    195   1.1  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, JZ_ENABLE);
    196   1.1  macallan 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    197   1.1  macallan 	DPRINTF("status: %02x\n", reg);
    198   1.1  macallan 	while ((bail > 0) && (reg == 0)) {
    199   1.1  macallan 		bail--;
    200   1.1  macallan 		reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    201   1.1  macallan 	}
    202   1.1  macallan 	DPRINTF("bail: %d\n", bail);
    203   1.1  macallan 	return (reg != 0);
    204   1.1  macallan }
    205   1.1  macallan 
    206   1.2  macallan STATIC void
    207   1.1  macallan jziic_disable(struct jziic_softc *sc)
    208   1.1  macallan {
    209   1.1  macallan 	int bail = 100000;
    210   1.1  macallan 	uint32_t reg;
    211   1.1  macallan 
    212   1.1  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBENB, 0);
    213   1.1  macallan 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    214   1.1  macallan 	DPRINTF("status: %02x\n", reg);
    215   1.1  macallan 	while ((bail > 0) && (reg != 0)) {
    216   1.1  macallan 		bail--;
    217   1.1  macallan 		reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBENBST);
    218   1.1  macallan 	}
    219   1.1  macallan 	DPRINTF("bail: %d\n", bail);
    220   1.1  macallan }
    221   1.1  macallan 
    222   1.2  macallan STATIC int
    223   1.1  macallan jziic_wait(struct jziic_softc *sc)
    224   1.1  macallan {
    225   1.1  macallan 	uint32_t reg;
    226   1.1  macallan 	int bail = 10000;
    227   1.1  macallan 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST);
    228   1.1  macallan 	while ((reg & JZ_MSTACT) && (bail > 0)) {
    229   1.1  macallan 		delay(100);
    230   1.1  macallan 		reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST);
    231   1.1  macallan 		bail--;
    232   1.4     skrll 	}
    233   1.1  macallan 	return ((reg & JZ_MSTACT) == 0);
    234   1.1  macallan }
    235   1.1  macallan 
    236   1.2  macallan STATIC void
    237   1.2  macallan jziic_set_speed(struct jziic_softc *sc)
    238   1.1  macallan {
    239   1.1  macallan 	int ticks, hcnt, lcnt, hold, setup;
    240   1.1  macallan 
    241   1.1  macallan 	/* PCLK ticks per SMBus cycle */
    242   1.1  macallan 	ticks = sc->sc_pclk / 100; /* assuming 100kHz for now */
    243   1.1  macallan 	hcnt = (ticks * 40 / (40 + 47)) - 8;
    244   1.1  macallan 	lcnt = (ticks * 47 / (40 + 47)) - 1;
    245   1.1  macallan 	hold = sc->sc_pclk * 4 / 10000 - 1; /* ... * 400 / 1000000 ... */
    246   1.5  riastrad 	hold = uimax(1, hold);
    247   1.1  macallan 	hold |= JZ_HDENB;
    248   1.1  macallan 	setup = sc->sc_pclk * 3 / 10000 + 1; /* ... * 300 / 1000000 ... */
    249   1.1  macallan 	DPRINTF("hcnt %d lcnt %d hold %d\n", hcnt, lcnt, hold);
    250   1.1  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSHCNT, hcnt);
    251   1.1  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSLCNT, lcnt);
    252   1.1  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDAHD, hold);
    253   1.1  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBSDASU, setup);
    254   1.1  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON,
    255   1.1  macallan 	    JZ_SLVDIS | JZ_STPHLD | JZ_REST | JZ_SPD_100KB | JZ_MD);
    256   1.1  macallan 	(void)bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT);
    257   1.2  macallan }
    258   1.2  macallan 
    259   1.2  macallan STATIC int
    260   1.2  macallan jziic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
    261   1.2  macallan     size_t cmdlen, void *vbuf, size_t buflen, int flags)
    262   1.2  macallan {
    263   1.2  macallan 	struct jziic_softc *sc = cookie;
    264   1.2  macallan 
    265   1.7   thorpej 	if (flags & I2C_F_POLL) {
    266   1.2  macallan 		return jziic_i2c_exec_poll(sc, op, addr, vcmd, cmdlen, vbuf,
    267   1.2  macallan 		    buflen, flags);
    268   1.2  macallan 	} else {
    269   1.2  macallan #ifdef JZIIC_DEBUG
    270   1.2  macallan 		uint8_t *b = vbuf;
    271   1.2  macallan 		int i, ret;
    272   1.2  macallan 
    273   1.2  macallan 		memset(vbuf, 0, buflen);
    274   1.2  macallan 		jziic_i2c_exec_intr(sc, op, addr, vcmd, cmdlen, vbuf,
    275   1.2  macallan 		    buflen, flags);
    276   1.2  macallan 		for (i = 0; i < buflen; i++) {
    277   1.2  macallan 			printf(" %02x", b[i]);
    278   1.2  macallan 		}
    279   1.2  macallan 		printf("\n");
    280   1.2  macallan 		ret = jziic_i2c_exec_poll(sc, op, addr, vcmd, cmdlen, vbuf,
    281   1.2  macallan 		    buflen, flags);
    282   1.2  macallan 		for (i = 0; i < buflen; i++) {
    283   1.2  macallan 			printf(" %02x", b[i]);
    284   1.2  macallan 		}
    285   1.2  macallan 		printf("\n");
    286   1.2  macallan 		return ret;
    287   1.2  macallan #else
    288   1.2  macallan 		return jziic_i2c_exec_intr(sc, op, addr, vcmd, cmdlen, vbuf,
    289   1.2  macallan 		    buflen, flags);
    290   1.2  macallan #endif
    291   1.2  macallan 	}
    292   1.2  macallan }
    293   1.2  macallan 
    294   1.2  macallan STATIC int
    295   1.2  macallan jziic_i2c_exec_poll(struct jziic_softc *sc, i2c_op_t op, i2c_addr_t addr,
    296   1.2  macallan     const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
    297   1.2  macallan {
    298   1.2  macallan 	int i, bail = 10000, ret = 0;
    299   1.2  macallan 	uint32_t abort;
    300   1.2  macallan 	uint8_t *rx, data;
    301   1.2  macallan 	const uint8_t *tx;
    302   1.2  macallan 
    303   1.2  macallan 	tx = vcmd;
    304   1.2  macallan 	rx = vbuf;
    305   1.2  macallan 
    306   1.2  macallan 	DPRINTF("%s: 0x%02x %d %d\n", __func__, addr, cmdlen, buflen);
    307   1.2  macallan 
    308   1.2  macallan 	jziic_disable(sc);
    309   1.2  macallan 
    310   1.2  macallan 	/* we're polling, so disable interrupts */
    311   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    312   1.2  macallan 
    313   1.2  macallan 	jziic_set_speed(sc);
    314   1.1  macallan 	jziic_wait(sc);
    315   1.1  macallan 	/* try to talk... */
    316   1.1  macallan 
    317   1.1  macallan 	if (!jziic_enable(sc)) {
    318   1.1  macallan 		ret = -1;
    319   1.1  macallan 		goto bork;
    320   1.1  macallan 	}
    321   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    322   1.1  macallan 
    323   1.1  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTAR, addr);
    324   1.1  macallan 	jziic_wait(sc);
    325   1.1  macallan 	DPRINTF("st: %02x\n",
    326   1.1  macallan 	    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST));
    327   1.1  macallan 	DPRINTF("wr int: %02x\n",
    328   1.1  macallan 	    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST));
    329   1.1  macallan 	abort = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC);
    330   1.1  macallan 	DPRINTF("abort: %02x\n", abort);
    331   1.1  macallan 	if ((abort != 0)) {
    332   1.1  macallan 		ret = -1;
    333   1.1  macallan 		goto bork;
    334   1.1  macallan 	}
    335   1.1  macallan 
    336   1.1  macallan 	do {
    337   1.1  macallan 		bail--;
    338   1.1  macallan 		delay(100);
    339   1.1  macallan 	} while (((bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST) &
    340   1.1  macallan 	           JZ_TFE) == 0) && (bail > 0));
    341   1.1  macallan 
    342   1.1  macallan 	if (cmdlen != 0) {
    343   1.1  macallan 		for (i = 0; i < cmdlen; i++) {
    344   1.1  macallan 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    345   1.1  macallan 			    JZ_SMBDC, *tx);
    346   1.1  macallan 			tx++;
    347   1.1  macallan 		}
    348   1.1  macallan 	}
    349   1.1  macallan 
    350   1.1  macallan 	if (I2C_OP_READ_P(op)) {
    351   1.1  macallan 		/* now read */
    352   1.1  macallan 		for (i = 0; i < (buflen + 1); i++) {
    353   1.1  macallan 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    354   1.1  macallan 			    JZ_SMBDC, JZ_CMD);
    355   1.1  macallan 		}
    356   1.1  macallan 		wbflush();
    357   1.1  macallan 		DPRINTF("rd st: %02x\n",
    358   1.1  macallan 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST));
    359   1.1  macallan 		DPRINTF("rd int: %02x\n",
    360   1.1  macallan 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST));
    361   1.1  macallan 		DPRINTF("abort: %02x\n",
    362   1.1  macallan 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBABTSRC));
    363   1.1  macallan 		for (i = 0; i < buflen; i++) {
    364   1.1  macallan 			bail = 10000;
    365   1.1  macallan 			while (((bus_space_read_4(sc->sc_memt, sc->sc_memh,
    366   1.1  macallan 				  JZ_SMBST) & JZ_RFNE) == 0) && (bail > 0)) {
    367   1.1  macallan 				bail--;
    368   1.1  macallan 				delay(100);
    369   1.4     skrll 			}
    370   1.1  macallan 			if (bail == 0) {
    371   1.1  macallan 				ret = -1;
    372   1.1  macallan 				goto bork;
    373   1.1  macallan 			}
    374   1.1  macallan 			data = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    375   1.1  macallan 			    JZ_SMBDC);
    376   1.1  macallan 			DPRINTF("rd st: %02x %d\n",
    377   1.1  macallan 			  bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST),
    378   1.1  macallan 			  bail);
    379   1.1  macallan 			DPRINTF("rd int: %02x\n",
    380   1.1  macallan 			  bus_space_read_4(sc->sc_memt, sc->sc_memh,
    381   1.1  macallan 			   JZ_SMBINTST));
    382   1.1  macallan 			DPRINTF("abort: %02x\n", abort);
    383   1.1  macallan 			DPRINTF("rd data: %02x\n", data);
    384   1.1  macallan 			*rx = data;
    385   1.1  macallan 			rx++;
    386   1.1  macallan 		}
    387   1.1  macallan 	} else {
    388   1.1  macallan 		tx = vbuf;
    389   1.1  macallan 		for (i = 0; i < buflen; i++) {
    390   1.1  macallan 			DPRINTF("wr data: %02x\n", *tx);
    391   1.1  macallan 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    392   1.1  macallan 			    JZ_SMBDC, *tx);
    393   1.1  macallan 			wbflush();
    394   1.1  macallan 			tx++;
    395   1.1  macallan 		}
    396   1.1  macallan 		jziic_wait(sc);
    397   1.1  macallan 		abort = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    398   1.1  macallan 		    JZ_SMBABTSRC);
    399   1.1  macallan 		DPRINTF("abort: %02x\n", abort);
    400   1.1  macallan 		if ((abort != 0)) {
    401   1.1  macallan 			ret = -1;
    402   1.1  macallan 			goto bork;
    403   1.1  macallan 		}
    404   1.1  macallan 
    405   1.1  macallan 		DPRINTF("st: %02x %d\n",
    406   1.1  macallan 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST), bail);
    407   1.1  macallan 		DPRINTF("wr int: %02x\n",
    408   1.1  macallan 		    bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST));
    409   1.1  macallan 	}
    410   1.1  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON,
    411   1.1  macallan 	    JZ_SLVDIS | JZ_REST | JZ_SPD_100KB | JZ_MD);
    412   1.1  macallan bork:
    413   1.1  macallan 	jziic_disable(sc);
    414   1.1  macallan 	return ret;
    415   1.1  macallan }
    416   1.2  macallan 
    417   1.2  macallan STATIC int
    418   1.2  macallan jziic_i2c_exec_intr(struct jziic_softc *sc, i2c_op_t op, i2c_addr_t addr,
    419   1.2  macallan     const void *vcmd, size_t cmdlen, void *vbuf, size_t buflen, int flags)
    420   1.2  macallan {
    421   1.2  macallan 	int i, ret = 0, bail;
    422   1.2  macallan 
    423   1.2  macallan 	DPRINTF("%s: 0x%02x %d %d\n", __func__, addr, cmdlen, buflen);
    424   1.2  macallan 
    425   1.2  macallan 	jziic_disable(sc);
    426   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    427   1.2  macallan 
    428   1.2  macallan 	mutex_enter(&sc->sc_cvlock);
    429   1.2  macallan 
    430   1.2  macallan 	sc->sc_reading = FALSE;
    431   1.2  macallan 
    432   1.2  macallan 	if (I2C_OP_READ_P(op)) {
    433   1.2  macallan 		sc->sc_cmd = vcmd;
    434   1.2  macallan 		sc->sc_cmdlen = cmdlen;
    435   1.2  macallan 		sc->sc_buf = vbuf;
    436   1.2  macallan 		sc->sc_buflen = buflen;
    437   1.2  macallan 		memset(vbuf, 0, buflen);
    438   1.2  macallan 	} else {
    439   1.2  macallan 		if ((cmdlen + buflen) > 256)
    440   1.2  macallan 			return -1;
    441   1.2  macallan 		memcpy(sc->sc_txbuf, vcmd, cmdlen);
    442   1.2  macallan 		memcpy(sc->sc_txbuf + cmdlen, vbuf, buflen);
    443   1.2  macallan 		sc->sc_cmd = sc->sc_txbuf;
    444   1.2  macallan 		sc->sc_cmdlen = cmdlen + buflen;
    445   1.2  macallan 		sc->sc_buf = NULL;
    446   1.2  macallan 		sc->sc_buflen = 0;
    447   1.2  macallan 	}
    448   1.2  macallan 	sc->sc_cmdptr = 0;
    449   1.2  macallan 	sc->sc_bufptr = 0;
    450   1.2  macallan 	sc->sc_rds = 0;
    451   1.2  macallan 	sc->sc_abort = 0;
    452   1.2  macallan 
    453   1.2  macallan 	jziic_set_speed(sc);
    454   1.2  macallan 	jziic_wait(sc);
    455   1.2  macallan 
    456   1.2  macallan 	/* set FIFO levels */
    457   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTXTL, 4);
    458   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBRXTL, 0
    459   1.2  macallan 	    /*min(7, max(0, buflen - 2 ))*/);
    460   1.2  macallan 
    461   1.2  macallan 	/* try to talk... */
    462   1.2  macallan 
    463   1.2  macallan 	if (!jziic_enable(sc)) {
    464   1.2  macallan 		ret = -1;
    465   1.2  macallan 		goto bork;
    466   1.2  macallan 	}
    467   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    468   1.2  macallan 
    469   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBTAR, addr);
    470   1.2  macallan 	jziic_wait(sc);
    471   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT, JZ_CLEARALL);
    472   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM,
    473   1.2  macallan 	    JZ_TXABT | JZ_TXEMP);
    474   1.2  macallan 
    475   1.2  macallan 	bail = 100 * sc->sc_cmdlen;
    476   1.2  macallan 	while ((sc->sc_cmdptr < sc->sc_cmdlen) && (bail > 0)) {
    477   1.2  macallan 		cv_timedwait(&sc->sc_ping, &sc->sc_cvlock, 1);
    478   1.2  macallan 		if (sc->sc_abort) {
    479   1.2  macallan 			/* we received an abort interrupt -> bailout */
    480   1.2  macallan 		    	DPRINTF("abort: %x\n", sc->sc_abort);
    481   1.2  macallan 		    	ret = -1;
    482   1.2  macallan 		    	goto bork;
    483   1.2  macallan 		}
    484   1.2  macallan 	    	bail--;
    485   1.2  macallan 	}
    486   1.2  macallan 
    487   1.2  macallan 	if (sc->sc_cmdptr < sc->sc_cmdlen) {
    488   1.2  macallan 		/* we didn't send everything? */
    489   1.2  macallan 	    	DPRINTF("sent %d of %d\n", sc->sc_cmdptr, sc->sc_cmdlen);
    490   1.2  macallan 	    	ret = -1;
    491   1.2  macallan 	    	goto bork;
    492   1.2  macallan 	}
    493   1.2  macallan 
    494   1.2  macallan 	if (I2C_OP_READ_P(op)) {
    495   1.2  macallan 		/* now read */
    496   1.2  macallan 		sc->sc_reading = TRUE;
    497   1.2  macallan 		bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM,
    498   1.2  macallan 		    JZ_TXABT | JZ_RXFL | JZ_TXEMP);
    499   1.2  macallan 
    500   1.5  riastrad 		for (i = 0; i < uimin((buflen + 1), 4); i++) {
    501   1.2  macallan 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
    502   1.2  macallan 			    JZ_SMBDC, JZ_CMD);
    503   1.2  macallan 			wbflush();
    504   1.2  macallan 		}
    505   1.2  macallan 		sc->sc_rds = i;
    506   1.2  macallan 
    507   1.2  macallan 		bail = 10 * sc->sc_buflen; /* 10 ticks per byte should be ok */
    508   1.2  macallan 		while ((sc->sc_bufptr < sc->sc_buflen) && (bail > 0)) {
    509   1.4     skrll 			cv_timedwait(&sc->sc_ping, &sc->sc_cvlock, 1);
    510   1.2  macallan 			if (sc->sc_abort) {
    511   1.2  macallan 				/* we received an abort interrupt -> bailout */
    512   1.2  macallan 		  	  	DPRINTF("rx abort: %x\n", sc->sc_abort);
    513   1.2  macallan 			    	ret = -1;
    514   1.2  macallan 			    	goto bork;
    515   1.2  macallan 			}
    516   1.2  macallan 			bail--;
    517   1.2  macallan 		}
    518   1.2  macallan 
    519   1.2  macallan 		if (sc->sc_bufptr < sc->sc_buflen) {
    520   1.2  macallan 			/* we didn't get everything? */
    521   1.2  macallan 		    	DPRINTF("rcvd %d of %d\n", sc->sc_bufptr, sc->sc_buflen);
    522   1.2  macallan 		    	ret = -1;
    523   1.2  macallan 		    	goto bork;
    524   1.2  macallan 		}
    525   1.2  macallan 	}
    526   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCON,
    527   1.2  macallan 	    JZ_SLVDIS | JZ_REST | JZ_SPD_100KB | JZ_MD);
    528   1.2  macallan bork:
    529   1.2  macallan 	bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    530   1.2  macallan 	jziic_disable(sc);
    531   1.2  macallan 	mutex_exit(&sc->sc_cvlock);
    532   1.2  macallan 	return ret;
    533   1.2  macallan }
    534   1.2  macallan 
    535   1.2  macallan STATIC int
    536   1.2  macallan jziic_intr(void *cookie)
    537   1.2  macallan {
    538   1.2  macallan 	struct jziic_softc *sc = cookie;
    539   1.2  macallan 	uint32_t stat, data, rstat;
    540   1.2  macallan 	int i;
    541   1.2  macallan 
    542   1.2  macallan 	stat = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTST);
    543   1.2  macallan 	if (stat & JZ_TXEMP) {
    544   1.2  macallan 		if (sc->sc_reading) {
    545   1.2  macallan 			if (sc->sc_rds < (sc->sc_buflen + 1)) {
    546   1.2  macallan 				for (i = 0;
    547   1.5  riastrad 				     i < uimin(4, (sc->sc_buflen + 1) -
    548   1.2  macallan 				                 sc->sc_rds);
    549   1.2  macallan 				     i++) {
    550   1.2  macallan 					bus_space_write_4( sc->sc_memt,
    551   1.2  macallan 					    sc->sc_memh,
    552   1.2  macallan 					    JZ_SMBDC, JZ_CMD);
    553   1.2  macallan 					wbflush();
    554   1.2  macallan 				}
    555   1.2  macallan 				sc->sc_rds += i;
    556   1.2  macallan 			} else {
    557   1.2  macallan 				/* we're done, so turn TX FIFO interrupt off */
    558   1.2  macallan 				bus_space_write_4(sc->sc_memt, sc->sc_memh,
    559   1.2  macallan 				    JZ_SMBINTM,
    560   1.2  macallan 				    JZ_TXABT | JZ_RXFL);
    561   1.2  macallan 			}
    562   1.4     skrll 		} else {
    563   1.2  macallan 			rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    564   1.2  macallan 			    JZ_SMBST);
    565   1.4     skrll 			while ((rstat & JZ_TFNF) &&
    566   1.2  macallan 			         (sc->sc_cmdptr < sc->sc_cmdlen)) {
    567   1.2  macallan 				data = *sc->sc_cmd;
    568   1.2  macallan 				sc->sc_cmd++;
    569   1.2  macallan 				sc->sc_cmdptr++;
    570   1.2  macallan 				bus_space_write_4(sc->sc_memt, sc->sc_memh,
    571   1.2  macallan 				    JZ_SMBDC, data & 0xff);
    572   1.2  macallan 				rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    573   1.2  macallan 				    JZ_SMBST);
    574   1.2  macallan 			};
    575   1.2  macallan 			/* no need to clear this one */
    576   1.2  macallan 			if (sc->sc_cmdptr >= sc->sc_cmdlen) {
    577   1.2  macallan 				cv_signal(&sc->sc_ping);
    578   1.2  macallan 				bus_space_write_4(sc->sc_memt, sc->sc_memh,
    579   1.2  macallan 				    JZ_SMBINTM, JZ_TXABT);
    580   1.2  macallan 			}
    581   1.4     skrll 		}
    582   1.2  macallan 	}
    583   1.2  macallan 	if (stat & JZ_RXFL) {
    584   1.2  macallan 		rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh, JZ_SMBST);
    585   1.2  macallan 		while ((rstat & JZ_RFNE) && (sc->sc_bufptr < sc->sc_buflen)) {
    586   1.2  macallan 			data = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    587   1.2  macallan 			   JZ_SMBDC);
    588   1.2  macallan 			*sc->sc_buf = (uint8_t)(data & 0xff);
    589   1.2  macallan 			sc->sc_buf++;
    590   1.2  macallan 			sc->sc_bufptr++;
    591   1.2  macallan 			rstat = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    592   1.2  macallan 			    JZ_SMBST);
    593   1.2  macallan 		}
    594   1.2  macallan 		if (sc->sc_bufptr >= sc->sc_buflen)
    595   1.2  macallan 			cv_signal(&sc->sc_ping);
    596   1.2  macallan 	}
    597   1.2  macallan 	if (stat & JZ_TXABT) {
    598   1.2  macallan 		sc->sc_abort = bus_space_read_4(sc->sc_memt, sc->sc_memh,
    599   1.2  macallan 		    JZ_SMBABTSRC);
    600   1.2  macallan 		cv_signal(&sc->sc_ping);
    601   1.2  macallan 		bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBCINT,
    602   1.2  macallan 		    JZ_CLEARALL);
    603   1.2  macallan 		bus_space_write_4(sc->sc_memt, sc->sc_memh, JZ_SMBINTM, 0);
    604   1.2  macallan 	}
    605   1.2  macallan 	return 0;
    606   1.2  macallan }
    607