Module Name: src
Committed By: jmcneill
Date: Mon Jul 9 10:24:44 UTC 2018
Modified Files:
src/sys/arch/arm/sunxi: sunxi_rsb.c
Log Message:
Put RSB controller into known state at the start of every transfer.
To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/sunxi/sunxi_rsb.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/arch/arm/sunxi/sunxi_rsb.c
diff -u src/sys/arch/arm/sunxi/sunxi_rsb.c:1.3 src/sys/arch/arm/sunxi/sunxi_rsb.c:1.4
--- src/sys/arch/arm/sunxi/sunxi_rsb.c:1.3 Sun Jul 1 21:15:02 2018
+++ src/sys/arch/arm/sunxi/sunxi_rsb.c Mon Jul 9 10:24:44 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_rsb.c,v 1.3 2018/07/01 21:15:02 jmcneill Exp $ */
+/* $NetBSD: sunxi_rsb.c,v 1.4 2018/07/09 10:24:44 jmcneill Exp $ */
/*-
* Copyright (c) 2014-2017 Jared McNeill <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_rsb.c,v 1.3 2018/07/01 21:15:02 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_rsb.c,v 1.4 2018/07/09 10:24:44 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -191,14 +191,6 @@ sunxi_rsb_attach(device_t parent, device
}
aprint_normal_dev(self, "interrupting on %s\n", intrstr);
- /* Enable interrupts */
- RSB_WRITE(sc, RSB_INTE_REG,
- RSB_INTE_LOAD_BSY_ENB |
- RSB_INTE_TRANS_ERR_ENB |
- RSB_INTE_TRANS_OVER_ENB);
- RSB_WRITE(sc, RSB_CTRL_REG,
- RSB_CTRL_GLOBAL_INT_ENB);
-
sc->sc_ic.ic_cookie = sc;
sc->sc_ic.ic_acquire_bus = sunxi_rsb_acquire_bus;
sc->sc_ic.ic_release_bus = sunxi_rsb_release_bus;
@@ -230,6 +222,23 @@ sunxi_rsb_intr(void *priv)
}
static int
+sunxi_rsb_soft_reset(struct sunxi_rsb_softc *sc)
+{
+ int retry = 1000;
+
+ RSB_WRITE(sc, RSB_CTRL_REG, RSB_CTRL_SOFT_RESET);
+ while (--retry > 0) {
+ if ((RSB_READ(sc, RSB_CTRL_REG) & RSB_CTRL_SOFT_RESET) == 0)
+ break;
+ delay(10);
+ }
+ if (retry == 0)
+ return EIO;
+
+ return 0;
+}
+
+static int
sunxi_rsb_wait(struct sunxi_rsb_softc *sc, int flags)
{
int error = 0, retry;
@@ -317,12 +326,7 @@ sunxi_rsb_acquire_bus(void *priv, int fl
{
struct sunxi_rsb_softc *sc = priv;
- if (flags & I2C_F_POLL) {
- if (!mutex_tryenter(&sc->sc_lock))
- return EBUSY;
- } else {
- mutex_enter(&sc->sc_lock);
- }
+ mutex_enter(&sc->sc_lock);
return 0;
}
@@ -349,6 +353,22 @@ sunxi_rsb_exec(void *priv, i2c_op_t op,
if (cmdlen != 1 || (len != 1 && len != 2 && len != 4))
return EINVAL;
+ error = sunxi_rsb_soft_reset(sc);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "soft reset timed out\n");
+ return error;
+ }
+
+ if ((flags & I2C_F_POLL) == 0) {
+ /* Enable interrupts */
+ RSB_WRITE(sc, RSB_INTE_REG,
+ RSB_INTE_LOAD_BSY_ENB |
+ RSB_INTE_TRANS_ERR_ENB |
+ RSB_INTE_TRANS_OVER_ENB);
+ RSB_WRITE(sc, RSB_CTRL_REG,
+ RSB_CTRL_GLOBAL_INT_ENB);
+ }
+
if (sc->sc_type == SUNXI_RSB && sc->sc_rsb_last_da != addr) {
/* Lookup run-time address for given device address */
for (rta = 0, i = 0; rsb_rtamap[i].rta != 0; i++)
@@ -367,7 +387,7 @@ sunxi_rsb_exec(void *priv, i2c_op_t op,
"SRTA failed, flags = %x, error = %d\n",
flags, error);
sc->sc_rsb_last_da = 0;
- return error;
+ goto done;
}
sc->sc_rsb_last_da = addr;
@@ -392,7 +412,8 @@ sunxi_rsb_exec(void *priv, i2c_op_t op,
(pbuf[2] << 16) | (pbuf[3] << 24);
break;
default:
- return EINVAL;
+ error = EINVAL;
+ goto done;
}
RSB_WRITE(sc, RSB_DATA0_REG, data);
}
@@ -404,14 +425,14 @@ sunxi_rsb_exec(void *priv, i2c_op_t op,
case 1: cmd = RSB_CMD_IDX_WR8; break;
case 2: cmd = RSB_CMD_IDX_WR16; break;
case 4: cmd = RSB_CMD_IDX_WR32; break;
- default: return EINVAL;
+ default: error = EINVAL; goto done;
}
} else {
switch (len) {
case 1: cmd = RSB_CMD_IDX_RD8; break;
case 2: cmd = RSB_CMD_IDX_RD16; break;
case 4: cmd = RSB_CMD_IDX_RD32; break;
- default: return EINVAL;
+ default: error = EINVAL; goto done;
}
}
RSB_WRITE(sc, RSB_CMD_REG, cmd);
@@ -428,7 +449,8 @@ sunxi_rsb_exec(void *priv, i2c_op_t op,
ctrl = RSB_READ(sc, RSB_CTRL_REG);
if (ctrl & RSB_CTRL_START_TRANS) {
device_printf(sc->sc_dev, "device is busy\n");
- return EBUSY;
+ error = EBUSY;
+ goto done;
}
/* Start the transfer */
@@ -436,9 +458,8 @@ sunxi_rsb_exec(void *priv, i2c_op_t op,
ctrl | RSB_CTRL_START_TRANS);
error = sunxi_rsb_wait(sc, flags);
- if (error) {
- return error;
- }
+ if (error)
+ goto done;
if (I2C_OP_READ_P(op)) {
uint32_t data = RSB_READ(sc, RSB_DATA0_REG);
@@ -453,9 +474,15 @@ sunxi_rsb_exec(void *priv, i2c_op_t op,
*(uint8_t *)buf = data & 0xff;
break;
default:
- return EINVAL;
+ error = EINVAL;
+ goto done;
}
}
- return 0;
+ error = 0;
+
+done:
+ RSB_WRITE(sc, RSB_CTRL_REG, 0);
+
+ return error;
}