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;
 }

Reply via email to