Date: Tue, 16 Sep 2008 20:11:15 GMT From: Rafal Jaworowski <raj@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 149900 for review Message-ID: <200809162011.m8GKBEsu080403@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=149900 Change 149900 by raj@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; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200809162011.m8GKBEsu080403>
