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