Home | History | Annotate | Line # | Download | only in dev
      1 /* $NetBSD: fire_i2c.c,v 1.5 2026/09/25 07:16:27 jdc Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2026 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Julian Coleman.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: fire_i2c.c,v 1.5 2026/09/25 07:16:27 jdc Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/condvar.h>
     37 #include <sys/device.h>
     38 #include <sys/intr.h>
     39 #include <sys/kernel.h>
     40 #include <sys/mutex.h>
     41 
     42 #include <machine/autoconf.h>
     43 #include <machine/openfirm.h>
     44 
     45 #include <dev/pci/pcivar.h>
     46 
     47 #include <dev/i2c/i2cvar.h>
     48 #include <sparc64/dev/fire_i2creg.h>
     49 #include <sparc64/dev/iommureg.h>
     50 #include <sparc64/dev/iommuvar.h>
     51 #include <sparc64/dev/pyrovar.h>
     52 
     53 #include "ioconf.h"
     54 
     55 #define FIREI2C_DEBUG 0
     56 #if FIREI2C_DEBUG > 0
     57 int dlvl = 1;		/* Set to 2 for verbose i2c ops output */
     58 #define DPRINTF(n) if (dlvl >= n) printf
     59 #else
     60 #define DPRINTF(n) if (0) printf
     61 #endif
     62 
     63 #define FIREI2C_SCL_FREQ	100000	/* Target i2c clock frequency */
     64 #define FIREI2C_OWN_ADDR	0x08	/* Our i2c slave address */
     65 
     66 /* i2c clocks to match possible system clock frequencies (1/1, 1/2, 1/32) */
     67 #define FIREI2C_CLK_FULL	0
     68 #define FIREI2C_CLK_HALF	1
     69 #define FIREI2C_CLK_TT		2
     70 #define FIREI2C_CLK_LEN		3
     71 
     72 /* i2c operations */
     73 #define FIREI2C_OP_READ		0x01
     74 #define FIREI2C_OP_WRITE	0x02
     75 #define FIREI2C_OP_WR_RD	0x04
     76 
     77 /* i2c stages */
     78 #define FIREI2C_STAGE_IDLE	0x00
     79 #define FIREI2C_STAGE_START	0x01
     80 #define FIREI2C_STAGE_WR_ADDR	0x02
     81 #define FIREI2C_STAGE_RE_ADDR	0x04
     82 #define FIREI2C_STAGE_WRITE	0x08
     83 #define FIREI2C_STAGE_REPSTART	0x10
     84 #define FIREI2C_STAGE_READ	0x20
     85 #define FIREI2C_STAGE_STOP	0x40
     86 
     87 /* mainbus intr map/mask are only used for i2c interrupts, so put them here. */
     88 struct mainbus_interrupt_map {
     89 	uint64_t paddr;		/* phys addr mask */
     90 	uint32_t intr;		/* interrupt mask */
     91 	int32_t cnode;		/* child node */
     92 	uint32_t cintr;		/* child interrupt */
     93 } __packed;
     94 
     95 struct mainbus_interrupt_map_mask {
     96 	uint64_t paddr;		/* phys addr mask */
     97 	uint32_t intr;		/* interrupt */
     98 } __packed;
     99 
    100 struct firei2c_softc {
    101 	device_t sc_dev;
    102 	bus_space_tag_t sc_bustag;
    103 	bus_space_handle_t sc_regh;
    104 	int sc_node;
    105 	void *sc_inth;
    106 
    107 	uint8_t sc_i2c_clks[FIREI2C_CLK_LEN];	/* Clocks for sys bus speeds */
    108 
    109 	struct i2c_controller sc_i2c;
    110 
    111 	kmutex_t sc_mutex;		/* Interrupt mutex ... */
    112 	kcondvar_t sc_cv;		/* ... and condvar */
    113 
    114 	int sc_op;			/* Operation to run */
    115 	int sc_stage;			/* Exec stage */
    116 	i2c_addr_t sc_target;		/* Saved exec args */
    117 	const u_int8_t *sc_cmdbuf;	/* ... */
    118 	size_t sc_cmdlen;		/* ... */
    119 	u_int8_t *sc_buf;		/* ... */
    120 	size_t sc_buflen;		/* ... */
    121 	int sc_i;			/* How far through buf */
    122 	int sc_err;			/* Error during transaction */
    123 
    124 };
    125 
    126 static int firei2c_match(device_t, cfdata_t, void *);
    127 static void firei2c_attach(device_t, device_t, void *);
    128 static void firei2c_intr_establish(struct firei2c_softc *,
    129     struct mainbus_attach_args *);
    130 static uint8_t firei2c_clock(int);
    131 static int firei2c_stop(struct firei2c_softc *);
    132 static int firei2c_wait(struct firei2c_softc *, int);
    133 int firei2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
    134     size_t, void *, size_t, int);
    135 static int firei2c_write(struct firei2c_softc *, const uint8_t *, size_t,
    136     uint8_t *, size_t, int);
    137 static int firei2c_read(struct firei2c_softc *, uint8_t *, size_t, int);
    138 int firei2c_intr(void *);
    139 static uint8_t firei2c_reg_read(struct firei2c_softc *, bus_size_t);
    140 static void firei2c_reg_write(struct firei2c_softc *, bus_size_t, uint8_t);
    141 
    142 CFATTACH_DECL_NEW(firei2c, sizeof(struct firei2c_softc),
    143 	firei2c_match, firei2c_attach, NULL, NULL);
    144 
    145 static int
    146 firei2c_match(device_t parent, cfdata_t cf, void *aux)
    147 {
    148 	struct mainbus_attach_args *ma = aux;
    149 	char *compat;
    150 
    151 	if (strcmp(ma->ma_name, "i2c"))
    152 		return 0;
    153 
    154 	compat = prom_getpropstring(ma->ma_node, "compatible");
    155 	if (!strcmp(compat, "fire-i2c"))
    156 		return 1;
    157 
    158 	return 0;
    159 }
    160 
    161 static void
    162 firei2c_attach(device_t parent, device_t self, void *aux)
    163 {
    164 	struct firei2c_softc *sc = device_private(self);
    165 	struct mainbus_attach_args *ma = aux;
    166 	int  sysclk;
    167 
    168 	sc->sc_bustag = ma->ma_bustag;
    169 	sc->sc_node = ma->ma_node;
    170 	sc->sc_dev = self;
    171 
    172 	if (ma->ma_nreg != 1) {
    173 		aprint_error(": register count error (%d != 1)\n",
    174 		    ma->ma_nreg);
    175 		return;
    176 	}
    177 	if (ma->ma_reg[0].ur_len < FIREI2C_SRST) {
    178 		aprint_error(": register length error (%" PRId64 " < %d\n",
    179 		    ma->ma_reg[0].ur_len, FIREI2C_SRST);
    180 		return;
    181 	}
    182 
    183 	if (bus_space_map(sc->sc_bustag, ma->ma_reg[0].ur_paddr,
    184 	    ma->ma_reg[0].ur_len, 0, &sc->sc_regh)) {
    185 		aprint_error(": failed to map registers\n");
    186 		return;
    187 	}
    188 
    189 	aprint_normal(": addr %" PRIx64 ": Fire/MI2C i2c controller\n",
    190 	    ma->ma_reg[0].ur_paddr);
    191 
    192 	firei2c_intr_establish(sc, ma);
    193 
    194 	/* Calculate clock, software reset, set our address */
    195 	sysclk = prom_getpropint(findroot(), "clock-frequency", 0);
    196 	sc->sc_i2c_clks[FIREI2C_CLK_FULL] = firei2c_clock(sysclk);
    197 	sc->sc_i2c_clks[FIREI2C_CLK_HALF] = firei2c_clock(sysclk / 2);
    198 	sc->sc_i2c_clks[FIREI2C_CLK_TT] = firei2c_clock(sysclk / 32);
    199 	firei2c_reg_write(sc, FIREI2C_SRST, FIREI2C_SRST_RST);
    200 	delay(1000);
    201 	firei2c_reg_write(sc, FIREI2C_CCR, sc->sc_i2c_clks[FIREI2C_CLK_FULL]);
    202 	firei2c_reg_write(sc, FIREI2C_ADDR,
    203 	    FIREI2C_OWN_ADDR << FIREI2C_ADDR_SHIFT);
    204 
    205 	/* i2c setup */
    206 	iic_tag_init(&sc->sc_i2c);
    207 	sc->sc_i2c.ic_cookie = sc;
    208 	sc->sc_i2c.ic_exec = firei2c_exec;
    209 
    210 	/* Synchronisation between exec and intr */
    211 	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
    212 	cv_init(&sc->sc_cv, "firei2c");
    213 	sc->sc_stage = FIREI2C_STAGE_IDLE;
    214 
    215 	iicbus_attach(sc->sc_dev, &sc->sc_i2c);
    216 	return;
    217 }
    218 
    219 /*
    220  * Use the mainbus (root) interrupt map/mask to find our interrupt number
    221  * (ino 60 or 61) and pyro leaf.
    222  * Both i2c interrupts must go to the same pyro leaf, but we assume that
    223  * OFW has set up the ino and the leaf mapping for us.
    224  */
    225 #define IMASK_LEN 3
    226 #define IMAP_LEN 10
    227 static void
    228 firei2c_intr_establish(struct firei2c_softc *sc,
    229     struct mainbus_attach_args *ma)
    230 {
    231 	struct mainbus_interrupt_map *mb_imap;
    232 	struct mainbus_interrupt_map_mask *mb_imask;
    233 	struct pyro_softc *psc = NULL;
    234 	int64_t paddr;
    235 	u_int intr;
    236 	int ihandle, root, size, i;
    237 
    238 	sc->sc_inth = NULL;	/* Default */
    239 	ihandle = 0;
    240 
    241 	/* Find our mapped interrupt number */
    242 	root = findroot();
    243 	mb_imask = NULL;
    244 	if (prom_getprop(root, "interrupt-map-mask",
    245 	    sizeof(int32_t), &size, (void **) &mb_imask) ||
    246 	    size != IMASK_LEN) {
    247 		aprint_error(": no interrupt-map-mask\n");
    248 		return;
    249 	}
    250 
    251 	mb_imap = NULL;
    252 	if (prom_getprop(root, "interrupt-map",
    253 	    sizeof(int32_t), &size, (void **) &mb_imap) ||
    254 	    size != IMAP_LEN) {
    255 		aprint_error(": no interrupt-map\n");
    256 		return;
    257 	}
    258 
    259 	intr = ma->ma_interrupts[0] && mb_imask->intr;
    260 	DPRINTF(1)("%s: intr %x masked to %x\n",
    261 	    device_xname(sc->sc_dev), ma->ma_interrupts[0], intr);
    262 	paddr = ma->ma_reg[0].ur_paddr & mb_imask->paddr;
    263 	DPRINTF(1)("%s: reg 0x%" PRIx64 " masked to 0x%" PRIx64 "\n",
    264 	    device_xname(sc->sc_dev), ma->ma_reg[0].ur_paddr, paddr);
    265 	for (i = 0; i < 2; i++) {
    266 		DPRINTF(1)("%s: checking paddr 0x%" PRIx64 ", intr %x\n",
    267 		    device_xname(sc->sc_dev), mb_imap->paddr, mb_imap->intr);
    268 		if (paddr == mb_imap->paddr && intr == mb_imap->intr) {
    269 			ihandle = mb_imap->cintr;
    270 			DPRINTF(1)("%s: found cintr %d, cnode 0x%x\n",
    271 			    device_xname(sc->sc_dev), ihandle, mb_imap->cnode);
    272 			break;
    273 		}
    274 		mb_imap++;
    275 	}
    276 	if (ihandle == 0) {
    277 		aprint_error(": failed to match interrupt\n");
    278 		return;
    279 	}
    280 
    281 	/* Find the pyro leaf with the matching cnode ) */
    282 	for (i = 0; i < pyro_cd.cd_ndevs; i++) {
    283 		device_t dt = device_lookup(&pyro_cd, i);
    284 		psc = device_private(dt);
    285 		if (psc && psc->sc_node == mb_imap->cnode) {
    286 			DPRINTF(1)("%s: matched pyro %d (0x%x)\n",
    287 			    device_xname(sc->sc_dev), i, psc->sc_node);
    288 			ihandle |= psc->sc_ign;
    289 			break;
    290 		}
    291 	}
    292 	if (psc == NULL) {
    293 		aprint_error(": failed to match pyro leaf\n");
    294 		return;
    295 	}
    296 
    297 	sc->sc_inth = psc->intr_establish_sc(psc,
    298 	    ihandle, IPL_BIO, firei2c_intr, sc, NULL);
    299 
    300 	if (sc->sc_inth != NULL) {
    301 		aprint_normal_dev(sc->sc_dev,
    302 		    "interrupting at ivec %x on pyro%d\n", ihandle, i);
    303 	}
    304 
    305 	return;
    306 }
    307 
    308 /*
    309  * Sampling frequency: input clock divided by 2^N (N is bits 0:2)
    310  * SCL frequency: sampling frequency divided by (M + 1) * 10 (bits 3:6)
    311  * i2c SCL is max 100kHz, so find the closest frequency at or below that.
    312  *
    313  * If the system (JBus) clock frequency changes, we must change our clock.
    314  * If increasing: after the JBus change, if decreasing: before the change.
    315  * This is to avoid running the i2c clock faster than the specification.
    316  */
    317 static uint8_t
    318 firei2c_clock(int sysclk)
    319 {
    320 	int p, f, best_p, best_f;
    321 	uint32_t sample, scl;
    322 	uint32_t min = FIREI2C_SCL_FREQ;
    323 	uint8_t clkval;
    324 
    325 	best_p = 0;
    326 	best_f = 0;
    327 	for (p = 0; p <= FIREI2C_CCR_POW2_MAX; p++) {
    328 		if (p)
    329 			sample = sysclk / (2 << (p - 1));
    330 		else
    331 			sample = sysclk;
    332 		for (f = 0; f <= FIREI2C_CCR_FACT_MAX; f++) {
    333 			scl = sample / ((f + 1) * 10);
    334 			if (scl <= FIREI2C_SCL_FREQ) {
    335 				if (FIREI2C_SCL_FREQ - scl < min) {
    336 					best_p = p;
    337 					best_f = f;
    338 					min = FIREI2C_SCL_FREQ - scl;
    339 				}
    340 				break;	/* Already at or below SCL_FREQ */
    341 			}
    342 		}
    343 		if (!min)	/* Exactly SCL_FREQ */
    344 			break;
    345 	}
    346 	clkval = best_p + (best_f << FIREI2C_CCR_FACT_SHIFT);
    347 	return clkval;
    348 }
    349 
    350 /* No interrupts for stop, so wait for idle */
    351 static int
    352 firei2c_stop(struct firei2c_softc *sc)
    353 {
    354 	int i;
    355 	uint8_t ctrl, val;
    356 
    357 	ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_STP;
    358 	firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    359 	for (i = 0; i < 500; i++) {
    360 		val = firei2c_reg_read(sc, FIREI2C_STAT);
    361 		if (val == FIREI2C_STAT_IDLE) {
    362 			mutex_enter(&sc->sc_mutex);
    363 			sc->sc_stage = FIREI2C_STAGE_IDLE;
    364 			mutex_exit(&sc->sc_mutex);
    365 			return 0;
    366 		}
    367 		delay(1000);
    368 	}
    369 	/* Clear the interrupt flag if we timed out */
    370 	ctrl = FIREI2C_CTRL_ENAB;
    371 	firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    372 	/* Set the stage to idle, even for timeout */
    373 	mutex_enter(&sc->sc_mutex);
    374 	sc->sc_stage = FIREI2C_STAGE_IDLE;
    375 	mutex_exit(&sc->sc_mutex);
    376 	return 1;
    377 }
    378 
    379 
    380 static int
    381 firei2c_wait(struct firei2c_softc *sc, int flags)
    382 {
    383 	volatile uint8_t ctrl;
    384 	int i;
    385 
    386 	for (i = 0; i < 500; i++) {
    387 		ctrl = firei2c_reg_read(sc, FIREI2C_CTRL);
    388 		if (ctrl & FIREI2C_CTRL_IFLG)
    389 			return 0;
    390 		delay(1000);
    391 	}
    392 	return 1;
    393 }
    394 
    395 /*
    396  * Flow for a "simple" read/write:
    397  *   1.  Send start
    398  *   2.  Send addr + R or W
    399  *   3.  Receive ACK
    400  *   4.  (nothing)
    401  *   5.  (nothing)
    402  *   6R. Receive data			6W.  Send data
    403  *   7R. Send ACK or NAK		7W.  Receive ACK or NAK
    404  *       either receive more (6R) or	     either write more (6W) or
    405  *   8.  Send stop
    406  *
    407  * Flow for read/write following a "register" write:
    408  *   1.  Send start
    409  *   2.  Send addr + W
    410  *   3.  Receive ACK
    411  *   4.  Send register
    412  *   5R. Send repeat start + addr + R	5W.  (nothing to do)
    413  *   6R. Receive data			6W.  Send data
    414  *   7R. Send ACK or NAK		7W.  Receive ACK or NAK
    415  *       either receive more (6R) or	     either write more (6W) or
    416  *   8.  Send stop
    417  *
    418  * After each step, we receive an interrupt notifying us of the result.
    419  * We clear the interrupt flag, check the status, and set up the next step.
    420  * If we're polling, we check the flag in a loop instead.
    421  */
    422 int
    423 firei2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, const void *cmd,
    424     size_t cmdlen, void *vbuf, size_t buflen, int flags)
    425 {
    426 	struct firei2c_softc *sc = arg;
    427 	const uint8_t *cmdbuf = cmd;
    428 	uint8_t *buf = vbuf;
    429 	uint8_t ctrl, val, ack, nack;
    430 	unsigned deadline, rem;
    431 	int err;
    432 
    433 	DPRINTF(1)("%s: exec op: %d addr: 0x%x "
    434 	    "cmdlen: %d buflen: %d flags 0x%x, intr %s, poll %s\n",
    435 	    device_xname(sc->sc_dev), op, addr,
    436 	    (int) cmdlen, (int) buflen, flags,
    437 	    sc->sc_inth == NULL ? "no" : "yes",
    438 	    flags & I2C_F_POLL ? "yes" : "no");
    439 	val = firei2c_reg_read(sc, FIREI2C_STAT);
    440 	if (val != FIREI2C_STAT_IDLE) {
    441 		/* Try sending stop */
    442 		DPRINTF(1)("%s: not idle, sending stop\n",
    443 		    device_xname(sc->sc_dev));
    444 		err = firei2c_stop(sc);
    445 		if (err) {
    446 			printf("%s: not idle (0x%02x)\n",
    447 			    device_xname(sc->sc_dev), val);
    448 			return 1;
    449 		}
    450 	}
    451 
    452 	/* Control defaults - bus enabled, interrupts enabled */
    453 	ctrl = FIREI2C_CTRL_ENAB;
    454 	if (sc->sc_inth != NULL && !(flags & I2C_F_POLL)) {
    455 		ctrl |= FIREI2C_CTRL_IEN;
    456 		sc->sc_target = addr;
    457 		sc->sc_cmdbuf = cmdbuf;
    458 		sc->sc_cmdlen = cmdlen;
    459 		sc->sc_buf = buf;
    460 		sc->sc_buflen = buflen;
    461 		sc->sc_i = 0;
    462 		sc->sc_err = 0;
    463 		if (I2C_OP_READ_P(op))
    464 			if (cmdlen > 0)
    465 				sc->sc_op = FIREI2C_OP_WR_RD;
    466 			else
    467 				sc->sc_op = FIREI2C_OP_READ;
    468 		else
    469 			sc->sc_op = FIREI2C_OP_WRITE;
    470 		mutex_enter(&sc->sc_mutex);
    471 		sc->sc_stage = FIREI2C_STAGE_START;
    472 		mutex_exit(&sc->sc_mutex);
    473 	}
    474 
    475 	/* Send start */
    476 	firei2c_reg_write(sc, FIREI2C_CTRL, ctrl | FIREI2C_CTRL_STA);
    477 
    478 	/* Interrupt-driven */
    479 	if (sc->sc_inth != NULL && !(flags & I2C_F_POLL)) {
    480 		/* Wait for the transfer to complete (stop). */
    481 		deadline = getticks() +
    482 		    /*timeout*/ hz / 10 + 10 * (cmdlen + buflen);
    483 		mutex_enter(&sc->sc_mutex);
    484 		while (sc->sc_stage != FIREI2C_STAGE_STOP) {
    485 			rem = deadline - getticks();
    486 			if (!rem || rem >= INT_MAX) {
    487 				printf("%s: intr timeout\n",
    488 				    device_xname(sc->sc_dev));
    489 				sc->sc_stage = FIREI2C_STAGE_STOP;
    490 				err = sc->sc_err | 1;
    491 				break;
    492 			}
    493 			cv_timedwait(&sc->sc_cv, &sc->sc_mutex, rem);
    494 		}
    495 		mutex_exit(&sc->sc_mutex);
    496 		err = sc->sc_err;
    497 		goto stop;
    498 	}
    499 
    500 	/*
    501 	 * If we are writing, write addr, cmd, buf.
    502 	 * If we are reading, either:
    503 	 *   write addr, cmd, repeat-start, then read addr to buf, or:
    504 	 *   read addr to buf.
    505 	 * Send stop
    506 	 */
    507 	err = firei2c_wait(sc, flags);
    508 	val = firei2c_reg_read(sc, FIREI2C_STAT);
    509 	if (err) {
    510 		printf("%s: start timeout 0x%x\n",
    511 		    device_xname(sc->sc_dev), val);
    512 		goto stop;
    513 	}
    514 	if (val != FIREI2C_STAT_STA) {
    515 		printf("%s: start error 0x%x\n",
    516 		    device_xname(sc->sc_dev), val);
    517 		err = 1;
    518 		goto stop;
    519 	}
    520 
    521 	/* Address + r/w in data, then send ctrl */
    522 	val = addr << FIREI2C_DATA_SHIFT;
    523 	if (I2C_OP_WRITE_P(op) || cmdlen > 0) {
    524 		ack = FIREI2C_STAT_AWR_ACK;
    525 		nack = FIREI2C_STAT_AWR_NAK;
    526 	} else {
    527 		val |= 0x01;
    528 		ack = FIREI2C_STAT_ARE_ACK;
    529 		nack = FIREI2C_STAT_ARE_NAK;
    530 	}
    531 	firei2c_reg_write(sc, FIREI2C_DATA, val);
    532 	firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    533 	err = firei2c_wait(sc, flags);
    534 	val = firei2c_reg_read(sc, FIREI2C_STAT);
    535 	if (err) {
    536 		printf("%s: addr timeout 0x%x\n",
    537 		    device_xname(sc->sc_dev), val);
    538 		goto stop;
    539 	}
    540 	if (val != ack) {
    541 		if (val != nack)	/* Don't print for NACK */
    542 			printf("%s: addr error 0x%x\n",
    543 			    device_xname(sc->sc_dev), val);
    544 		err = 1;
    545 		goto stop;
    546 	}
    547 
    548 	err = 0;
    549 	if (I2C_OP_READ_P(op)) {
    550 		if (cmdlen > 0) {
    551 			/* Write register */
    552 			err = firei2c_write(sc, cmd, cmdlen,
    553 			    NULL, 0, flags);
    554 			if (err)
    555 				goto stop;
    556 
    557 			/* Send repeat start */
    558 			firei2c_reg_write(sc, FIREI2C_CTRL,
    559 			    ctrl | FIREI2C_CTRL_STA);
    560 			err = firei2c_wait(sc, flags);
    561 			val = firei2c_reg_read(sc, FIREI2C_STAT);
    562 			if (err) {
    563 				printf("%s: repeat start timeout 0x%x\n",
    564 				    device_xname(sc->sc_dev), val);
    565 				goto stop;
    566 			}
    567 			if (val != FIREI2C_STAT_REPSTA) {
    568 				printf("%s: repeat start error 0x%x\n",
    569 				    device_xname(sc->sc_dev), val);
    570 				err = 1;
    571 				goto stop;
    572 			}
    573 
    574 			/* Address + r in data, then send ctrl */
    575 			val = addr << FIREI2C_DATA_SHIFT;
    576 			val |= 0x01;
    577 			ack = FIREI2C_STAT_ARE_ACK;
    578 			nack = FIREI2C_STAT_ARE_NAK;
    579 			firei2c_reg_write(sc, FIREI2C_DATA, val);
    580 			firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    581 			err = firei2c_wait(sc, flags);
    582 			val = firei2c_reg_read(sc, FIREI2C_STAT);
    583 			if (err) {
    584 				printf("%s: addr timeout 0x%x\n",
    585 				    device_xname(sc->sc_dev), val);
    586 				goto stop;
    587 			}
    588 			if (val != ack) {
    589 				if (val != nack)
    590 					printf("%s: addr error 0x%x\n",
    591 					    device_xname(sc->sc_dev), val);
    592 				err = 1;
    593 				goto stop;
    594 			}
    595 		}
    596 
    597 		/* Read data */
    598 		err = firei2c_read(sc, buf, buflen, flags);
    599 	} else
    600 		/* Write data or register + data */
    601 		err = firei2c_write(sc, cmd, cmdlen, buf, buflen, flags);
    602 
    603 stop:
    604 	err |= firei2c_stop(sc);
    605 
    606 	return err;
    607 }
    608 
    609 static int
    610 firei2c_write(struct firei2c_softc *sc, const uint8_t *cmd, size_t cmdlen,
    611     uint8_t *buf, size_t buflen, int flags)
    612 {
    613 	uint8_t ctrl, val;
    614 	int i, err;
    615 
    616 	DPRINTF(2)("%s: write %ld\n",
    617 	    device_xname(sc->sc_dev), cmdlen + buflen);
    618 	ctrl = FIREI2C_CTRL_ENAB;
    619 	for (i = 0; i < cmdlen + buflen; i++) {
    620 		/* Bytes in data, then send ctrl */
    621 		if (i < cmdlen)
    622 			val = cmd[i];
    623 		else
    624 			val = buf[i - cmdlen];
    625 		firei2c_reg_write(sc, FIREI2C_DATA, val);
    626 		firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    627 		err = firei2c_wait(sc, flags);
    628 		val = firei2c_reg_read(sc, FIREI2C_STAT);
    629 		if (err) {
    630 			printf("%s: write timeout 0x%x\n",
    631 			    device_xname(sc->sc_dev), val);
    632 			return 1;
    633 		}
    634 		if (val != FIREI2C_STAT_DAT_ACK) {
    635 			if (val != FIREI2C_STAT_DAT_NAK)
    636 				printf("%s: write error 0x%x\n",
    637 				    device_xname(sc->sc_dev), val);
    638 			return 1;
    639 		}
    640 
    641 	}
    642 	return 0;
    643 }
    644 
    645 static int
    646 firei2c_read(struct firei2c_softc *sc, uint8_t *buf, size_t buflen, int flags)
    647 {
    648 	uint8_t ctrl, val, ack;
    649 	int i, err;
    650 
    651 	DPRINTF(2)("%s: read %ld\n", device_xname(sc->sc_dev), buflen);
    652 	for (i = 0; i < buflen; i++) {
    653 		/* Send ACK on all but last byte */
    654 		if (i < buflen - 1) {
    655 			ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_AAK;
    656 			ack = FIREI2C_STAT_MDAT_ACK;
    657 		} else {
    658 			ctrl = FIREI2C_CTRL_ENAB;
    659 			ack = FIREI2C_STAT_MDAT_NAK;
    660 		}
    661 		/* Send ctrl, then bytes in data */
    662 		firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    663 		err = firei2c_wait(sc, flags);
    664 		val = firei2c_reg_read(sc, FIREI2C_STAT);
    665 		if (err) {
    666 			printf("%s: read timeout 0x%x\n",
    667 			    device_xname(sc->sc_dev), val);
    668 			return 1;
    669 		}
    670 		if (val != ack) {
    671 			printf("%s: read error 0x%x\n",
    672 			    device_xname(sc->sc_dev), val);
    673 			return 1;
    674 		}
    675 		buf[i] = firei2c_reg_read(sc, FIREI2C_DATA);
    676 	}
    677 	return 0;
    678 }
    679 
    680 /*
    681  * When we receive an interrupt, check the status versus the step
    682  * and set up the next stage.
    683  * See the comments before firei2c_exec() for the list of steps.
    684  */
    685 int
    686 firei2c_intr(void *arg)
    687 {
    688 	struct firei2c_softc *sc = arg;
    689 	uint8_t ctrl, val;
    690 
    691 	mutex_enter(&sc->sc_mutex);
    692 	ctrl = firei2c_reg_read(sc, FIREI2C_CTRL);
    693 	if (ctrl & FIREI2C_CTRL_IFLG) {
    694 		/* Disable interrupts */
    695 		firei2c_reg_write(sc, FIREI2C_CTRL, ctrl & ~FIREI2C_CTRL_IEN);
    696 	}
    697 
    698 	if (sc->sc_stage == FIREI2C_STAGE_IDLE) {
    699 		DPRINTF(1)("%s: intr and idle\n", device_xname(sc->sc_dev));
    700 		mutex_exit(&sc->sc_mutex);
    701 		return 0;
    702 	}
    703 
    704 	ctrl = FIREI2C_CTRL_ENAB | FIREI2C_CTRL_IEN;
    705 	val = firei2c_reg_read(sc, FIREI2C_STAT);
    706 
    707 	switch (sc->sc_stage) {
    708 	case FIREI2C_STAGE_START:
    709 		DPRINTF(2)("%s: intr start, op %x\n",
    710 		    device_xname(sc->sc_dev), sc->sc_op);
    711 		if (val != FIREI2C_STAT_STA) {
    712 			printf("%s: intr start error 0x%02x\n",
    713 			    device_xname(sc->sc_dev), val);
    714 			sc->sc_err = 1;
    715 			sc->sc_stage = FIREI2C_STAGE_STOP;
    716 			break;
    717 		}
    718 
    719 		/* Address + r/w in data, then send ctrl */
    720 		val = sc->sc_target << FIREI2C_DATA_SHIFT;
    721 		if (sc->sc_op == FIREI2C_OP_READ) {
    722 			val |= 0x01;
    723 			sc->sc_stage = FIREI2C_STAGE_RE_ADDR;
    724 		} else
    725 			sc->sc_stage = FIREI2C_STAGE_WR_ADDR;
    726 		firei2c_reg_write(sc, FIREI2C_DATA, val);
    727 		firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    728 		break;
    729 
    730 	case FIREI2C_STAGE_WR_ADDR:
    731 		DPRINTF(2)("%s: intr addr(w) 0x%02x = 0x%02x\n",
    732 		    device_xname(sc->sc_dev), sc->sc_target, val);
    733 		if (val != FIREI2C_STAT_AWR_ACK) {
    734 			if (val != FIREI2C_STAT_AWR_NAK)
    735 				printf("%s: intr addr(w) error 0x%02x\n",
    736 				    device_xname(sc->sc_dev), val);
    737 			sc->sc_err = 1;
    738 			sc->sc_stage = FIREI2C_STAGE_STOP;
    739 			break;
    740 		}
    741 
    742 		sc->sc_stage = FIREI2C_STAGE_WRITE;
    743 		val = FIREI2C_STAT_DAT_ACK;	/* For write */
    744 		/* Fallthrough */
    745 
    746 	case FIREI2C_STAGE_WRITE:
    747 		DPRINTF(2)("%s: intr write 0x%02x = 0x%02x\n",
    748 		    device_xname(sc->sc_dev), sc->sc_target, val);
    749 		if (val != FIREI2C_STAT_DAT_ACK) {
    750 			if (val != FIREI2C_STAT_DAT_NAK)
    751 				printf("%s: intr write error 0x%02x\n",
    752 				    device_xname(sc->sc_dev), val);
    753 			sc->sc_err = 1;
    754 			sc->sc_stage = FIREI2C_STAGE_STOP;
    755 			break;
    756 		}
    757 
    758 		/* Start the write from cmd */
    759 		if (sc->sc_i < sc->sc_cmdlen) {
    760 			firei2c_reg_write(sc, FIREI2C_DATA,
    761 			    sc->sc_cmdbuf[sc->sc_i]);
    762 			firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    763 			sc->sc_i++;
    764 			break;
    765 		}
    766 
    767 		/* If a read OP, switch with repeat start after writing cmd */
    768 		if (sc->sc_op == FIREI2C_OP_WR_RD) {
    769 			sc->sc_i = 0;
    770 			sc->sc_stage = FIREI2C_STAGE_REPSTART;
    771 			ctrl |= FIREI2C_CTRL_STA;
    772 			firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    773 			break;
    774 		}
    775 
    776 		/* If a write OP, continue the write, now from buf */
    777 		if (sc->sc_i < sc->sc_cmdlen + sc->sc_buflen) {
    778 			firei2c_reg_write(sc, FIREI2C_DATA,
    779 			    sc->sc_buf[sc->sc_i - sc->sc_cmdlen]);
    780 			firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    781 			sc->sc_i++;
    782 		} else {
    783 			sc->sc_stage = FIREI2C_STAGE_STOP;
    784 		}
    785 		break;
    786 
    787 	case FIREI2C_STAGE_REPSTART:
    788 		DPRINTF(2)("%s: intr repstart 0x%02x = 0x%02x\n",
    789 		    device_xname(sc->sc_dev), sc->sc_target, val);
    790 		if (val != FIREI2C_STAT_REPSTA) {
    791 			printf("%s: intr repstart error 0x%02x\n",
    792 			    device_xname(sc->sc_dev), val);
    793 			sc->sc_err = 1;
    794 			sc->sc_stage = FIREI2C_STAGE_STOP;
    795 			break;
    796 		}
    797 
    798 		/* Address + r in data, then send ctrl */
    799 		val = (sc->sc_target << FIREI2C_DATA_SHIFT) | 0x01;
    800 		sc->sc_stage = FIREI2C_STAGE_RE_ADDR;
    801 		firei2c_reg_write(sc, FIREI2C_DATA, val);
    802 		firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    803 		break;
    804 
    805 	case FIREI2C_STAGE_RE_ADDR:
    806 		DPRINTF(2)("%s: intr addr(r) 0x%02x = 0x%02x\n",
    807 		    device_xname(sc->sc_dev), sc->sc_target, val);
    808 		if (val != FIREI2C_STAT_ARE_ACK) {
    809 			if (val != FIREI2C_STAT_ARE_NAK)
    810 				printf("%s: intr addr(r) error 0x%02x\n",
    811 				    device_xname(sc->sc_dev), val);
    812 			sc->sc_err = 1;
    813 			sc->sc_stage = FIREI2C_STAGE_STOP;
    814 			break;
    815 		}
    816 
    817 		sc->sc_stage = FIREI2C_STAGE_READ;
    818 		val = FIREI2C_STAT_MDAT_NAK;	/* For read */
    819 		/* Fallthrough */
    820 
    821 	case FIREI2C_STAGE_READ:
    822 		DPRINTF(2)("%s: intr read 0x%02x = 0x%02x\n",
    823 		    device_xname(sc->sc_dev), sc->sc_target, val);
    824 		if (sc->sc_i > 0 && sc->sc_i < sc->sc_buflen) {
    825 			if (val != FIREI2C_STAT_MDAT_ACK) {
    826 				printf("%s: intr read error 0x%02x\n",
    827 				    device_xname(sc->sc_dev), val);
    828 				sc->sc_err = 1;
    829 				sc->sc_stage = FIREI2C_STAGE_STOP;
    830 				break;
    831 			}
    832 		} else {
    833 			if (val != FIREI2C_STAT_MDAT_NAK) {
    834 				printf("%s: intr read error 0x%02x\n",
    835 				    device_xname(sc->sc_dev), val);
    836 				sc->sc_err = 1;
    837 				sc->sc_stage = FIREI2C_STAGE_STOP;
    838 				break;
    839 			}
    840 		}
    841 
    842 		/* Data read is 1 cycle behind ctrl  */
    843 		if (sc->sc_i > 0 && sc->sc_i <= sc->sc_buflen) {
    844 			sc->sc_buf[sc->sc_i - 1] =
    845 			   firei2c_reg_read(sc, FIREI2C_DATA);
    846 		}
    847 
    848 		if (sc->sc_i == sc->sc_buflen) {
    849 			/* Last data was read */
    850 			sc->sc_stage = FIREI2C_STAGE_STOP;
    851 		} else {
    852 			/* Send ACK on all but last byte */
    853 			if (sc->sc_i < sc->sc_buflen - 1)
    854 				ctrl |= FIREI2C_CTRL_AAK;
    855 			firei2c_reg_write(sc, FIREI2C_CTRL, ctrl);
    856 			sc->sc_i++;
    857 		}
    858 		break;
    859 	}
    860 
    861 	if (sc->sc_stage == FIREI2C_STAGE_STOP) {
    862 		DPRINTF(2)("%s: intr stop (err=%d)\n",
    863 		    device_xname(sc->sc_dev), sc->sc_err);
    864 		cv_signal(&sc->sc_cv);
    865 	}
    866 
    867 	mutex_exit(&sc->sc_mutex);
    868 
    869 	return 1;
    870 
    871 }
    872 
    873 static uint8_t
    874 firei2c_reg_read(struct firei2c_softc *sc, bus_size_t reg)
    875 {
    876 	uint32_t val;
    877 	bus_space_barrier(sc->sc_bustag, sc->sc_regh, reg, 8,
    878 	    BUS_SPACE_BARRIER_READ);
    879 	val = bus_space_read_8(sc->sc_bustag, sc->sc_regh, reg);
    880 	return val & 0xff;
    881 }
    882 
    883 static void
    884 firei2c_reg_write(struct firei2c_softc *sc, bus_size_t reg, uint8_t val)
    885 {
    886 	bus_space_write_8(sc->sc_bustag, sc->sc_regh, reg, val);
    887 	bus_space_barrier(sc->sc_bustag, sc->sc_regh, reg, 8,
    888 	    BUS_SPACE_BARRIER_WRITE);
    889 }
    890