Home | History | Annotate | Line # | Download | only in ic
      1 /* $NetBSD: dwiic.c,v 1.11 2025/09/15 15:18:42 thorpej Exp $ */
      2 
      3 /* $OpenBSD: dwiic.c,v 1.4 2018/05/23 22:08:00 kettenis Exp $ */
      4 
      5 /*-
      6  * Copyright (c) 2017 The NetBSD Foundation, Inc.
      7  * All rights reserved.
      8  *
      9  * This code is derived from software contributed to The NetBSD Foundation
     10  * by Manuel Bouyer.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 /*
     34  * Synopsys DesignWare I2C controller
     35  *
     36  * Copyright (c) 2015, 2016 joshua stein <jcs (at) openbsd.org>
     37  *
     38  * Permission to use, copy, modify, and/or distribute this software for any
     39  * purpose with or without fee is hereby granted, provided that the above
     40  * copyright notice and this permission notice appear in all copies.
     41  *
     42  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     43  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     44  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     45  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     46  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     47  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     48  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     49  */
     50 
     51 #include <sys/cdefs.h>
     52 __KERNEL_RCSID(0, "$NetBSD: dwiic.c,v 1.11 2025/09/15 15:18:42 thorpej Exp $");
     53 
     54 #include <sys/param.h>
     55 
     56 #include <sys/atomic.h>
     57 #include <sys/bus.h>
     58 #include <sys/device.h>
     59 #include <sys/kernel.h>
     60 #include <sys/systm.h>
     61 
     62 #include <dev/ic/dwiic_var.h>
     63 
     64 //#define DWIIC_DEBUG
     65 
     66 #ifdef DWIIC_DEBUG
     67 #define DPRINTF(x) printf x
     68 #else
     69 #define DPRINTF(x)
     70 #endif
     71 
     72 /* register offsets */
     73 #define DW_IC_CON		0x0
     74 #define DW_IC_TAR		0x4
     75 #define DW_IC_DATA_CMD		0x10
     76 #define DW_IC_SS_SCL_HCNT	0x14
     77 #define DW_IC_SS_SCL_LCNT	0x18
     78 #define DW_IC_FS_SCL_HCNT	0x1c
     79 #define DW_IC_FS_SCL_LCNT	0x20
     80 #define DW_IC_INTR_STAT		0x2c
     81 #define DW_IC_INTR_MASK		0x30
     82 #define DW_IC_RAW_INTR_STAT	0x34
     83 #define DW_IC_RX_TL		0x38
     84 #define DW_IC_TX_TL		0x3c
     85 #define DW_IC_CLR_INTR		0x40
     86 #define DW_IC_CLR_RX_UNDER	0x44
     87 #define DW_IC_CLR_RX_OVER	0x48
     88 #define DW_IC_CLR_TX_OVER	0x4c
     89 #define DW_IC_CLR_RD_REQ	0x50
     90 #define DW_IC_CLR_TX_ABRT	0x54
     91 #define DW_IC_CLR_RX_DONE	0x58
     92 #define DW_IC_CLR_ACTIVITY	0x5c
     93 #define DW_IC_CLR_STOP_DET	0x60
     94 #define DW_IC_CLR_START_DET	0x64
     95 #define DW_IC_CLR_GEN_CALL	0x68
     96 #define DW_IC_ENABLE		0x6c
     97 #define DW_IC_STATUS		0x70
     98 #define DW_IC_TXFLR		0x74
     99 #define DW_IC_RXFLR		0x78
    100 #define DW_IC_SDA_HOLD		0x7c
    101 #define DW_IC_TX_ABRT_SOURCE	0x80
    102 #define DW_IC_ENABLE_STATUS	0x9c
    103 #define DW_IC_COMP_PARAM_1	0xf4
    104 #define DW_IC_COMP_VERSION	0xf8
    105 #define DW_IC_SDA_HOLD_MIN_VERS	0x3131312A
    106 #define DW_IC_COMP_TYPE		0xfc
    107 #define DW_IC_COMP_TYPE_VALUE	0x44570140
    108 
    109 #define DW_IC_CON_MASTER	0x1
    110 #define DW_IC_CON_SPEED_STD	0x2
    111 #define DW_IC_CON_SPEED_FAST	0x4
    112 #define DW_IC_CON_10BITADDR_MASTER 0x10
    113 #define DW_IC_CON_RESTART_EN	0x20
    114 #define DW_IC_CON_SLAVE_DISABLE	0x40
    115 
    116 #define DW_IC_DATA_CMD_READ	0x100
    117 #define DW_IC_DATA_CMD_STOP	0x200
    118 #define DW_IC_DATA_CMD_RESTART	0x400
    119 
    120 #define DW_IC_INTR_RX_UNDER	0x001
    121 #define DW_IC_INTR_RX_OVER	0x002
    122 #define DW_IC_INTR_RX_FULL	0x004
    123 #define DW_IC_INTR_TX_OVER	0x008
    124 #define DW_IC_INTR_TX_EMPTY	0x010
    125 #define DW_IC_INTR_RD_REQ	0x020
    126 #define DW_IC_INTR_TX_ABRT	0x040
    127 #define DW_IC_INTR_RX_DONE	0x080
    128 #define DW_IC_INTR_ACTIVITY	0x100
    129 #define DW_IC_INTR_STOP_DET	0x200
    130 #define DW_IC_INTR_START_DET	0x400
    131 #define DW_IC_INTR_GEN_CALL	0x800
    132 
    133 #define DW_IC_STATUS_ACTIVITY	0x1
    134 
    135 /* hardware abort codes from the DW_IC_TX_ABRT_SOURCE register */
    136 #define ABRT_7B_ADDR_NOACK	0
    137 #define ABRT_10ADDR1_NOACK	1
    138 #define ABRT_10ADDR2_NOACK	2
    139 #define ABRT_TXDATA_NOACK	3
    140 #define ABRT_GCALL_NOACK	4
    141 #define ABRT_GCALL_READ		5
    142 #define ABRT_SBYTE_ACKDET	7
    143 #define ABRT_SBYTE_NORSTRT	9
    144 #define ABRT_10B_RD_NORSTRT	10
    145 #define ABRT_MASTER_DIS		11
    146 #define ARB_LOST		12
    147 
    148 static int	dwiic_init(struct dwiic_softc *);
    149 static void	dwiic_enable(struct dwiic_softc *, bool);
    150 static uint32_t	dwiic_read(struct dwiic_softc *, int);
    151 static void	dwiic_write(struct dwiic_softc *, int, uint32_t);
    152 static int	dwiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
    153 		    size_t, void *, size_t, int);
    154 
    155 bool
    156 dwiic_attach(struct dwiic_softc *sc)
    157 {
    158 	if (sc->sc_power != NULL) {
    159 		if (!sc->sc_power(sc, 1)) {
    160 			aprint_error_dev(sc->sc_dev, "failed to power up\n");
    161 			return 0;
    162 		}
    163 	}
    164 
    165 	/* fetch timing parameters */
    166 	if (sc->ss_hcnt == 0)
    167 		sc->ss_hcnt = dwiic_read(sc, DW_IC_SS_SCL_HCNT);
    168 	if (sc->ss_lcnt == 0)
    169 		sc->ss_lcnt = dwiic_read(sc, DW_IC_SS_SCL_LCNT);
    170 	if (sc->fs_hcnt == 0)
    171 		sc->fs_hcnt = dwiic_read(sc, DW_IC_FS_SCL_HCNT);
    172 	if (sc->fs_lcnt == 0)
    173 		sc->fs_lcnt = dwiic_read(sc, DW_IC_FS_SCL_LCNT);
    174 	if (sc->sda_hold_time == 0)
    175 		sc->sda_hold_time = dwiic_read(sc, DW_IC_SDA_HOLD);
    176 
    177 	if (dwiic_init(sc)) {
    178 		aprint_error_dev(sc->sc_dev, "failed initializing\n");
    179 		return 0;
    180 	}
    181 
    182 	/* leave the controller disabled */
    183 	dwiic_write(sc, DW_IC_INTR_MASK, 0);
    184 	dwiic_enable(sc, 0);
    185 	dwiic_read(sc, DW_IC_CLR_INTR);
    186 
    187 	mutex_init(&sc->sc_int_lock, MUTEX_DEFAULT, IPL_VM);
    188 	cv_init(&sc->sc_int_readwait, "dwiicr");
    189 	cv_init(&sc->sc_int_writewait, "dwiicw");
    190 	cv_init(&sc->sc_int_stopwait, "dwiics");
    191 
    192 	/* setup and attach iic bus */
    193 	iic_tag_init(&sc->sc_i2c_tag);
    194 	sc->sc_i2c_tag.ic_cookie = sc;
    195 	sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
    196 
    197 	/* config_found for "i2cbus" is done in the bus-attachment glue */
    198 
    199 	atomic_store_release(&sc->sc_attached, true);
    200 
    201 	return 1;
    202 }
    203 
    204 int
    205 dwiic_detach(device_t self, int flags)
    206 {
    207 	struct dwiic_softc *sc = device_private(self);
    208 
    209 	dwiic_enable(sc, 0);
    210 	if (sc->sc_ih != NULL) {
    211 		intr_disestablish(sc->sc_ih);
    212 		sc->sc_ih = NULL;
    213 	}
    214 
    215 	return 0;
    216 }
    217 
    218 bool
    219 dwiic_suspend(device_t self, const pmf_qual_t *qual)
    220 {
    221 	struct dwiic_softc *sc = device_private(self);
    222 
    223 	/* disable controller */
    224 	dwiic_enable(sc, 0);
    225 
    226 	/* disable interrupts */
    227 	dwiic_write(sc, DW_IC_INTR_MASK, 0);
    228 	dwiic_read(sc, DW_IC_CLR_INTR);
    229 	if (sc->sc_power != NULL) {
    230 		if (!sc->sc_power(sc, 0)) {
    231 			device_printf(sc->sc_dev, "failed to power off\n");
    232 		}
    233 	}
    234 	return true;
    235 }
    236 
    237 bool
    238 dwiic_resume(device_t self, const pmf_qual_t *qual)
    239 {
    240 	struct dwiic_softc *sc = device_private(self);
    241 	if (sc->sc_power != NULL) {
    242 		if (!sc->sc_power(sc, 1)) {
    243 			device_printf(sc->sc_dev, "failed to power up\n");
    244 			return false;
    245 		}
    246 	}
    247 	dwiic_init(sc);
    248 	return true;
    249 }
    250 
    251 static uint32_t
    252 dwiic_read(struct dwiic_softc *sc, int offset)
    253 {
    254 	u_int32_t b = bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
    255 
    256 	DPRINTF(("%s: read at 0x%x = 0x%x\n", device_xname(sc->sc_dev), offset, b));
    257 
    258 	return b;
    259 }
    260 
    261 static void
    262 dwiic_write(struct dwiic_softc *sc, int offset, uint32_t val)
    263 {
    264 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val);
    265 
    266 	DPRINTF(("%s: write at 0x%x: 0x%x\n", device_xname(sc->sc_dev), offset,
    267 	    val));
    268 }
    269 
    270 static int
    271 dwiic_init(struct dwiic_softc *sc)
    272 {
    273 	uint32_t reg;
    274 
    275 	/* make sure we're talking to a device we know */
    276 	reg = dwiic_read(sc, DW_IC_COMP_TYPE);
    277 	if (reg != DW_IC_COMP_TYPE_VALUE) {
    278 		DPRINTF(("%s: invalid component type 0x%x\n",
    279 		    device_xname(sc->sc_dev), reg));
    280 		return 1;
    281 	}
    282 
    283 	/* disable the adapter */
    284 	dwiic_enable(sc, 0);
    285 
    286 	/* write standard-mode SCL timing parameters */
    287 	dwiic_write(sc, DW_IC_SS_SCL_HCNT, sc->ss_hcnt);
    288 	dwiic_write(sc, DW_IC_SS_SCL_LCNT, sc->ss_lcnt);
    289 
    290 	/* and fast-mode SCL timing parameters */
    291 	dwiic_write(sc, DW_IC_FS_SCL_HCNT, sc->fs_hcnt);
    292 	dwiic_write(sc, DW_IC_FS_SCL_LCNT, sc->fs_lcnt);
    293 
    294 	/* SDA hold time */
    295 	reg = dwiic_read(sc, DW_IC_COMP_VERSION);
    296 	if (reg >= DW_IC_SDA_HOLD_MIN_VERS)
    297 		dwiic_write(sc, DW_IC_SDA_HOLD, sc->sda_hold_time);
    298 
    299 	/* FIFO threshold levels */
    300 	sc->tx_fifo_depth = 32;
    301 	sc->rx_fifo_depth = 32;
    302 	dwiic_write(sc, DW_IC_TX_TL, sc->tx_fifo_depth / 2);
    303 	dwiic_write(sc, DW_IC_RX_TL, 0);
    304 
    305 	/* configure as i2c master with fast speed */
    306 	sc->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
    307 	    DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
    308 	dwiic_write(sc, DW_IC_CON, sc->master_cfg);
    309 
    310 	return 0;
    311 }
    312 
    313 static void
    314 dwiic_enable(struct dwiic_softc *sc, bool enable)
    315 {
    316 	int retries;
    317 
    318 	for (retries = 100; retries > 0; retries--) {
    319 		dwiic_write(sc, DW_IC_ENABLE, enable);
    320 		if ((dwiic_read(sc, DW_IC_ENABLE_STATUS) & 1) == enable)
    321 			return;
    322 
    323 		DELAY(25);
    324 	}
    325 
    326 	device_printf(sc->sc_dev, "failed to %sable\n",
    327 	    (enable ? "en" : "dis"));
    328 }
    329 
    330 static int
    331 dwiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
    332     size_t cmdlen, void *buf, size_t len, int flags)
    333 {
    334 	struct dwiic_softc *sc = cookie;
    335 	u_int32_t ic_con, st, cmd, resp;
    336 	int retries, tx_limit, rx_avail, x, readpos;
    337 	const uint8_t *bcmd;
    338 	uint8_t *bdata;
    339 
    340 	if (sc->sc_poll)
    341 		flags |= I2C_F_POLL;
    342 
    343 	DPRINTF(("%s: %s: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
    344 	    "flags 0x%02x\n", device_xname(sc->sc_dev), __func__, op, addr, cmdlen,
    345 	    len, flags));
    346 
    347 	/* setup transfer */
    348 	sc->sc_i2c_xfer.op = op;
    349 	sc->sc_i2c_xfer.buf = buf;
    350 	sc->sc_i2c_xfer.len = len;
    351 	sc->sc_i2c_xfer.flags = flags;
    352 	sc->sc_i2c_xfer.error = 0;
    353 
    354 	/* wait for bus to be idle */
    355 	for (retries = 100; retries > 0; retries--) {
    356 		st = dwiic_read(sc, DW_IC_STATUS);
    357 		if (!(st & DW_IC_STATUS_ACTIVITY))
    358 			break;
    359 		DELAY(1000);
    360 	}
    361 	DPRINTF(("%s: %s: status 0x%x\n", device_xname(sc->sc_dev), __func__, st));
    362 	if (st & DW_IC_STATUS_ACTIVITY) {
    363 		return (1);
    364 	}
    365 
    366 	/* disable controller */
    367 	dwiic_enable(sc, 0);
    368 
    369 	/* set slave address */
    370 	ic_con = dwiic_read(sc, DW_IC_CON);
    371 	ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
    372 	dwiic_write(sc, DW_IC_CON, ic_con);
    373 	dwiic_write(sc, DW_IC_TAR, addr);
    374 
    375 	/* disable interrupts */
    376 	dwiic_write(sc, DW_IC_INTR_MASK, 0);
    377 	dwiic_read(sc, DW_IC_CLR_INTR);
    378 
    379 	/* enable controller */
    380 	dwiic_enable(sc, 1);
    381 
    382 	/* wait until the controller is ready for commands */
    383 	if (flags & I2C_F_POLL)
    384 		DELAY(200);
    385 	else {
    386 		mutex_enter(&sc->sc_int_lock);
    387 		dwiic_read(sc, DW_IC_CLR_INTR);
    388 		dwiic_write(sc, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY);
    389 
    390 		if (cv_timedwait(&sc->sc_int_writewait,
    391 		    &sc->sc_int_lock, hz / 2) != 0)
    392 			device_printf(sc->sc_dev,
    393 			    "timed out waiting for tx_empty intr\n");
    394 		dwiic_write(sc, DW_IC_INTR_MASK, 0);
    395 		dwiic_read(sc, DW_IC_CLR_INTR);
    396 		mutex_exit(&sc->sc_int_lock);
    397 	}
    398 
    399 	/* send our command, one byte at a time */
    400 	if (cmdlen > 0) {
    401 		bcmd = (const void *)cmdbuf;
    402 
    403 		DPRINTF(("%s: %s: sending cmd (len %zu):", device_xname(sc->sc_dev),
    404 		    __func__, cmdlen));
    405 		for (x = 0; x < cmdlen; x++)
    406 			DPRINTF((" %02x", bcmd[x]));
    407 		DPRINTF(("\n"));
    408 
    409 		tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
    410 		if (cmdlen > tx_limit) {
    411 			/* TODO */
    412 			device_printf(sc->sc_dev, "can't write %zu (> %d)\n",
    413 			    cmdlen, tx_limit);
    414 			sc->sc_i2c_xfer.error = 1;
    415 			return (1);
    416 		}
    417 
    418 		for (x = 0; x < cmdlen; x++) {
    419 			cmd = bcmd[x];
    420 			/*
    421 			 * Generate STOP condition if this is the last
    422 			 * byte of the transfer.
    423 			 */
    424 			if (x == (cmdlen - 1) && len == 0 && I2C_OP_STOP_P(op))
    425 				cmd |= DW_IC_DATA_CMD_STOP;
    426 			dwiic_write(sc, DW_IC_DATA_CMD, cmd);
    427 		}
    428 	}
    429 
    430 	bdata = (void *)buf;
    431 	x = readpos = 0;
    432 	tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
    433 
    434 	DPRINTF(("%s: %s: need to read %zu bytes, can send %d read reqs\n",
    435 		device_xname(sc->sc_dev), __func__, len, tx_limit));
    436 
    437 	while (x < len) {
    438 		if (I2C_OP_WRITE_P(op))
    439 			cmd = bdata[x];
    440 		else
    441 			cmd = DW_IC_DATA_CMD_READ;
    442 
    443 		/*
    444 		 * Generate RESTART condition if we're reversing
    445 		 * direction.
    446 		 */
    447 		if (x == 0 && cmdlen > 0 && I2C_OP_READ_P(op))
    448 			cmd |= DW_IC_DATA_CMD_RESTART;
    449 		/*
    450 		 * Generate STOP condition on the last byte of the
    451 		 * transfer.
    452 		 */
    453 		if (x == (len - 1) && I2C_OP_STOP_P(op))
    454 			cmd |= DW_IC_DATA_CMD_STOP;
    455 
    456 		dwiic_write(sc, DW_IC_DATA_CMD, cmd);
    457 
    458 		tx_limit--;
    459 		x++;
    460 
    461 		/*
    462 		 * As TXFLR fills up, we need to clear it out by reading all
    463 		 * available data.
    464 		 */
    465 		while (I2C_OP_READ_P(op) && (tx_limit == 0 || x == len)) {
    466 			DPRINTF(("%s: %s: tx_limit %d, sent %d read reqs\n",
    467 			    device_xname(sc->sc_dev), __func__, tx_limit, x));
    468 
    469 			if (flags & I2C_F_POLL) {
    470 				for (retries = 100; retries > 0; retries--) {
    471 					rx_avail = dwiic_read(sc, DW_IC_RXFLR);
    472 					if (rx_avail > 0)
    473 						break;
    474 					DELAY(50);
    475 				}
    476 			} else {
    477 				mutex_enter(&sc->sc_int_lock);
    478 				dwiic_read(sc, DW_IC_CLR_INTR);
    479 				dwiic_write(sc, DW_IC_INTR_MASK,
    480 				    DW_IC_INTR_RX_FULL);
    481 
    482 				if (cv_timedwait(&sc->sc_int_readwait,
    483 				    &sc->sc_int_lock, hz / 2) != 0)
    484 					device_printf(sc->sc_dev,
    485 					    "timed out waiting for "
    486 					    "rx_full intr\n");
    487 
    488 				dwiic_write(sc, DW_IC_INTR_MASK, 0);
    489 				dwiic_read(sc, DW_IC_CLR_INTR);
    490 				mutex_exit(&sc->sc_int_lock);
    491 				rx_avail = dwiic_read(sc, DW_IC_RXFLR);
    492 			}
    493 
    494 			if (rx_avail == 0) {
    495 				device_printf(sc->sc_dev,
    496 				    "timed out reading remaining %d\n",
    497 				    (int)(len - 1 - readpos));
    498 				sc->sc_i2c_xfer.error = 1;
    499 				return (1);
    500 			}
    501 
    502 			DPRINTF(("%s: %s: %d avail to read (%zu remaining)\n",
    503 			    device_xname(sc->sc_dev), __func__, rx_avail,
    504 			    len - readpos));
    505 
    506 			while (rx_avail > 0) {
    507 				resp = dwiic_read(sc, DW_IC_DATA_CMD);
    508 				if (readpos < len) {
    509 					bdata[readpos] = resp;
    510 					readpos++;
    511 				}
    512 				rx_avail--;
    513 			}
    514 
    515 			if (readpos >= len)
    516 				break;
    517 
    518 			DPRINTF(("%s: still need to read %d bytes\n",
    519 			    device_xname(sc->sc_dev), (int)(len - readpos)));
    520 			tx_limit = sc->tx_fifo_depth -
    521 			    dwiic_read(sc, DW_IC_TXFLR);
    522 		}
    523 	}
    524 
    525 	if (I2C_OP_STOP_P(op) && I2C_OP_WRITE_P(op)) {
    526 		if (flags & I2C_F_POLL) {
    527 			/* wait for bus to be idle */
    528 			for (retries = 100; retries > 0; retries--) {
    529 				st = dwiic_read(sc, DW_IC_STATUS);
    530 				if (!(st & DW_IC_STATUS_ACTIVITY))
    531 					break;
    532 				DELAY(1000);
    533 			}
    534 			if (st & DW_IC_STATUS_ACTIVITY)
    535 				device_printf(sc->sc_dev, "timed out waiting "
    536 				    "for bus idle\n");
    537 		} else {
    538 			mutex_enter(&sc->sc_int_lock);
    539 			dwiic_read(sc, DW_IC_CLR_INTR);
    540 			dwiic_write(sc, DW_IC_INTR_MASK,
    541 			    DW_IC_INTR_STOP_DET);
    542 			if (cv_timedwait(&sc->sc_int_stopwait,
    543 			    &sc->sc_int_lock, hz / 2) != 0)
    544 				device_printf(sc->sc_dev, "timed out waiting "
    545 				    "for stop intr\n");
    546 			dwiic_write(sc, DW_IC_INTR_MASK, 0);
    547 			dwiic_read(sc, DW_IC_CLR_INTR);
    548 			mutex_exit(&sc->sc_int_lock);
    549 		}
    550 	}
    551 
    552 	return 0;
    553 }
    554 
    555 static uint32_t
    556 dwiic_read_clear_intrbits(struct dwiic_softc *sc)
    557 {
    558        uint32_t stat;
    559 
    560        stat = dwiic_read(sc, DW_IC_INTR_STAT);
    561 
    562        if (stat & DW_IC_INTR_RX_UNDER)
    563 	       dwiic_read(sc, DW_IC_CLR_RX_UNDER);
    564        if (stat & DW_IC_INTR_RX_OVER)
    565 	       dwiic_read(sc, DW_IC_CLR_RX_OVER);
    566        if (stat & DW_IC_INTR_TX_OVER)
    567 	       dwiic_read(sc, DW_IC_CLR_TX_OVER);
    568        if (stat & DW_IC_INTR_RD_REQ)
    569 	       dwiic_read(sc, DW_IC_CLR_RD_REQ);
    570        if (stat & DW_IC_INTR_TX_ABRT)
    571 	       dwiic_read(sc, DW_IC_CLR_TX_ABRT);
    572        if (stat & DW_IC_INTR_RX_DONE)
    573 	       dwiic_read(sc, DW_IC_CLR_RX_DONE);
    574        if (stat & DW_IC_INTR_ACTIVITY)
    575 	       dwiic_read(sc, DW_IC_CLR_ACTIVITY);
    576        if (stat & DW_IC_INTR_STOP_DET)
    577 	       dwiic_read(sc, DW_IC_CLR_STOP_DET);
    578        if (stat & DW_IC_INTR_START_DET)
    579 	       dwiic_read(sc, DW_IC_CLR_START_DET);
    580        if (stat & DW_IC_INTR_GEN_CALL)
    581 	       dwiic_read(sc, DW_IC_CLR_GEN_CALL);
    582 
    583        return stat;
    584 }
    585 
    586 int
    587 dwiic_intr(void *arg)
    588 {
    589 	struct dwiic_softc *sc = arg;
    590 	uint32_t en, stat;
    591 
    592 	/*
    593 	 * Give up if attach hasn't succeeded.  If it failed, nothing
    594 	 * to do here.  If it is still ongoing and simply hasn't yet
    595 	 * succeeded, interrupts from the device are masked -- so this
    596 	 * interrupt must be shared with another driver -- and any
    597 	 * interrupts applicable to us will be delivered once
    598 	 * interrupts from the device are unmasked in dwiic_i2c_exec.
    599 	 */
    600 	if (!atomic_load_acquire(&sc->sc_attached))
    601 		return 0;
    602 
    603 	en = dwiic_read(sc, DW_IC_ENABLE);
    604 	/* probably for the other controller */
    605 	if (!en)
    606 		return 0;
    607 
    608 	stat = dwiic_read_clear_intrbits(sc);
    609 	DPRINTF(("%s: %s: enabled=0x%x stat=0x%x\n", device_xname(sc->sc_dev),
    610 	    __func__, en, stat));
    611 	if (!(stat & ~DW_IC_INTR_ACTIVITY))
    612 		return 1;
    613 
    614 	if (stat & DW_IC_INTR_TX_ABRT)
    615 		sc->sc_i2c_xfer.error = 1;
    616 
    617 	if (sc->sc_i2c_xfer.flags & I2C_F_POLL)
    618 		DPRINTF(("%s: %s: intr in poll mode?\n", device_xname(sc->sc_dev),
    619 		    __func__));
    620 	else {
    621 		mutex_enter(&sc->sc_int_lock);
    622 		if (stat & DW_IC_INTR_RX_FULL) {
    623 			dwiic_write(sc, DW_IC_INTR_MASK, 0);
    624 			DPRINTF(("%s: %s: waking up reader\n",
    625 			    device_xname(sc->sc_dev), __func__));
    626 			cv_signal(&sc->sc_int_readwait);
    627 		}
    628 		if (stat & DW_IC_INTR_TX_EMPTY) {
    629 			dwiic_write(sc, DW_IC_INTR_MASK, 0);
    630 			DPRINTF(("%s: %s: waking up writer\n",
    631 			    device_xname(sc->sc_dev), __func__));
    632 			cv_signal(&sc->sc_int_writewait);
    633 		}
    634 		if (stat & DW_IC_INTR_STOP_DET) {
    635 			dwiic_write(sc, DW_IC_INTR_MASK, 0);
    636 			DPRINTF(("%s: %s: waking up stopper\n",
    637 			    device_xname(sc->sc_dev), __func__));
    638 			cv_signal(&sc->sc_int_stopwait);
    639 		}
    640 		mutex_exit(&sc->sc_int_lock);
    641 	}
    642 
    643 	return 1;
    644 }
    645