Module Name:    src
Committed By:   phx
Date:           Wed May 12 17:20:24 UTC 2010

Modified Files:
        src/sys/arch/sandpoint/sandpoint: eumbvar.h iic_eumb.c

Log Message:
Rewrote most of the code to make the 8245 I2C module finally work.
Tested with a RICOH RS5C372 RTC on a Synology DS-101g+ and Kurobox.
Reviewed by <nisimura>.


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

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/sandpoint/sandpoint/eumbvar.h
diff -u src/sys/arch/sandpoint/sandpoint/eumbvar.h:1.4 src/sys/arch/sandpoint/sandpoint/eumbvar.h:1.5
--- src/sys/arch/sandpoint/sandpoint/eumbvar.h:1.4	Mon Apr 28 20:23:34 2008
+++ src/sys/arch/sandpoint/sandpoint/eumbvar.h	Wed May 12 17:20:24 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: eumbvar.h,v 1.4 2008/04/28 20:23:34 martin Exp $ */
+/* $NetBSD: eumbvar.h,v 1.5 2010/05/12 17:20:24 phx Exp $ */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -38,5 +38,3 @@
 };
 
 int eumbcnattach(bus_space_tag_t, int, int, int, int, int);
-void iic_bootstrap_init(void);
-int iic_bootstrap_read(int, int, uint8_t *, size_t);

Index: src/sys/arch/sandpoint/sandpoint/iic_eumb.c
diff -u src/sys/arch/sandpoint/sandpoint/iic_eumb.c:1.7 src/sys/arch/sandpoint/sandpoint/iic_eumb.c:1.8
--- src/sys/arch/sandpoint/sandpoint/iic_eumb.c:1.7	Wed Mar 18 10:22:35 2009
+++ src/sys/arch/sandpoint/sandpoint/iic_eumb.c	Wed May 12 17:20:24 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: iic_eumb.c,v 1.7 2009/03/18 10:22:35 cegger Exp $ */
+/* $NetBSD: iic_eumb.c,v 1.8 2010/05/12 17:20:24 phx Exp $ */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: iic_eumb.c,v 1.7 2009/03/18 10:22:35 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: iic_eumb.c,v 1.8 2010/05/12 17:20:24 phx Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -45,31 +45,31 @@
 
 #include <sandpoint/sandpoint/eumbvar.h>
 
-void iic_bootstrap_init(void);
-int iic_bootstrap_read(int, int, uint8_t *, size_t);
-
-static int  iic_eumb_match(struct device *, struct cfdata *, void *);
-static void iic_eumb_attach(struct device *, struct device *, void *);
-
 struct iic_eumb_softc {
 	struct device		sc_dev;
 	bus_space_tag_t		sc_iot;
 	bus_space_handle_t	sc_ioh;
 	struct i2c_controller	sc_i2c;
 	kmutex_t		sc_buslock;
+	bool			sc_start;
 };
 
+static int  iic_eumb_match(struct device *, struct cfdata *, void *);
+static void iic_eumb_attach(struct device *, struct device *, void *);
+
 CFATTACH_DECL(iic_eumb, sizeof(struct iic_eumb_softc),
     iic_eumb_match, iic_eumb_attach, NULL, NULL);
 
-static int motoi2c_acquire_bus(void *, int);
+static int  motoi2c_acquire_bus(void *, int);
 static void motoi2c_release_bus(void *, int);
-static int motoi2c_send_start(void *, int);
-static int motoi2c_send_stop(void *, int);
-static int motoi2c_initiate_xfer(void *, uint16_t, int);
-static int motoi2c_read_byte(void *, uint8_t *, int);
-static int motoi2c_write_byte(void *, uint8_t, int);
-static void waitxferdone(int);
+static int  motoi2c_send_start(void *, int);
+static int  motoi2c_send_stop(void *, int);
+static int  motoi2c_initiate_xfer(void *, uint16_t, int);
+static int  motoi2c_read_byte(void *, uint8_t *, int);
+static int  motoi2c_write_byte(void *, uint8_t, int);
+static int  motoi2c_waitxferdone(struct iic_eumb_softc *);
+
+struct iic_eumb_softc *iic_eumb;
 
 static struct i2c_controller motoi2c = {
 	.ic_acquire_bus = motoi2c_acquire_bus,
@@ -103,9 +103,11 @@
 #define	 SR_RXAK  0x01	/* 1 to indicate receive has completed */
 #define I2CDR	0x0010	/* data */
 
-#define	CSR_READ(r)	in8rb(0xfc003000 + (r))
-#define	CSR_WRITE(r,v)	out8rb(0xfc003000 + (r), (v))
-#define	CSR_WRITE4(r,v)	out32rb(0xfc003000 + (r), (v))
+#define	I2C_READ(r)	bus_space_read_4(sc->sc_iot, sc->sc_ioh, (r))
+#define	I2C_WRITE(r,v)	bus_space_write_4(sc->sc_iot, sc->sc_ioh, (r), (v))
+#define I2C_SETCLR(r, s, c) \
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, (r), \
+	    (bus_space_read_4(sc->sc_iot, sc->sc_ioh, (r)) | (s)) & ~(c))
 
 static int found;
 
@@ -119,74 +121,48 @@
 static void
 iic_eumb_attach(struct device *parent, struct device *self, void *aux)
 {
-	struct iic_eumb_softc *sc = (void *)self;
-	struct eumb_attach_args *eaa = aux;
+	struct iic_eumb_softc *sc;
+	struct eumb_attach_args *eaa;
 	struct i2cbus_attach_args iba;
 	bus_space_handle_t ioh;
 
+	sc = (struct iic_eumb_softc *)self;
+	eaa = aux;
 	found = 1;
 	printf("\n");
 
 	bus_space_map(eaa->eumb_bt, 0x3000, 0x20, 0, &ioh);
 	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
+
+	iic_eumb = sc;
 	sc->sc_i2c = motoi2c;
 	sc->sc_i2c.ic_cookie = sc;
 	sc->sc_iot = eaa->eumb_bt;
 	sc->sc_ioh = ioh;
+	sc->sc_start = false;
+	memset(&iba, 0, sizeof(iba));
 	iba.iba_tag = &sc->sc_i2c;
 
-	iic_bootstrap_init();
-#if 0
-	/* not yet */
+	I2C_WRITE(I2CCR, 0);		/* reset before changing anything */
+	I2C_WRITE(I2CFDR, 0x1031);	/* DFFSR=0x10, divider 3072 (0x31) */
+	I2C_WRITE(I2CADR, 0x7f << 1);	/* our slave address is 0x7f */
+	I2C_WRITE(I2CSR, 0);		/* clear status flags */
+	I2C_WRITE(I2CCR, CR_MEN);	/* enable the I2C module */
+
 	config_found_ia(&sc->sc_dev, "i2cbus", &iba, iicbus_print);
 
-	/* we never attempt to use I2C interrupt */
-	intr_establish(16 + 16, IST_LEVEL, IPL_BIO, iic_intr, sc);
+#if 0
+	/* we do not use the I2C interrupt yet */
+	intr_establish(16 + 16, IST_LEVEL, IPL_BIO, motoic2_intr, sc);
 #endif
 }
 
-void
-iic_bootstrap_init(void)
-{
-
-	CSR_WRITE(I2CCR, 0);
-	CSR_WRITE4(I2CFDR, 0x1031); /* XXX magic XXX */
-	CSR_WRITE(I2CADR, 0);
-	CSR_WRITE(I2CSR, 0);
-	CSR_WRITE(I2CCR, CR_MEN);
-}
-
-int
-iic_bootstrap_read(int i2caddr, int offset, uint8_t *rvp, size_t len)
-{
-	i2c_addr_t addr;
-	uint8_t cmdbuf[1];
-
-	if (motoi2c_acquire_bus(&motoi2c, I2C_F_POLL) != 0)
-		return -1;
-	while (len) {
-		addr = i2caddr + (offset >> 8);
-		cmdbuf[0] = offset & 0xff;
-		if (iic_exec(&motoi2c, I2C_OP_READ_WITH_STOP, addr,
-			     cmdbuf, 1, rvp, 1, I2C_F_POLL)) {
-			motoi2c_release_bus(&motoi2c, I2C_F_POLL);
-			return -1;
-		}
-		len--;
-		rvp++;
-		offset++;
-	}
-	motoi2c_release_bus(&motoi2c, I2C_F_POLL);
-	return 0;	
-}
-
 static int
 motoi2c_acquire_bus(void *v, int flags)
 {
-	struct iic_eumb_softc *sc = v;
+	struct iic_eumb_softc *sc;
 
-	if (flags & I2C_F_POLL)
-		return 0;
+	sc = v;
 	mutex_enter(&sc->sc_buslock);
 	return 0;
 }
@@ -194,88 +170,168 @@
 static void
 motoi2c_release_bus(void *v, int flags)
 {
-	struct iic_eumb_softc *sc = v;
+	struct iic_eumb_softc *sc;
 
-	if (flags & I2C_F_POLL)
-		return;
+	sc = v;
 	mutex_exit(&sc->sc_buslock);
 }
 
 static int
 motoi2c_send_start(void *v, int flags)
 {
-	int loop = 10;
+	struct iic_eumb_softc *sc;
+	int timo;
+
+	sc = v;
+
+	if (!sc->sc_start && (I2C_READ(I2CSR) & SR_MBB) != 0) {
+		/* wait for bus becoming available */
+		timo = 100;
+		do
+			DELAY(10);
+		while (--timo > 0 && (I2C_READ(I2CSR) & SR_MBB) != 0);
+
+		if (timo == 0) {
+#ifdef DEBUG
+			printf("%s: bus is busy\n", __func__);
+#endif
+			return -1;
+		}
+	}
+	else if (sc->sc_start &&
+	    (I2C_READ(I2CSR) & (SR_MIF | SR_MAL)) == SR_MIF) {
+		sc->sc_start = false;
+#ifdef DEBUG
+		printf("%s: lost the bus\n", __func__);
+#endif
+		return -1;
+	}
+
+	/* reset interrupt and arbitration-lost flags */
+	I2C_SETCLR(I2CSR, 0, SR_MIF | SR_MAL);
+
+	if (!sc->sc_start) {
+		/* generate start condition */
+		I2C_SETCLR(I2CCR, CR_MSTA | CR_MTX, CR_TXAK | CR_RSTA);
+		sc->sc_start = true;
+	} else	/* repeated start, we still own the bus */
+		I2C_SETCLR(I2CCR, CR_RSTA | CR_MTX, CR_TXAK);
 
-	CSR_WRITE(I2CSR, 0);
-	CSR_WRITE(I2CCR, CR_MEN);
-	do {
-		DELAY(1);
-	} while (--loop > 0 && (CSR_READ(I2CSR) & SR_MBB));
 	return 0;
 }
 
 static int
 motoi2c_send_stop(void *v, int flags)
 {
+	struct iic_eumb_softc *sc;
 
-	CSR_WRITE(I2CCR, CR_MEN);
+	sc = v;
+	I2C_SETCLR(I2CCR, 0, CR_MSTA | CR_RSTA | CR_TXAK);
+	sc->sc_start = false;
+	DELAY(100);
 	return 0;
 }
 
 static int
 motoi2c_initiate_xfer(void *v, i2c_addr_t addr, int flags)
 {
-	int rd_req;
+	struct iic_eumb_softc *sc;
 
-	rd_req = !!(flags & I2C_F_READ);
-	CSR_WRITE(I2CCR, CR_MIEN | CR_MEN | CR_MSTA | CR_MTX);
-	CSR_WRITE(I2CDR, (addr << 1) | rd_req);
-	if (flags & I2C_F_STOP)
-		CSR_WRITE(I2CCR, CR_MIEN | CR_MEN | CR_TXAK);
-	waitxferdone(SR_MIF);
-	return 0;
+	sc = v;
+
+	/* start condition */
+	if (motoi2c_send_start(v, flags) != 0)
+		return -1;
+
+	/* send target address and transfer direction */
+	I2C_WRITE(I2CDR, (addr << 1) | ((flags & I2C_F_READ) ? 1 : 0));
+
+	if (motoi2c_waitxferdone(sc) == 0) {
+		if (flags & I2C_F_READ) {
+			/* clear TX mode */
+			I2C_SETCLR(I2CCR, 0, CR_MTX);
+			/*
+			 * A dummy read is required to start with
+			 * receiving bytes.
+			 */
+			(void)I2C_READ(I2CDR);
+		}
+		if (flags & I2C_F_STOP)
+			return motoi2c_send_stop(v, flags);
+		return 0;
+	}
+	return -1;
 }
 
 static int
 motoi2c_read_byte(void *v, uint8_t *bytep, int flags)
 {
-	int last_byte, send_stop;
+	struct iic_eumb_softc *sc;
+
+	sc = v;
+
+	/* wait for next byte */
+	if (motoi2c_waitxferdone(sc) != 0)
+		return -1;
+
+	/* no TX-acknowledge for next byte */
+	if (flags & I2C_F_LAST)
+		I2C_SETCLR(I2CCR, CR_TXAK, 0);
+
+	*bytep = I2C_READ(I2CDR);
+
+	/*
+	 * To make the TXAK take effect we have to receive another
+	 * byte, which will be discarded.
+	 */
+	if (flags & I2C_F_LAST) {
+		(void)motoi2c_waitxferdone(sc);	/* ignore RXAK flag */
+		if (flags & I2C_F_STOP)
+			(void)motoi2c_send_stop(v, flags);
+		(void)I2C_READ(I2CDR);
+	} else if (flags & I2C_F_STOP)
+		return motoi2c_send_stop(v, flags);
 
-	last_byte = (flags & I2C_F_LAST) != 0;
-	send_stop = (flags & I2C_F_STOP) != 0;
-	if (last_byte)
-		CSR_WRITE(I2CCR, CR_MIEN | CR_MEN | CR_MSTA | CR_TXAK);
-	if (send_stop)
-		CSR_WRITE(I2CCR, CR_MIEN | CR_MEN | CR_TXAK);
-	waitxferdone(SR_MIF);
-	*bytep = CSR_READ(I2CDR);
 	return 0;
 }
 
 static int
 motoi2c_write_byte(void *v, uint8_t byte, int flags)
 {
-	int send_stop;
+	struct iic_eumb_softc *sc;
+
+	sc = v;
+	I2C_WRITE(I2CDR, byte);
+	DELAY(10);
+
+	if (motoi2c_waitxferdone(sc) != 0)
+		return -1;
+
+	if (flags & I2C_F_STOP)
+		return motoi2c_send_stop(v, flags);
 
-	send_stop = (flags & I2C_F_STOP) != 0;
-	if (send_stop)
-		CSR_WRITE(I2CCR, CR_MEN);
-	CSR_WRITE(I2CDR, byte);
-	waitxferdone(SR_MIF);
 	return 0;
 }
 
 /* busy waiting for byte data transfer completion */
-static void
-waitxferdone(int cond)
+static int
+motoi2c_waitxferdone(struct iic_eumb_softc *sc)
 {
-	int timo, sr;
+	uint32_t sr;
+	int timo;
 
-	timo = 100;
+	timo = 1000;
 	do {
-		DELAY(1);
-		sr = CSR_READ(I2CSR);
-	} while (--timo > 0 && (sr & cond) == 0);
-	sr &= ~cond;
-	CSR_WRITE(I2CSR, sr);
+		sr = I2C_READ(I2CSR);
+		DELAY(10);
+	} while (--timo > 0 && (sr & SR_MIF) == 0);
+
+#ifdef DEBUG
+	if (timo == 0)
+		printf("%s: timeout\n", __func__);
+	if (sr & SR_RXAK)
+		printf("%s: missing rx ack\n", __func__);
+#endif
+	I2C_SETCLR(I2CSR, 0, sr);
+	return (timo == 0 || (sr & SR_RXAK) != 0) ? -1 : 0;
 }

Reply via email to