Home | History | Annotate | Line # | Download | only in ic
dwiic.c revision 1.4
      1 /* $NetBSD: dwiic.c,v 1.4 2018/09/26 18:32:51 jakllsch 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.4 2018/09/26 18:32:51 jakllsch 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 int	dwiic_i2c_acquire_bus(void *, int);
    149 static void	dwiic_i2c_release_bus(void *, int);
    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_i2c_lock, MUTEX_DEFAULT, IPL_NONE);
    188 	mutex_init(&sc->sc_int_lock, MUTEX_DEFAULT, IPL_VM);
    189 	cv_init(&sc->sc_int_readwait, "dwiicr");
    190 	cv_init(&sc->sc_int_writewait, "dwiicw");
    191 	cv_init(&sc->sc_int_stopwait, "dwiics");
    192 
    193 	/* setup and attach iic bus */
    194 	sc->sc_i2c_tag.ic_cookie = sc;
    195 	sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
    196 	sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
    197 	sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
    198 
    199 	sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
    200 
    201 	config_found_ia(sc->sc_dev, "i2cbus", &sc->sc_iba, iicbus_print);
    202 	return 1;
    203 }
    204 
    205 int
    206 dwiic_detach(device_t self, int flags)
    207 {
    208 	struct dwiic_softc *sc = device_private(self);
    209 
    210 	dwiic_enable(sc, 0);
    211 	if (sc->sc_ih != NULL) {
    212 		intr_disestablish(sc->sc_ih);
    213 		sc->sc_ih = NULL;
    214 	}
    215 
    216 	return 0;
    217 }
    218 
    219 bool
    220 dwiic_suspend(device_t self, const pmf_qual_t *qual)
    221 {
    222 	struct dwiic_softc *sc = device_private(self);
    223 
    224 	/* disable controller */
    225 	dwiic_enable(sc, 0);
    226 
    227 	/* disable interrupts */
    228 	dwiic_write(sc, DW_IC_INTR_MASK, 0);
    229 	dwiic_read(sc, DW_IC_CLR_INTR);
    230 	if (sc->sc_power != NULL) {
    231 		if (!sc->sc_power(sc, 0)) {
    232 			device_printf(sc->sc_dev, "failed to power off\n");
    233 		}
    234 	}
    235 	return true;
    236 }
    237 
    238 bool
    239 dwiic_resume(device_t self, const pmf_qual_t *qual)
    240 {
    241 	struct dwiic_softc *sc = device_private(self);
    242 	if (sc->sc_power != NULL) {
    243 		if (!sc->sc_power(sc, 1)) {
    244 			device_printf(sc->sc_dev, "failed to power up\n");
    245 			return false;
    246 		}
    247 	}
    248 	dwiic_init(sc);
    249 	return true;
    250 }
    251 
    252 static uint32_t
    253 dwiic_read(struct dwiic_softc *sc, int offset)
    254 {
    255 	u_int32_t b = bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
    256 
    257 	DPRINTF(("%s: read at 0x%x = 0x%x\n", device_xname(sc->sc_dev), offset, b));
    258 
    259 	return b;
    260 }
    261 
    262 static void
    263 dwiic_write(struct dwiic_softc *sc, int offset, uint32_t val)
    264 {
    265 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val);
    266 
    267 	DPRINTF(("%s: write at 0x%x: 0x%x\n", device_xname(sc->sc_dev), offset,
    268 	    val));
    269 }
    270 
    271 static int
    272 dwiic_i2c_acquire_bus(void *cookie, int flags)
    273 {
    274 	struct dwiic_softc *sc = cookie;
    275 
    276 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
    277 		return (0);
    278 
    279 	mutex_enter(&sc->sc_i2c_lock);
    280 	return 0;
    281 }
    282 
    283 void
    284 dwiic_i2c_release_bus(void *cookie, int flags)
    285 {
    286 	struct dwiic_softc *sc = cookie;
    287 
    288 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
    289 		return;
    290 
    291 	mutex_exit(&sc->sc_i2c_lock);
    292 }
    293 
    294 static int
    295 dwiic_init(struct dwiic_softc *sc)
    296 {
    297 	uint32_t reg;
    298 
    299 	/* make sure we're talking to a device we know */
    300 	reg = dwiic_read(sc, DW_IC_COMP_TYPE);
    301 	if (reg != DW_IC_COMP_TYPE_VALUE) {
    302 		DPRINTF(("%s: invalid component type 0x%x\n",
    303 		    device_xname(sc->sc_dev), reg));
    304 		return 1;
    305 	}
    306 
    307 	/* disable the adapter */
    308 	dwiic_enable(sc, 0);
    309 
    310 	/* write standard-mode SCL timing parameters */
    311 	dwiic_write(sc, DW_IC_SS_SCL_HCNT, sc->ss_hcnt);
    312 	dwiic_write(sc, DW_IC_SS_SCL_LCNT, sc->ss_lcnt);
    313 
    314 	/* and fast-mode SCL timing parameters */
    315 	dwiic_write(sc, DW_IC_FS_SCL_HCNT, sc->fs_hcnt);
    316 	dwiic_write(sc, DW_IC_FS_SCL_LCNT, sc->fs_lcnt);
    317 
    318 	/* SDA hold time */
    319 	reg = dwiic_read(sc, DW_IC_COMP_VERSION);
    320 	if (reg >= DW_IC_SDA_HOLD_MIN_VERS)
    321 		dwiic_write(sc, DW_IC_SDA_HOLD, sc->sda_hold_time);
    322 
    323 	/* FIFO threshold levels */
    324 	sc->tx_fifo_depth = 32;
    325 	sc->rx_fifo_depth = 32;
    326 	dwiic_write(sc, DW_IC_TX_TL, sc->tx_fifo_depth / 2);
    327 	dwiic_write(sc, DW_IC_RX_TL, 0);
    328 
    329 	/* configure as i2c master with fast speed */
    330 	sc->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
    331 	    DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
    332 	dwiic_write(sc, DW_IC_CON, sc->master_cfg);
    333 
    334 	return 0;
    335 }
    336 
    337 static void
    338 dwiic_enable(struct dwiic_softc *sc, bool enable)
    339 {
    340 	int retries;
    341 
    342 	for (retries = 100; retries > 0; retries--) {
    343 		dwiic_write(sc, DW_IC_ENABLE, enable);
    344 		if ((dwiic_read(sc, DW_IC_ENABLE_STATUS) & 1) == enable)
    345 			return;
    346 
    347 		DELAY(25);
    348 	}
    349 
    350 	device_printf(sc->sc_dev, "failed to %sable\n",
    351 	    (enable ? "en" : "dis"));
    352 }
    353 
    354 static int
    355 dwiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
    356     size_t cmdlen, void *buf, size_t len, int flags)
    357 {
    358 	struct dwiic_softc *sc = cookie;
    359 	u_int32_t ic_con, st, cmd, resp;
    360 	int retries, tx_limit, rx_avail, x, readpos;
    361 	const uint8_t *bcmd;
    362 	uint8_t *bdata;
    363 
    364 	if (cold || sc->sc_poll)
    365 		flags |= I2C_F_POLL;
    366 
    367 	DPRINTF(("%s: %s: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
    368 	    "flags 0x%02x\n", device_xname(sc->sc_dev), __func__, op, addr, cmdlen,
    369 	    len, flags));
    370 
    371 	/* setup transfer */
    372 	sc->sc_i2c_xfer.op = op;
    373 	sc->sc_i2c_xfer.buf = buf;
    374 	sc->sc_i2c_xfer.len = len;
    375 	sc->sc_i2c_xfer.flags = flags;
    376 	sc->sc_i2c_xfer.error = 0;
    377 
    378 	/* wait for bus to be idle */
    379 	for (retries = 100; retries > 0; retries--) {
    380 		st = dwiic_read(sc, DW_IC_STATUS);
    381 		if (!(st & DW_IC_STATUS_ACTIVITY))
    382 			break;
    383 		DELAY(1000);
    384 	}
    385 	DPRINTF(("%s: %s: status 0x%x\n", device_xname(sc->sc_dev), __func__, st));
    386 	if (st & DW_IC_STATUS_ACTIVITY) {
    387 		return (1);
    388 	}
    389 
    390 	/* disable controller */
    391 	dwiic_enable(sc, 0);
    392 
    393 	/* set slave address */
    394 	ic_con = dwiic_read(sc, DW_IC_CON);
    395 	ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
    396 	dwiic_write(sc, DW_IC_CON, ic_con);
    397 	dwiic_write(sc, DW_IC_TAR, addr);
    398 
    399 	/* disable interrupts */
    400 	dwiic_write(sc, DW_IC_INTR_MASK, 0);
    401 	dwiic_read(sc, DW_IC_CLR_INTR);
    402 
    403 	/* enable controller */
    404 	dwiic_enable(sc, 1);
    405 
    406 	/* wait until the controller is ready for commands */
    407 	if (flags & I2C_F_POLL)
    408 		DELAY(200);
    409 	else {
    410 		mutex_enter(&sc->sc_int_lock);
    411 		dwiic_read(sc, DW_IC_CLR_INTR);
    412 		dwiic_write(sc, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY);
    413 
    414 		if (cv_timedwait(&sc->sc_int_writewait,
    415 		    &sc->sc_int_lock, hz / 2) != 0)
    416 			device_printf(sc->sc_dev,
    417 			    "timed out waiting for tx_empty intr\n");
    418 		dwiic_write(sc, DW_IC_INTR_MASK, 0);
    419 		dwiic_read(sc, DW_IC_CLR_INTR);
    420 		mutex_exit(&sc->sc_int_lock);
    421 	}
    422 
    423 	/* send our command, one byte at a time */
    424 	if (cmdlen > 0) {
    425 		bcmd = (const void *)cmdbuf;
    426 
    427 		DPRINTF(("%s: %s: sending cmd (len %zu):", device_xname(sc->sc_dev),
    428 		    __func__, cmdlen));
    429 		for (x = 0; x < cmdlen; x++)
    430 			DPRINTF((" %02x", bcmd[x]));
    431 		DPRINTF(("\n"));
    432 
    433 		tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
    434 		if (cmdlen > tx_limit) {
    435 			/* TODO */
    436 			device_printf(sc->sc_dev, "can't write %zu (> %d)\n",
    437 			    cmdlen, tx_limit);
    438 			sc->sc_i2c_xfer.error = 1;
    439 			return (1);
    440 		}
    441 
    442 		for (x = 0; x < cmdlen; x++) {
    443 			cmd = bcmd[x];
    444 			/*
    445 			 * Generate STOP condition if this is the last
    446 			 * byte of the transfer.
    447 			 */
    448 			if (x == (cmdlen - 1) && len == 0 && I2C_OP_STOP_P(op))
    449 				cmd |= DW_IC_DATA_CMD_STOP;
    450 			dwiic_write(sc, DW_IC_DATA_CMD, cmd);
    451 		}
    452 	}
    453 
    454 	bdata = (void *)buf;
    455 	x = readpos = 0;
    456 	tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
    457 
    458 	DPRINTF(("%s: %s: need to read %zu bytes, can send %d read reqs\n",
    459 		device_xname(sc->sc_dev), __func__, len, tx_limit));
    460 
    461 	while (x < len) {
    462 		if (I2C_OP_WRITE_P(op))
    463 			cmd = bdata[x];
    464 		else
    465 			cmd = DW_IC_DATA_CMD_READ;
    466 
    467 		/*
    468 		 * Generate RESTART condition if we're reversing
    469 		 * direction.
    470 		 */
    471 		if (x == 0 && cmdlen > 0 && I2C_OP_READ_P(op))
    472 			cmd |= DW_IC_DATA_CMD_RESTART;
    473 		/*
    474 		 * Generate STOP conditon on the last byte of the
    475 		 * transfer.
    476 		 */
    477 		if (x == (len - 1) && I2C_OP_STOP_P(op))
    478 			cmd |= DW_IC_DATA_CMD_STOP;
    479 
    480 		dwiic_write(sc, DW_IC_DATA_CMD, cmd);
    481 
    482 		tx_limit--;
    483 		x++;
    484 
    485 		/*
    486 		 * As TXFLR fills up, we need to clear it out by reading all
    487 		 * available data.
    488 		 */
    489 		while (I2C_OP_READ_P(op) && (tx_limit == 0 || x == len)) {
    490 			DPRINTF(("%s: %s: tx_limit %d, sent %d read reqs\n",
    491 			    device_xname(sc->sc_dev), __func__, tx_limit, x));
    492 
    493 			if (flags & I2C_F_POLL) {
    494 				for (retries = 100; retries > 0; retries--) {
    495 					rx_avail = dwiic_read(sc, DW_IC_RXFLR);
    496 					if (rx_avail > 0)
    497 						break;
    498 					DELAY(50);
    499 				}
    500 			} else {
    501 				mutex_enter(&sc->sc_int_lock);
    502 				dwiic_read(sc, DW_IC_CLR_INTR);
    503 				dwiic_write(sc, DW_IC_INTR_MASK,
    504 				    DW_IC_INTR_RX_FULL);
    505 
    506 				if (cv_timedwait(&sc->sc_int_readwait,
    507 				    &sc->sc_int_lock, hz / 2) != 0)
    508 					device_printf(sc->sc_dev,
    509 					    "timed out waiting for "
    510 					    "rx_full intr\n");
    511 
    512 				dwiic_write(sc, DW_IC_INTR_MASK, 0);
    513 				dwiic_read(sc, DW_IC_CLR_INTR);
    514 				mutex_exit(&sc->sc_int_lock);
    515 				rx_avail = dwiic_read(sc, DW_IC_RXFLR);
    516 			}
    517 
    518 			if (rx_avail == 0) {
    519 				device_printf(sc->sc_dev,
    520 				    "timed out reading remaining %d\n",
    521 				    (int)(len - 1 - readpos));
    522 				sc->sc_i2c_xfer.error = 1;
    523 				return (1);
    524 			}
    525 
    526 			DPRINTF(("%s: %s: %d avail to read (%zu remaining)\n",
    527 			    device_xname(sc->sc_dev), __func__, rx_avail,
    528 			    len - readpos));
    529 
    530 			while (rx_avail > 0) {
    531 				resp = dwiic_read(sc, DW_IC_DATA_CMD);
    532 				if (readpos < len) {
    533 					bdata[readpos] = resp;
    534 					readpos++;
    535 				}
    536 				rx_avail--;
    537 			}
    538 
    539 			if (readpos >= len)
    540 				break;
    541 
    542 			DPRINTF(("%s: still need to read %d bytes\n",
    543 			    device_xname(sc->sc_dev), (int)(len - readpos)));
    544 			tx_limit = sc->tx_fifo_depth -
    545 			    dwiic_read(sc, DW_IC_TXFLR);
    546 		}
    547 	}
    548 
    549 	if (I2C_OP_STOP_P(op) && I2C_OP_WRITE_P(op)) {
    550 		if (flags & I2C_F_POLL) {
    551 			/* wait for bus to be idle */
    552 			for (retries = 100; retries > 0; retries--) {
    553 				st = dwiic_read(sc, DW_IC_STATUS);
    554 				if (!(st & DW_IC_STATUS_ACTIVITY))
    555 					break;
    556 				DELAY(1000);
    557 			}
    558 			if (st & DW_IC_STATUS_ACTIVITY)
    559 				device_printf(sc->sc_dev, "timed out waiting "
    560 				    "for bus idle\n");
    561 		} else {
    562 			mutex_enter(&sc->sc_int_lock);
    563 			dwiic_read(sc, DW_IC_CLR_INTR);
    564 			dwiic_write(sc, DW_IC_INTR_MASK,
    565 			    DW_IC_INTR_STOP_DET);
    566 			if (cv_timedwait(&sc->sc_int_stopwait,
    567 			    &sc->sc_int_lock, hz / 2) != 0)
    568 				device_printf(sc->sc_dev, "timed out waiting "
    569 				    "for stop intr\n");
    570 			dwiic_write(sc, DW_IC_INTR_MASK, 0);
    571 			dwiic_read(sc, DW_IC_CLR_INTR);
    572 			mutex_exit(&sc->sc_int_lock);
    573 		}
    574 	}
    575 
    576 	return 0;
    577 }
    578 
    579 static uint32_t
    580 dwiic_read_clear_intrbits(struct dwiic_softc *sc)
    581 {
    582        uint32_t stat;
    583 
    584        stat = dwiic_read(sc, DW_IC_INTR_STAT);
    585 
    586        if (stat & DW_IC_INTR_RX_UNDER)
    587 	       dwiic_read(sc, DW_IC_CLR_RX_UNDER);
    588        if (stat & DW_IC_INTR_RX_OVER)
    589 	       dwiic_read(sc, DW_IC_CLR_RX_OVER);
    590        if (stat & DW_IC_INTR_TX_OVER)
    591 	       dwiic_read(sc, DW_IC_CLR_TX_OVER);
    592        if (stat & DW_IC_INTR_RD_REQ)
    593 	       dwiic_read(sc, DW_IC_CLR_RD_REQ);
    594        if (stat & DW_IC_INTR_TX_ABRT)
    595 	       dwiic_read(sc, DW_IC_CLR_TX_ABRT);
    596        if (stat & DW_IC_INTR_RX_DONE)
    597 	       dwiic_read(sc, DW_IC_CLR_RX_DONE);
    598        if (stat & DW_IC_INTR_ACTIVITY)
    599 	       dwiic_read(sc, DW_IC_CLR_ACTIVITY);
    600        if (stat & DW_IC_INTR_STOP_DET)
    601 	       dwiic_read(sc, DW_IC_CLR_STOP_DET);
    602        if (stat & DW_IC_INTR_START_DET)
    603 	       dwiic_read(sc, DW_IC_CLR_START_DET);
    604        if (stat & DW_IC_INTR_GEN_CALL)
    605 	       dwiic_read(sc, DW_IC_CLR_GEN_CALL);
    606 
    607        return stat;
    608 }
    609 
    610 int
    611 dwiic_intr(void *arg)
    612 {
    613 	struct dwiic_softc *sc = arg;
    614 	uint32_t en, stat;
    615 
    616 	en = dwiic_read(sc, DW_IC_ENABLE);
    617 	/* probably for the other controller */
    618 	if (!en)
    619 		return 0;
    620 
    621 	stat = dwiic_read_clear_intrbits(sc);
    622 	DPRINTF(("%s: %s: enabled=0x%x stat=0x%x\n", device_xname(sc->sc_dev),
    623 	    __func__, en, stat));
    624 	if (!(stat & ~DW_IC_INTR_ACTIVITY))
    625 		return 1;
    626 
    627 	if (stat & DW_IC_INTR_TX_ABRT)
    628 		sc->sc_i2c_xfer.error = 1;
    629 
    630 	if (sc->sc_i2c_xfer.flags & I2C_F_POLL)
    631 		DPRINTF(("%s: %s: intr in poll mode?\n", device_xname(sc->sc_dev),
    632 		    __func__));
    633 	else {
    634 		mutex_enter(&sc->sc_int_lock);
    635 		if (stat & DW_IC_INTR_RX_FULL) {
    636 			dwiic_write(sc, DW_IC_INTR_MASK, 0);
    637 			DPRINTF(("%s: %s: waking up reader\n",
    638 			    device_xname(sc->sc_dev), __func__));
    639 			cv_signal(&sc->sc_int_readwait);
    640 		}
    641 		if (stat & DW_IC_INTR_TX_EMPTY) {
    642 			dwiic_write(sc, DW_IC_INTR_MASK, 0);
    643 			DPRINTF(("%s: %s: waking up writer\n",
    644 			    device_xname(sc->sc_dev), __func__));
    645 			cv_signal(&sc->sc_int_writewait);
    646 		}
    647 		if (stat & DW_IC_INTR_STOP_DET) {
    648 			dwiic_write(sc, DW_IC_INTR_MASK, 0);
    649 			DPRINTF(("%s: %s: waking up stopper\n",
    650 			    device_xname(sc->sc_dev), __func__));
    651 			cv_signal(&sc->sc_int_stopwait);
    652 		}
    653 		mutex_exit(&sc->sc_int_lock);
    654 	}
    655 
    656 	return 1;
    657 }
    658