Date: Tue, 28 Nov 2006 21:45:45 GMT From: Warner Losh <imp@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 110635 for review Message-ID: <200611282145.kASLjjWa096328@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=110635 Change 110635 by imp@imp_lighthouse on 2006/11/28 21:44:53 Go to an interrupt driven model. This saves 4.00 out of 4.00 system time seconds in reading a 2k part. The final speed is unaffected. Allow zero length read/write transactions. They aren't allowed in linux, but are useful for (a) probing (b) waiting for the device to become active during a long running operation like writing to eeprom. Affected files ... .. //depot/projects/arm/src/sys/arm/at91/at91_twi.c#29 edit Differences ... ==== //depot/projects/arm/src/sys/arm/at91/at91_twi.c#29 (text+ko) ==== @@ -52,9 +52,7 @@ struct resource *irq_res; /* IRQ resource */ struct resource *mem_res; /* Memory resource */ struct mtx sc_mtx; /* basically a perimeter lock */ - volatile int flags; -#define RXRDY 4 -#define TXRDY 0x10 + volatile uint32_t flags; uint32_t cwgr; int sc_started; int twi_addr; @@ -131,8 +129,6 @@ WR4(sc, TWI_CR, TWI_CR_SWRST); WR4(sc, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS); WR4(sc, TWI_CWGR, sc->cwgr); -// WR4(sc, TWI_IER, TWI_SR_RXRDY | TWI_SR_OVRE | TWI_SR_UNRE | -// TWI_SR_NACK); if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) device_printf(dev, "could not allocate iicbus instance\n"); @@ -210,15 +206,15 @@ /* Reading the status also clears the interrupt */ status = RD4(sc, TWI_SR); - printf("status %x\n", status); if (status == 0) return; - AT91_TWI_LOCK(sc); if (status & TWI_SR_RXRDY) - sc->flags |= RXRDY; + sc->flags |= TWI_SR_RXRDY; if (status & TWI_SR_TXRDY) - sc->flags |= TXRDY; - AT91_TWI_UNLOCK(sc); + sc->flags |= TWI_SR_TXRDY; + if (status & TWI_SR_TXCOMP) + sc->flags |= TWI_SR_TXCOMP; + WR4(sc, TWI_IDR, status); wakeup(sc); return; } @@ -226,13 +222,15 @@ static int at91_twi_wait(struct at91_twi_softc *sc, uint32_t bit) { - int err = 0; - int counter = 100000; + int err; - while (!(RD4(sc, TWI_SR) & bit) && counter-- >= 0) - continue; - if (counter <= 0) - err = EIO; + sc->flags = 0; + WR4(sc, TWI_IER, bit); + err = msleep(sc, &sc->sc_mtx, PZERO | PCATCH, "iic", MAX(1,hz/10)); + if (sc->flags & bit) + err = 0; + else if (err == 0) + err = EBUSY; return (err); } @@ -303,11 +301,13 @@ at91_twi_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) { struct at91_twi_softc *sc; - int i, len; + int i, len, err; uint32_t rdwr; uint8_t *buf; sc = device_get_softc(dev); + err = 0; + AT91_TWI_LOCK(sc); for (i = 0; i < nmsgs; i++) { /* * The linux atmel driver doesn't use the internal device @@ -320,15 +320,15 @@ WR4(sc, TWI_MMR, TWI_MMR_DADR(msgs[i].slave) | rdwr); len = msgs[i].len; buf = msgs[i].buf; - if (len == 0 || buf == NULL) + if (len != 0 && buf == NULL) return (EINVAL); WR4(sc, TWI_CR, TWI_CR_START); if (msgs[i].flags & IIC_M_RD) { while (len--) { if (len == 0) WR4(sc, TWI_CR, TWI_CR_STOP); - if (at91_twi_wait(sc, TWI_SR_RXRDY)) - return (EIO); + if ((err = at91_twi_wait(sc, TWI_SR_RXRDY))) + goto out; *buf++ = RD4(sc, TWI_RHR) & 0xff; } } else { @@ -336,14 +336,16 @@ WR4(sc, TWI_THR, *buf++); if (len == 0) WR4(sc, TWI_CR, TWI_CR_STOP); - if (at91_twi_wait(sc, TWI_SR_TXRDY)) - return (EIO); + if ((err = at91_twi_wait(sc, TWI_SR_TXRDY))) + goto out; } } - if (at91_twi_wait(sc, TWI_SR_TXCOMP)) - return (EIO); + if ((err = at91_twi_wait(sc, TWI_SR_TXCOMP))) + break; } - return (0); +out:; + AT91_TWI_UNLOCK(sc); + return (err); } static device_method_t at91_twi_methods[] = {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200611282145.kASLjjWa096328>