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