Skip site navigation (1)Skip section navigation (2)
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>