Module Name: src Committed By: hkenken Date: Fri Nov 29 12:42:54 UTC 2019
Modified Files: src/sys/dev/i2c: motoi2c.c Log Message: Add wait for stop condition. To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/sys/dev/i2c/motoi2c.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/i2c/motoi2c.c diff -u src/sys/dev/i2c/motoi2c.c:1.5 src/sys/dev/i2c/motoi2c.c:1.6 --- src/sys/dev/i2c/motoi2c.c:1.5 Mon Aug 5 12:21:00 2019 +++ src/sys/dev/i2c/motoi2c.c Fri Nov 29 12:42:53 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: motoi2c.c,v 1.5 2019/08/05 12:21:00 hkenken Exp $ */ +/* $NetBSD: motoi2c.c,v 1.6 2019/11/29 12:42:53 hkenken Exp $ */ /*- * Copyright (c) 2007, 2010 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: motoi2c.c,v 1.5 2019/08/05 12:21:00 hkenken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: motoi2c.c,v 1.6 2019/11/29 12:42:53 hkenken Exp $"); #if defined(__arm__) || defined(__aarch64__) #include "opt_fdt.h" @@ -163,6 +163,24 @@ motoi2c_release_bus(void *v, int flags) mutex_exit(&sc->sc_buslock); } +static int +motoi2c_stop_wait(struct motoi2c_softc *sc) +{ + u_int timo; + int error = 0; + + timo = 1000; + while ((I2C_READ(I2CSR) & SR_MBB) != 0 && --timo) + DELAY(1); + + if (timo == 0) { + DPRINTF(("%s: timeout (sr=%#x)\n", __func__, I2C_READ(I2CSR))); + error = ETIMEDOUT; + } + + return error; +} + /* busy waiting for byte data transfer completion */ static int motoi2c_busy_wait(struct motoi2c_softc *sc, uint8_t cr) @@ -224,15 +242,9 @@ motoi2c_exec(void *v, i2c_op_t op, i2c_a if ((cr & CR_MSTA) == 0 && (sr & SR_MBB) != 0) { /* wait for bus becoming available */ - u_int timo = 100; - do { - DELAY(10); - } while (--timo > 0 && ((sr = I2C_READ(I2CSR)) & SR_MBB) != 0); - - if (timo == 0) { - DPRINTF(("%s: bus is busy (%#x)\n", __func__, sr)); + error = motoi2c_stop_wait(sc); + if (error) return ETIMEDOUT; - } } /* reset interrupt and arbitration-lost flags (all others are RO) */ @@ -240,12 +252,10 @@ motoi2c_exec(void *v, i2c_op_t op, i2c_a sr = I2C_READ(I2CSR); /* - * Generate start (or restart) condition + * Generate start condition */ - /* CR_RTSA is write-only and transitory */ - uint8_t rsta = (cr & CR_MSTA ? CR_RSTA : 0); cr = CR_MEN | CR_MTX | CR_MSTA; - I2C_WRITE(I2CCR, cr | rsta); + I2C_WRITE(I2CCR, cr); DPRINTF(("%s: started: sr=%#x cr=%#x/%#x\n", __func__, I2C_READ(I2CSR), cr, I2C_READ(I2CCR))); @@ -339,14 +349,14 @@ motoi2c_exec(void *v, i2c_op_t op, i2c_a cr |= CR_TXAK; I2C_WRITE(I2CCR, cr); } else if (i == datalen - 1 && I2C_OP_STOP_P(op)) { - cr = CR_MEN; + cr = CR_MEN | CR_TXAK; I2C_WRITE(I2CCR, cr); } *dataptr++ = I2C_READ(I2CDR); } if (datalen == 0) { if (I2C_OP_STOP_P(op)) { - cr = CR_MEN; + cr = CR_MEN | CR_TXAK; I2C_WRITE(I2CCR, cr); } (void)I2C_READ(I2CDR); /* dummy read */ @@ -378,6 +388,7 @@ motoi2c_exec(void *v, i2c_op_t op, i2c_a if (error || (cr & CR_TXAK) || ((cr & CR_MSTA) && I2C_OP_STOP_P(op))) { cr = CR_MEN; I2C_WRITE(I2CCR, cr); + motoi2c_stop_wait(sc); DPRINTF(("%s: stopping: cr=%#x/%#x\n", __func__, cr, I2C_READ(I2CCR))); }