PERFORCE change 149900 for review

Rafal Jaworowski raj at FreeBSD.org
Tue Sep 16 20:11:15 UTC 2008


http://perforce.freebsd.org/chv.cgi?CH=149900

Change 149900 by raj at raj_mimi on 2008/09/16 20:10:58

	Refactor and optimize the TWSI (I2C) driver.
	
	Obtained from:	Semihalf

Affected files ...

.. //depot/projects/arm/src/sys/arm/mv/twsi.c#2 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/mv/twsi.c#2 (text+ko) ====

@@ -56,8 +56,7 @@
 #include <dev/iicbus/iicbus.h>
 #include "iicbus_if.h"
 
-
-#define MV_TWSI_NAME	"twsi"
+#define MV_TWSI_NAME		"twsi"
 
 #define TWSI_SLAVE_ADDR		0x00
 #define TWSI_EXT_SLAVE_ADDR	0x10
@@ -88,15 +87,22 @@
 
 #define TWSI_SOFT_RESET		0x1c
 
-struct mv_twsi_softc
-{
+#define TWSI_DEBUG
+#undef TWSI_DEBUG
+
+#ifdef  TWSI_DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+struct mv_twsi_softc {
 	device_t	dev;
 	struct resource	*res[1];	/* SYS_RES_MEMORY */
 	struct mtx	mutex;
 	device_t	iicbus;
 };
 
-
 static int mv_twsi_probe(device_t);
 static int mv_twsi_attach(device_t);
 static int mv_twsi_detach(device_t);
@@ -189,6 +195,7 @@
 	DELAY(1000);
 }
 
+
 /*
  * timeout given in us
  * returns
@@ -202,12 +209,79 @@
 	timeout /= 10;
 	while (!(TWSI_READ(sc, TWSI_CONTROL) & mask)) {
 		DELAY(10);
-		if(--timeout < 0)
+		if (--timeout < 0)
 			return (timeout);
 	}
 	return (0);
 }
 
+
+/*
+ * 'timeout' is given in us. Note also that timeout handling is not exact --
+ * twsi_locked_start() total wait can be more than 2 x timeout
+ * (twsi_poll_ctrl() is called twice). 'mask' can be either TWSI_STATUS_START
+ * or TWSI_STATUS_RPTD_START
+ */
+static int
+twsi_locked_start(device_t dev, struct mv_twsi_softc *sc, int32_t mask,
+    u_char slave, int timeout)
+{
+	int read_access, iflg_set = 0;
+	uint32_t status;
+
+	mtx_assert(&sc->mutex, MA_OWNED);
+
+	if (mask == TWSI_STATUS_RPTD_START)
+		/* read IFLG to know if it should be cleared later; from NBSD */
+		iflg_set = TWSI_READ(sc, TWSI_CONTROL) & TWSI_CONTROL_IFLG;
+
+	twsi_control_set(sc, TWSI_CONTROL_START);
+
+	if (mask == TWSI_STATUS_RPTD_START && iflg_set) {
+		debugf("IFLG set, clearing\n");
+		twsi_clear_iflg(sc);
+	}
+
+	/*
+	 * Without this delay we timeout checking IFLG if the timeout is 0.
+	 * NBSD driver always waits here too.
+	 */
+	DELAY(1000);
+
+	if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
+		debugf("timeout sending %sSTART condition\n",
+		    mask == TWSI_STATUS_START ? "" : "repeated ");
+		return (IIC_ETIMEOUT);
+	}
+
+	status = TWSI_READ(sc, TWSI_STATUS);
+	if (status != mask) {
+		debugf("wrong status (%02x) after sending %sSTART condition\n",
+		    status, mask == TWSI_STATUS_START ? "" : "repeated ");
+		return (IIC_ESTATUS);
+	}
+
+	TWSI_WRITE(sc, TWSI_DATA, slave);
+	DELAY(1000);
+	twsi_clear_iflg(sc);
+
+	if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
+		debugf("timeout sending slave address\n");
+		return (IIC_ETIMEOUT);
+	}
+	
+	read_access = (slave & 0x1) ? 1 : 0;
+	status = TWSI_READ(sc, TWSI_STATUS);
+	if (status != (read_access ?
+	    TWSI_STATUS_ADDR_R_ACK : TWSI_STATUS_ADDR_W_ACK)) {
+		debugf("no ACK (status: %02x) after sending slave address\n",
+		    status);
+		return (IIC_ENOACK);
+	}
+
+	return (IIC_NOERR);
+}
+
 static int
 mv_twsi_probe(device_t dev)
 {
@@ -228,23 +302,19 @@
 
 	/* Allocate IO resources */
 	if (bus_alloc_resources(dev, res_spec, sc->res)) {
-		device_printf(dev, "%s: could not allocate resources\n",
-		    __func__);
+		device_printf(dev, "could not allocate resources\n");
 		mv_twsi_detach(dev);
 		return (ENXIO);
 	}
 
 	sc->iicbus = device_add_child(dev, "iicbus", -1);
 	if (sc->iicbus == NULL) {
-		device_printf(dev, "%s: could not add iicbus child\n",
-		    __func__);
+		device_printf(dev, "could not add iicbus child\n");
 		mv_twsi_detach(dev);
 		return (ENXIO);
 	}
 
-	/* probe and attach the iicbus */
 	bus_generic_attach(dev);
-
 	return (0);
 }
 
@@ -306,123 +376,48 @@
 }
 
 /*
- * timeout is given in us (at least pcf driver assumes this). Note also
- * that timeout handling is not exact -- mv_twsi_start() total wait can be
- * more than 2 x timeout (poll_iflag() is called twice).
+ * timeout is given in us
  */
 static int
 mv_twsi_repeated_start(device_t dev, u_char slave, int timeout)
 {
 	struct mv_twsi_softc *sc;
-	uint32_t status;
-	int iflg_set, rv;
+	int rv;
 
 	sc = device_get_softc(dev);
 
 	mtx_lock(&sc->mutex);
-	/* read IFLG to know if it should be cleared later (NBSD does it) */
-	iflg_set = TWSI_READ(sc, TWSI_CONTROL) & TWSI_CONTROL_IFLG;
-
-	twsi_control_set(sc, TWSI_CONTROL_START);
-
-	if (iflg_set) {
-		device_printf(dev, "%s: IFLG set, clearing\n", __func__);
-		twsi_clear_iflg(sc);
-	}
-
-	/* DELAY analogous to mv_twsi_start */
-	DELAY(1000);
-
-	if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
-		device_printf(dev, "%s: timeout sending repeated START "
-		    "condition\n", __func__);
-		rv = IIC_ETIMEOUT;
-		goto err;
-	}
-
-	status = TWSI_READ(sc, TWSI_STATUS);
-	if (status != TWSI_STATUS_RPTD_START) {
-		device_printf(dev, "%s: wrong status (%02x) after sending "
-		    "repeated START condition\n", __func__, status);
-		rv = IIC_ESTATUS;
-		goto err;
-	}
+	rv = twsi_locked_start(dev, sc, TWSI_STATUS_RPTD_START, slave,
+	    timeout);
 	mtx_unlock(&sc->mutex);
-	return (IIC_NOERR);
 
-err:
-	mtx_unlock(&sc->mutex);
-	mv_twsi_stop(dev);
-	return (rv);
+	if (rv) {
+		mv_twsi_stop(dev);
+		return (rv);
+	} else
+		return (IIC_NOERR);
 }
 
 /*
- * timeout is given in us (at least pcf driver assumes this). Note also
- * that timeout handling is not exact -- mv_twsi_start() total wait can be
- * more than 2 x timeout (poll_iflag() is called twice).
+ * timeout is given in us
  */
 static int
 mv_twsi_start(device_t dev, u_char slave, int timeout)
 {
 	struct mv_twsi_softc *sc;
-	uint32_t status;
-	int read_access, rv;
+	int rv;
 
 	sc = device_get_softc(dev);
 
 	mtx_lock(&sc->mutex);
-	twsi_control_set(sc, TWSI_CONTROL_START);
-
-	/*
-	 * Without this delay, we timeout checking IFLG if the timeout is
-	 * 0. NBSD driver always waits here.
-	 */
-	DELAY(1000);
-
-	if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
-		device_printf(dev, "%s: timeout sending START condition\n",
-		    __func__);
-		rv = IIC_ETIMEOUT;
-		goto err;
-	}
-
-	status = TWSI_READ(sc, TWSI_STATUS);
-	if (status != TWSI_STATUS_START) {
-		device_printf(dev, "%s: wrong status (%02x) after sending "
-		    "START condition\n", __func__, status);
-		rv = IIC_ESTATUS;
-		goto err;
-	}
-
-	TWSI_WRITE(sc, TWSI_DATA, slave);
-
-	DELAY(1000);
-
-	twsi_clear_iflg(sc);
-
-	if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
-		device_printf(dev, "%s: timeout sending slave address\n",
-		    __func__);
-		rv = IIC_ETIMEOUT;
-		goto err;
-	}
-
-	read_access = (slave & 0x1) ? 1 : 0;
-	status = TWSI_READ(sc, TWSI_STATUS);
-	if (status != (read_access ?
-			TWSI_STATUS_ADDR_R_ACK : TWSI_STATUS_ADDR_W_ACK)) {
-		device_printf(dev, "%s: no ACK (status: %02x) after sending "
-		    "slave address\n", __func__, status);
-		rv = IIC_ENOACK;
-		goto err;
-	}
+	rv = twsi_locked_start(dev, sc, TWSI_STATUS_START, slave, timeout);
 	mtx_unlock(&sc->mutex);
-	return (IIC_NOERR);
 
-err:
-	mtx_unlock(&sc->mutex);
-	mv_twsi_stop(dev);
-	return (rv);
+	if (rv) {
+		mv_twsi_stop(dev);
+		return (rv);
+	} else
+		return (IIC_NOERR);
 }
 
 static int
@@ -454,7 +449,7 @@
 	*read = 0;
 	while (*read < len) {
 		/*
-		 * check if we are reading last byte of the last buffer,
+		 * Check if we are reading last byte of the last buffer,
 		 * do not send ACK then, per I2C specs
 		 */
 		last_byte = ((*read == len - 1) && last) ? 1 : 0;
@@ -464,21 +459,18 @@
 			twsi_control_set(sc, TWSI_CONTROL_ACK);
 
 		DELAY (1000);
-
 		twsi_clear_iflg(sc);
 
 		if (twsi_poll_ctrl(sc, delay, TWSI_CONTROL_IFLG)) {
-			device_printf(dev, "%s: timeout reading data\n",
-			    __func__);
+			debugf("timeout reading data\n");
 			rv = IIC_ETIMEOUT;
 			goto out;
 		}
 
 		status = TWSI_READ(sc, TWSI_STATUS);
 		if (status != (last_byte ?
-			TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) {
-			device_printf(dev, "%s: wrong status (%02x) while "
-			    "reading\n", __func__, status);
+		    TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) {
+			debugf("wrong status (%02x) while reading\n", status);
 			rv = IIC_ESTATUS;
 			goto out;
 		}
@@ -508,16 +500,14 @@
 
 		twsi_clear_iflg(sc);
 		if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
-			device_printf(dev, "%s: timeout writing data\n",
-			    __func__);
+			debugf("timeout writing data\n");
 			rv = IIC_ETIMEOUT;
 			goto out;
 		}
 
 		status = TWSI_READ(sc, TWSI_STATUS);
 		if (status != TWSI_STATUS_DATA_WR_ACK) {
-			device_printf(dev, "%s: wrong status (%02x) while "
-			    "writing\n", __func__, status);
+			debugf("wrong status (%02x) while writing\n", status);
 			rv = IIC_ESTATUS;
 			goto out;
 		}


More information about the p4-projects mailing list