Current-Users archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
PXA2x0 I2C slave mode
Hi! all,
My pxa255 machine requires support for I2C slave mode.
This patch supports interrupt handler and polling mode.
I will commit this patch next weekend.
Thanks
--
kiyohara
Index: arch/arm/xscale/pxa2x0_i2c.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/xscale/pxa2x0_i2c.c,v
retrieving revision 1.7
diff -u -r1.7 pxa2x0_i2c.c
--- arch/arm/xscale/pxa2x0_i2c.c 23 Jun 2011 11:26:22 -0000 1.7
+++ arch/arm/xscale/pxa2x0_i2c.c 31 Jul 2011 02:41:43 -0000
@@ -21,9 +21,10 @@
__KERNEL_RCSID(0, "$NetBSD: pxa2x0_i2c.c,v 1.7 2011/06/23 11:26:22 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: arch/arm/xscale/pxa2x0_i2c.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/xscale/pxa2x0_i2c.h,v
retrieving revision 1.4
diff -u -r1.4 pxa2x0_i2c.h
--- arch/arm/xscale/pxa2x0_i2c.h 22 Jun 2011 16:18:55 -0000 1.4
+++ arch/arm/xscale/pxa2x0_i2c.h 31 Jul 2011 02:41:43 -0000
@@ -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_ */
Home |
Main Index |
Thread Index |
Old Index