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