Module Name:    src
Committed By:   kiyohara
Date:           Sat Aug  6 03:42:11 UTC 2011

Modified Files:
        src/sys/arch/arm/xscale: pxa2x0_i2c.c pxa2x0_i2c.h

Log Message:
Support slave mode for PXA2x0 I2C.


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/xscale/pxa2x0_i2c.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/xscale/pxa2x0_i2c.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/xscale/pxa2x0_i2c.c
diff -u src/sys/arch/arm/xscale/pxa2x0_i2c.c:1.7 src/sys/arch/arm/xscale/pxa2x0_i2c.c:1.8
--- src/sys/arch/arm/xscale/pxa2x0_i2c.c:1.7	Thu Jun 23 11:26:22 2011
+++ src/sys/arch/arm/xscale/pxa2x0_i2c.c	Sat Aug  6 03:42:11 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: pxa2x0_i2c.c,v 1.7 2011/06/23 11:26:22 kiyohara Exp $	*/
+/*	$NetBSD: pxa2x0_i2c.c,v 1.8 2011/08/06 03:42:11 kiyohara Exp $	*/
 /*	$OpenBSD: pxa2x0_i2c.c,v 1.2 2005/05/26 03:52:07 pascoe Exp $	*/
 
 /*
@@ -18,12 +18,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pxa2x0_i2c.c,v 1.7 2011/06/23 11:26:22 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pxa2x0_i2c.c,v 1.8 2011/08/06 03:42:11 kiyohara Exp $");
 
 #include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/device.h>
 #include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
 
 #include <dev/i2c/i2cvar.h>
 
@@ -118,7 +119,7 @@
 
 retry:
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_UR);
-	bus_space_write_4(iot, ioh, I2C_ISAR, 0x00);
+	bus_space_write_4(iot, ioh, I2C_ISAR, sc->sc_isar);
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE | ISR_IRF);
 	delay(1);
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_SCLE);
@@ -162,8 +163,7 @@
 
 	rv = bus_space_read_4(iot, ioh, I2C_IDBR);
 	*valuep = (u_char)rv;
-	rv = bus_space_read_4(iot, ioh, I2C_ICR);
-	bus_space_write_4(iot, ioh, I2C_ICR, rv & ~(ICR_STOP | ICR_ACKNAK));
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_BEIE | ICR_SADIE);
 
 	return 0;
 
@@ -172,9 +172,9 @@
 		goto retry;
 
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_UR);
-	bus_space_write_4(iot, ioh, I2C_ISAR, 0x00);
+	bus_space_write_4(iot, ioh, I2C_ISAR, sc->sc_isar);
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE | ISR_IRF);
-	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_SCLE);
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_BEIE | ICR_SADIE);
 
 	return EIO;
 }
@@ -190,7 +190,7 @@
 
 retry:
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_UR);
-	bus_space_write_4(iot, ioh, I2C_ISAR, 0x00);
+	bus_space_write_4(iot, ioh, I2C_ISAR, sc->sc_isar);
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
 	delay(1);
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_SCLE);
@@ -235,8 +235,7 @@
 
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
 
-	rv = bus_space_read_4(iot, ioh, I2C_ICR);
-	bus_space_write_4(iot, ioh, I2C_ICR, rv & ~ICR_STOP);
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_BEIE | ICR_SADIE);
 
 	return 0;
 
@@ -245,9 +244,9 @@
 		goto retry;
 
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_UR);
-	bus_space_write_4(iot, ioh, I2C_ISAR, 0x00);
+	bus_space_write_4(iot, ioh, I2C_ISAR, sc->sc_isar);
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
-	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_SCLE);
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_BEIE | ICR_SADIE);
 
 	return EIO;
 }
@@ -266,7 +265,7 @@
 
 retry:
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_UR);
-	bus_space_write_4(iot, ioh, I2C_ISAR, 0x00);
+	bus_space_write_4(iot, ioh, I2C_ISAR, sc->sc_isar);
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
 	delay(1);
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_SCLE);
@@ -290,8 +289,7 @@
 
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
 
-	rv = bus_space_read_4(iot, ioh, I2C_ICR);
-	bus_space_write_4(iot, ioh, I2C_ICR, rv & ~ICR_STOP);
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_BEIE | ICR_SADIE);
 
 	return 0;
 
@@ -300,9 +298,9 @@
 		goto retry;
 
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_UR);
-	bus_space_write_4(iot, ioh, I2C_ISAR, 0x00);
+	bus_space_write_4(iot, ioh, I2C_ISAR, sc->sc_isar);
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
-	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_SCLE);
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_BEIE | ICR_SADIE);
 
 	return EIO;
 }
@@ -318,7 +316,7 @@
 
 retry:
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_UR);
-	bus_space_write_4(iot, ioh, I2C_ISAR, 0x00);
+	bus_space_write_4(iot, ioh, I2C_ISAR, sc->sc_isar);
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
 	delay(1);
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_SCLE);
@@ -386,6 +384,8 @@
 	rv = bus_space_read_4(iot, ioh, I2C_ICR);
 	bus_space_write_4(iot, ioh, I2C_ICR, rv & ~ICR_STOP);
 
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_BEIE | ICR_SADIE);
+
 	return 0;
 
 err:
@@ -393,9 +393,9 @@
 		goto retry;
 
 	bus_space_write_4(iot, ioh, I2C_ICR, ICR_UR);
-	bus_space_write_4(iot, ioh, I2C_ISAR, 0x00);
+	bus_space_write_4(iot, ioh, I2C_ISAR, sc->sc_isar);
 	bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
-	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_SCLE);
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_BEIE | ICR_SADIE);
 
 	return EIO;
 }
@@ -529,3 +529,190 @@
 	}
 	return 0;
 }
+
+
+int
+pxa2x0_i2c_poll(struct pxa2x0_i2c_softc *sc, int len, char *data, int op)
+{
+	bus_space_tag_t iot = sc->sc_iot;
+	bus_space_handle_t ioh = sc->sc_ioh;
+	uint32_t rv;
+	int timeout, tries, n = 0;
+
+	KASSERT(len > 0);
+
+	if (sc->sc_stat == PI2C_STAT_SEND) {
+		if (op != I2C_F_WRITE)
+			return 0;
+		goto send;
+	} else if (sc->sc_stat == PI2C_STAT_RECEIVE) {
+		if (op != I2C_F_READ)
+			return 0;
+		goto receive;
+	}
+
+	bus_space_write_4(iot, ioh, I2C_ISAR, sc->sc_isar);
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_SADIE);
+
+	/* Poll Slave Address Detected */
+	tries = I2C_RETRY_COUNT;
+	while (1 /*CONSTCOND*/) {
+		rv = bus_space_read_4(iot, ioh, I2C_ISR);
+		if ((rv & (ISR_SAD | ISR_UB)) == (ISR_SAD | ISR_UB))
+			break;
+		if (--tries <= 0)
+			return 0;
+		delay(1000);	/* XXXX */
+	}
+	bus_space_write_4(iot, ioh, I2C_ISR, ISR_SAD);	/* Clear SAD */
+
+	rv = bus_space_read_4(iot, ioh, I2C_ISR);
+	if (rv & ISR_RWM) {
+		if (op != I2C_F_WRITE)
+			return 0;
+		if (rv & ISR_ACKNAK)
+			return 0;
+
+send:
+		bus_space_write_4(iot, ioh, I2C_IDBR, data[n]);
+
+		/* Initiate the transfer */
+		rv = bus_space_read_4(iot, ioh, I2C_ICR);
+		bus_space_write_4(iot, ioh, I2C_ICR, rv | ICR_TB | ICR_ITEIE);
+
+		while (n < len - 1) {
+			timeout = 10000;
+			while (--timeout > 0) {
+				rv = bus_space_read_4(iot, ioh, I2C_ISR);
+				rv &= (ISR_ITE | ISR_ACKNAK | ISR_RWM);
+				if (rv == ISR_ITE)
+					break;
+				delay(1);
+			}
+			if (timeout == 0)
+				goto err;
+			bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
+
+			n++;
+			if (n < len)
+				bus_space_write_4(iot, ioh, I2C_IDBR, data[n]);
+
+			rv = bus_space_read_4(iot, ioh, I2C_ICR);
+			bus_space_write_4(iot, ioh, I2C_ICR,
+			    rv | ICR_TB | ICR_ITEIE);
+		}
+
+		timeout = 10000;
+		while (--timeout > 0) {
+			rv = bus_space_read_4(iot, ioh, I2C_ISR);
+			rv &= (ISR_ITE | ISR_ACKNAK | ISR_RWM);
+			if (rv == (ISR_ITE | ISR_ACKNAK))
+				break;
+			delay(1);
+		}
+		if (timeout == 0)
+			goto err;
+		bus_space_write_4(iot, ioh, I2C_ISR, ISR_ITE);
+
+		n++;
+	} else {
+		if (op != I2C_F_READ)
+			return 0;
+
+		while (n < len) {
+			rv = bus_space_read_4(iot, ioh, I2C_ICR);
+			bus_space_write_4(iot, ioh, I2C_ICR,
+			    rv | ICR_TB | ICR_IRFIE);
+
+receive:
+			timeout = 10000;
+			while (--timeout > 0) {
+				rv = bus_space_read_4(iot, ioh, I2C_ISR);
+				rv &= (ISR_IRF | ISR_ACKNAK | ISR_RWM);
+				if (rv == ISR_IRF)
+					break;
+				delay(1);
+			}
+			if (timeout == 0)
+				goto err;
+
+			data[n++] = bus_space_read_4(iot, ioh, I2C_IDBR);
+
+			bus_space_write_4(iot, ioh, I2C_ISR, ISR_IRF);
+		}
+
+		/* Release I2C bus and allow next transfer. */
+		rv = bus_space_read_4(iot, ioh, I2C_ICR);
+		bus_space_write_4(iot, ioh, I2C_ICR, rv | ICR_TB);
+	}
+
+	timeout = 10000;
+	while (--timeout > 0) {
+		rv = bus_space_read_4(iot, ioh, I2C_ISR);
+		rv &= (ISR_UB | ISR_SSD);
+		if (rv == ISR_SSD)
+			break;
+		delay(1);
+	}
+	if (timeout == 0)
+		goto err;
+	bus_space_write_4(iot, ioh, I2C_ISR, ISR_SSD);
+
+err:
+	bus_space_write_4(iot, ioh, I2C_ICR, ICR_IUE | ICR_BEIE | ICR_SADIE);
+
+	sc->sc_stat = PI2C_STAT_STOP;
+	return n;
+}
+
+int
+pxa2x0_i2c_intr_sub(struct pxa2x0_i2c_softc *sc, int *len, uint8_t *buf)
+{
+	bus_space_tag_t iot = sc->sc_iot;
+	bus_space_handle_t ioh = sc->sc_ioh;
+	int rv;
+	uint16_t isr;
+
+	isr = bus_space_read_4(iot, ioh, I2C_ISR);
+	bus_space_write_4(iot, ioh, I2C_ISR,
+	  isr & (ISR_BED|ISR_SAD|ISR_IRF|ISR_ITE|ISR_ALD|ISR_SSD));
+
+	DPRINTF(("%s: Interrupt Status 0x%x\n", __func__, isr));
+
+	*len = 0;
+	if (isr & ISR_SAD) {		/* Slave Address Detected */
+		if (isr & ISR_RWM)
+			sc->sc_stat = PI2C_STAT_SEND;
+		else {
+			rv = bus_space_read_4(iot, ioh, I2C_ICR);
+			bus_space_write_4(iot, ioh, I2C_ICR,
+			    rv | ICR_TB | ICR_IRFIE);
+			sc->sc_stat = PI2C_STAT_RECEIVE;
+		}
+		return 1;	/* handled */
+	} else if (isr & ISR_IRF) {	/* IDBR Receive Full */
+		*buf = bus_space_read_4(iot, ioh, I2C_IDBR);
+		*len = 1;
+
+		/* Next transfer start */
+		rv = bus_space_read_4(iot, ioh, I2C_ICR);
+		bus_space_write_4(iot, ioh, I2C_ICR,
+		    rv | ICR_TB | ICR_IRFIE | ICR_SSDIE);
+		return 1;	/* handled */
+	} else if (isr & ISR_SSD) {	/* Slave STOP Detected */
+		sc->sc_stat = PI2C_STAT_STOP;
+
+		bus_space_write_4(iot, ioh, I2C_ICR,
+		    ICR_IUE | ICR_BEIE | ICR_SADIE);
+		return 1;	/* handled */
+	} else if (isr & ISR_BED) {	/* Bus Error Detected */
+		aprint_error_dev(sc->sc_dev,
+		    "%s: Bus Error Detected\n", __func__);
+		sc->sc_stat = PI2C_STAT_ERROR;
+		return 0;	/* not handled */
+	}
+
+	sc->sc_stat = PI2C_STAT_UNKNOWN;
+	aprint_error_dev(sc->sc_dev, "Interrupt not handled 0x%x\n", isr);
+	return 0;	/* not handled */
+}

Index: src/sys/arch/arm/xscale/pxa2x0_i2c.h
diff -u src/sys/arch/arm/xscale/pxa2x0_i2c.h:1.4 src/sys/arch/arm/xscale/pxa2x0_i2c.h:1.5
--- src/sys/arch/arm/xscale/pxa2x0_i2c.h:1.4	Wed Jun 22 16:18:55 2011
+++ src/sys/arch/arm/xscale/pxa2x0_i2c.h	Sat Aug  6 03:42:11 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: pxa2x0_i2c.h,v 1.4 2011/06/22 16:18:55 kiyohara Exp $	*/
+/*	$NetBSD: pxa2x0_i2c.h,v 1.5 2011/08/06 03:42:11 kiyohara Exp $	*/
 /*	$OpenBSD: pxa2x0_i2c.h,v 1.2 2005/05/26 03:52:07 pascoe Exp $	*/
 
 /*
@@ -31,6 +31,16 @@
 	bus_size_t sc_size;
 
 	uint32_t sc_icr;
+	uint32_t sc_isar;	/* I2C Slave Address */
+
+	enum {
+		PI2C_STAT_UNKNOWN = -2,
+		PI2C_STAT_ERROR = -1,
+		PI2C_STAT_INIT = 0,
+		PI2C_STAT_SEND,
+		PI2C_STAT_RECEIVE,
+		PI2C_STAT_STOP,
+	} sc_stat;
 
 	uint32_t sc_flags;
 #define	PI2CF_FAST_MODE		(1U << 0)
@@ -41,10 +51,10 @@
 void	pxa2x0_i2c_init(struct pxa2x0_i2c_softc *);
 void	pxa2x0_i2c_open(struct pxa2x0_i2c_softc *);
 void	pxa2x0_i2c_close(struct pxa2x0_i2c_softc *);
-int	pxa2x0_i2c_read(struct pxa2x0_i2c_softc *sc, u_char, u_char *);
+int	pxa2x0_i2c_read(struct pxa2x0_i2c_softc *, u_char, u_char *);
 int	pxa2x0_i2c_write(struct pxa2x0_i2c_softc *, u_char, u_char);
 int	pxa2x0_i2c_write_2(struct pxa2x0_i2c_softc *, u_char, u_short);
-int	pxa2x0_i2c_quick(struct pxa2x0_i2c_softc *sc, u_char, u_char);
+int	pxa2x0_i2c_quick(struct pxa2x0_i2c_softc *, u_char, u_char);
 
 int	pxa2x0_i2c_send_start(struct pxa2x0_i2c_softc *, int flags);
 int	pxa2x0_i2c_send_stop(struct pxa2x0_i2c_softc *, int flags);
@@ -55,4 +65,7 @@
 void	pxa2x0_i2c_reset(struct pxa2x0_i2c_softc *);
 int	pxa2x0_i2c_wait(struct pxa2x0_i2c_softc *, int, int);
 
+int	pxa2x0_i2c_poll(struct pxa2x0_i2c_softc *, int, char *, int);
+int	pxa2x0_i2c_intr_sub(struct pxa2x0_i2c_softc *, int *, uint8_t *);
+
 #endif	/* _PXA2X0_I2C_H_ */

Reply via email to