From owner-p4-projects@FreeBSD.ORG Tue Apr 4 16:56:04 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 6328816A420; Tue, 4 Apr 2006 16:56:04 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 28CC016A401 for ; Tue, 4 Apr 2006 16:56:04 +0000 (UTC) (envelope-from imp@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 4891243D72 for ; Tue, 4 Apr 2006 16:55:47 +0000 (GMT) (envelope-from imp@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id k34Gti46075355 for ; Tue, 4 Apr 2006 16:55:44 GMT (envelope-from imp@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id k34GthkT075352 for perforce@freebsd.org; Tue, 4 Apr 2006 16:55:43 GMT (envelope-from imp@freebsd.org) Date: Tue, 4 Apr 2006 16:55:43 GMT Message-Id: <200604041655.k34GthkT075352@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to imp@freebsd.org using -f From: Warner Losh To: Perforce Change Reviews Cc: Subject: PERFORCE change 94609 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Apr 2006 16:56:04 -0000 http://perforce.freebsd.org/chv.cgi?CH=94609 Change 94609 by imp@imp_Speedy on 2006/04/04 16:54:42 Finish integrating to FreeBSD iicbus framework. Eliminate old untested kludge. Affected files ... .. //depot/projects/arm/src/sys/arm/at91/at91_twi.c#10 edit Differences ... ==== //depot/projects/arm/src/sys/arm/at91/at91_twi.c#10 (text+ko) ==== @@ -54,13 +54,14 @@ struct resource *mem_res; /* Memory resource */ struct mtx sc_mtx; /* basically a perimeter lock */ int flags; -#define XFER_PENDING 1 /* true when transfer taking place */ #define OPENED 2 /* Device opened */ #define RXRDY 4 -#define TXCOMP 8 +#define STOP_DONE 8 #define TXRDY 0x10 struct cdev *cdev; uint32_t cwgr; + int sc_started; + int twi_addr; }; static inline uint32_t @@ -225,7 +226,7 @@ if (status & TWI_SR_RXRDY) sc->flags |= RXRDY; if (status & TWI_SR_TXCOMP) - sc->flags |= TXCOMP; + sc->flags |= STOP_DONE; if (status & TWI_SR_TXRDY) sc->flags |= TXRDY; AT91_TWI_UNLOCK(sc); @@ -233,6 +234,20 @@ return; } +static int +at91_twi_wait_stop_done(struct at91_twi_softc *sc) +{ + int err = 0; + + while (!(sc->flags & STOP_DONE)) { + err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twiwsd", 0); + if (err) + break; + } + sc->flags &= ~STOP_DONE; + return (err); +} + static int at91_twi_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { @@ -263,103 +278,7 @@ return (0); } - -static int -at91_twi_read_master(struct at91_twi_softc *sc, struct at91_twi_io *xfr) -{ - uint8_t *walker; - uint8_t buffer[256]; - size_t len; - int err = 0; - - if (xfr->xfer_len > sizeof(buffer)) - return (EINVAL); - walker = buffer; - len = xfr->xfer_len; - RD4(sc, TWI_RHR); - // Master mode, with the right address and interal addr size - WR4(sc, TWI_MMR, TWI_MMR_IADRSZ(xfr->iadrsz) | TWI_MMR_MREAD | - TWI_MMR_DADR(xfr->dadr)); - WR4(sc, TWI_IADR, xfr->iadr); - WR4(sc, TWI_CR, TWI_CR_START); - while (len-- > 1) { - while (!(sc->flags & RXRDY)) { - err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twird", - 0); - if (err) - return (err); - } - sc->flags &= ~RXRDY; - *walker++ = RD4(sc, TWI_RHR) & 0xff; - } - WR4(sc, TWI_CR, TWI_CR_STOP); - while (!(sc->flags & TXCOMP)) { - err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twird2", 0); - if (err) - return (err); - } - sc->flags &= ~TXCOMP; - *walker = RD4(sc, TWI_RHR) & 0xff; - if (xfr->xfer_buf) { - AT91_TWI_UNLOCK(sc); - err = copyout(buffer, xfr->xfer_buf, xfr->xfer_len); - AT91_TWI_LOCK(sc); - } - return (err); -} - static int -at91_twi_write_master(struct at91_twi_softc *sc, struct at91_twi_io *xfr) -{ - uint8_t *walker; - uint8_t buffer[256]; - size_t len; - int err; - - if (xfr->xfer_len > sizeof(buffer)) - return (EINVAL); - walker = buffer; - len = xfr->xfer_len; - AT91_TWI_UNLOCK(sc); - err = copyin(xfr->xfer_buf, buffer, xfr->xfer_len); - AT91_TWI_LOCK(sc); - if (err) - return (err); - /* Setup the xfr for later readback */ - xfr->xfer_buf = 0; - xfr->xfer_len = 1; - while (len--) { - WR4(sc, TWI_MMR, TWI_MMR_IADRSZ(xfr->iadrsz) | TWI_MMR_MWRITE | - TWI_MMR_DADR(xfr->dadr)); - WR4(sc, TWI_IADR, xfr->iadr++); - WR4(sc, TWI_THR, *walker++); - WR4(sc, TWI_CR, TWI_CR_START); - /* - * If we get signal while waiting for TXRDY, make sure we - * try to stop this device - */ - while (!(sc->flags & TXRDY)) { - err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twiwr", - 0); - if (err) - break; - } - WR4(sc, TWI_CR, TWI_CR_STOP); - if (err) - return (err); - while (!(sc->flags & TXCOMP)) { - err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twiwr2", - 0); - if (err) - return (err); - } - /* Readback */ - at91_twi_read_master(sc, xfr); - } - return (err); -} - -static int at91_twi_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { @@ -368,36 +287,8 @@ sc = CDEV2SOFTC(dev); AT91_TWI_LOCK(sc); - while (sc->flags & XFER_PENDING) { - err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, - "twiwait", 0); - if (err) { - AT91_TWI_UNLOCK(sc); - return (err); - } - } - sc->flags |= XFER_PENDING; - switch (cmd) { - case TWIIOCXFER: - { - struct at91_twi_io *xfr = (struct at91_twi_io *)data; - switch (xfr->type) - { - case TWI_IO_READ_MASTER: - err = at91_twi_read_master(sc, xfr); - break; - case TWI_IO_WRITE_MASTER: - err = at91_twi_write_master(sc, xfr); - break; - default: - err = EINVAL; - break; - } - break; - } - case TWIIOCSETCLOCK: { struct at91_twi_clock *twick = (struct at91_twi_clock *)data; @@ -414,46 +305,167 @@ err = ENOTTY; break; } - sc->flags &= ~XFER_PENDING; AT91_TWI_UNLOCK(sc); wakeup(sc); return err; } +/* + * Stop the transfer by entering a STOP state on the iic bus. For read + * operations, we've already entered the STOP state, since we need to do + * that to read the last character. For write operations, we need to + * wait for the TXCOMP bit to turn on before returning. + */ static int at91_twi_stop(device_t dev) { - return (EIO); + struct at91_twi_softc *sc; + int err = 0; + + sc = device_get_softc(dev); + if (sc->sc_started) { + WR4(sc, TWI_CR, TWI_CR_STOP); + err = at91_twi_wait_stop_done(sc); + } + return (err); } +/* + * enter a START condition without requiring the device to be in a STOP + * state. + */ static int at91_twi_repeated_start(device_t dev, u_char slave, int timeout) { - return EIO; + struct at91_twi_softc *sc; + + sc = device_get_softc(dev); + WR4(sc, TWI_MMR, TWI_MMR_DADR(slave)); + WR4(sc, TWI_CR, TWI_CR_START); + sc->sc_started = 1; + return (0); } +/* + * enter a START condition from an idle state. + */ static int at91_twi_start(device_t dev, u_char slave, int timeout) { - return EIO; + struct at91_twi_softc *sc; + + sc = device_get_softc(dev); + WR4(sc, TWI_MMR, TWI_MMR_DADR(slave)); + WR4(sc, TWI_CR, TWI_CR_START); + sc->sc_started = 1; + return (0); } static int at91_twi_write(device_t dev, char *buf, int len, int *sent, int timeout /* us */) { - return EIO; + struct at91_twi_softc *sc; + uint8_t *walker; + int err = 0; + + walker = buf; + sc = device_get_softc(dev); + WR4(sc, TWI_MMR, TWI_MMR_MWRITE | RD4(sc, TWI_MMR)); + AT91_TWI_LOCK(sc); + while (len--) { + WR4(sc, TWI_THR, *walker++); + while (!(sc->flags & TXRDY)) { + err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twiwr", + 0); + if (err) + goto errout; + } + } +errout:; + AT91_TWI_UNLOCK(sc); + return (err); } static int at91_twi_read(device_t dev, char *buf, int len, int *read, int last, int delay /* us */) { - return EIO; + struct at91_twi_softc *sc; + char *walker; + int err = 0; + + walker = buf; + sc = device_get_softc(dev); + AT91_TWI_LOCK(sc); + WR4(sc, TWI_MMR, ~TWI_MMR_MWRITE & RD4(sc, TWI_MMR)); + while (len-- > 0) { + err = 0; + while (!(sc->flags & RXRDY)) { + err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "twird", + 0); + if (err) + goto errout; + } + sc->flags &= ~RXRDY; + *walker++ = RD4(sc, TWI_RHR) & 0xff; + if (len == 1 && last) + break; + } + if (!last) + goto errout; + WR4(sc, TWI_CR, TWI_CR_STOP); + err = at91_twi_wait_stop_done(sc); + *walker = RD4(sc, TWI_RHR) & 0xff; + if (read) + *read = walker - buf; + sc->sc_started = 0; +errout:; + AT91_TWI_UNLOCK(sc); + return (err); } static int at91_twi_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr) { + struct at91_twi_softc *sc; + int ckdiv, rate; + + sc = device_get_softc(dev); + if (oldaddr) + *oldaddr = sc->twi_addr; + if (addr != 0) + sc->twi_addr = 0; + else + sc->twi_addr = addr; + + rate = 1; + + /* + * 8 * is because "rate == 1" -> 4 clocks down, 4 clocks up. The + * speeds are for 1.5kb/s, 45kb/s and 90kb/s. + */ + switch (speed) { + case IIC_SLOW: + ckdiv = 8 * AT91C_MASTER_CLOCK / 1500; + break; + + case IIC_FAST: + ckdiv = 8 * AT91C_MASTER_CLOCK / 45000; + break; + + case IIC_UNKNOWN: + case IIC_FASTEST: + default: + ckdiv = 8 * AT91C_MASTER_CLOCK / 90000; + break; + } + + sc->cwgr = TWI_CWGR_CKDIV(ckdiv) | TWI_CWGR_CHDIV(TWI_CWGR_DIV(rate)) | + TWI_CWGR_CLDIV(TWI_CWGR_DIV(rate)); + WR4(sc, TWI_CR, TWI_CR_SWRST); + WR4(sc, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS); + WR4(sc, TWI_CWGR, sc->cwgr); + return EIO; }