[U-Boot-Users] [PATCH/review] Blackfin: overhaul i2c driver

Mike Frysinger vapier at gentoo.org
Sat Apr 19 02:37:01 CEST 2008


The current Blackfin i2c driver does not work properly with certain devices
due to it breaking up transfers incorrectly.  This is a rewrite of the
driver and relocates it to the newer place in the source tree.

Signed-off-by: Mike Frysinger <vapier at gentoo.org>
---
I couldn't get git-format-patch to detect the rename (tried -B, -M, and -C),
but the resulting diff between the files isn't terribly readable in the
first place, so it shouldn't be that big of a deal.

 cpu/blackfin/Makefile         |    2 +-
 cpu/blackfin/i2c.c            |  444 -----------------------------------------
 drivers/i2c/Makefile          |    1 +
 drivers/i2c/bfin-twi_i2c.c    |  300 +++++++++++++++++++++++++++
 include/configs/bf533-ezkit.h |    2 +-
 include/configs/bf533-stamp.h |    2 +-
 include/configs/bf537-stamp.h |   43 +----
 7 files changed, 308 insertions(+), 486 deletions(-)
 delete mode 100644 cpu/blackfin/i2c.c
 create mode 100644 drivers/i2c/bfin-twi_i2c.c

diff --git a/cpu/blackfin/Makefile b/cpu/blackfin/Makefile
index f194a38..b3a8b1e 100644
--- a/cpu/blackfin/Makefile
+++ b/cpu/blackfin/Makefile
@@ -17,7 +17,7 @@ EXTRA    :=
 CEXTRA   := initcode.o
 SEXTRA   := start.o
 SOBJS    := interrupt.o cache.o flush.o
-COBJS    := cpu.o traps.o interrupts.o reset.o serial.o i2c.o watchdog.o
+COBJS    := cpu.o traps.o interrupts.o reset.o serial.o watchdog.o
 
 ifeq ($(CONFIG_BFIN_BOOT_MODE),BFIN_BOOT_BYPASS)
 COBJS    += initcode.o
diff --git a/cpu/blackfin/i2c.c b/cpu/blackfin/i2c.c
deleted file mode 100644
index 47be258..0000000
--- a/cpu/blackfin/i2c.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * i2c.c - driver for Blackfin on-chip TWI/I2C
- *
- * Copyright (c) 2006-2008 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <common.h>
-
-#ifdef CONFIG_HARD_I2C
-
-#include <asm/blackfin.h>
-#include <i2c.h>
-#include <asm/io.h>
-#include <asm/mach-common/bits/twi.h>
-
-/* Two-Wire Interface		(0xFFC01400 - 0xFFC014FF) */
-#ifdef TWI0_CLKDIV
-#define bfin_read_TWI_CLKDIV()               bfin_read_TWI0_CLKDIV()
-#define bfin_write_TWI_CLKDIV(val)           bfin_write_TWI0_CLKDIV(val)
-#define bfin_read_TWI_CONTROL()              bfin_read_TWI0_CONTROL()
-#define bfin_write_TWI_CONTROL(val)          bfin_write_TWI0_CONTROL(val)
-#define bfin_read_TWI_SLAVE_CTL()            bfin_read_TWI0_SLAVE_CTL()
-#define bfin_write_TWI_SLAVE_CTL(val)        bfin_write_TWI0_SLAVE_CTL(val)
-#define bfin_read_TWI_SLAVE_STAT()           bfin_read_TWI0_SLAVE_STAT()
-#define bfin_write_TWI_SLAVE_STAT(val)       bfin_write_TWI0_SLAVE_STAT(val)
-#define bfin_read_TWI_SLAVE_ADDR()           bfin_read_TWI0_SLAVE_ADDR()
-#define bfin_write_TWI_SLAVE_ADDR(val)       bfin_write_TWI0_SLAVE_ADDR(val)
-#define bfin_read_TWI_MASTER_CTL()           bfin_read_TWI0_MASTER_CTL()
-#define bfin_write_TWI_MASTER_CTL(val)       bfin_write_TWI0_MASTER_CTL(val)
-#define bfin_read_TWI_MASTER_STAT()          bfin_read_TWI0_MASTER_STAT()
-#define bfin_write_TWI_MASTER_STAT(val)      bfin_write_TWI0_MASTER_STAT(val)
-#define bfin_read_TWI_MASTER_ADDR()          bfin_read_TWI0_MASTER_ADDR()
-#define bfin_write_TWI_MASTER_ADDR(val)      bfin_write_TWI0_MASTER_ADDR(val)
-#define bfin_read_TWI_INT_STAT()             bfin_read_TWI0_INT_STAT()
-#define bfin_write_TWI_INT_STAT(val)         bfin_write_TWI0_INT_STAT(val)
-#define bfin_read_TWI_INT_MASK()             bfin_read_TWI0_INT_MASK()
-#define bfin_write_TWI_INT_MASK(val)         bfin_write_TWI0_INT_MASK(val)
-#define bfin_read_TWI_FIFO_CTL()             bfin_read_TWI0_FIFO_CTL()
-#define bfin_write_TWI_FIFO_CTL(val)         bfin_write_TWI0_FIFO_CTL(val)
-#define bfin_read_TWI_FIFO_STAT()            bfin_read_TWI0_FIFO_STAT()
-#define bfin_write_TWI_FIFO_STAT(val)        bfin_write_TWI0_FIFO_STAT(val)
-#define bfin_read_TWI_XMT_DATA8()            bfin_read_TWI0_XMT_DATA8()
-#define bfin_write_TWI_XMT_DATA8(val)        bfin_write_TWI0_XMT_DATA8(val)
-#define bfin_read_TWI_XMT_DATA_16()          bfin_read_TWI0_XMT_DATA16()
-#define bfin_write_TWI_XMT_DATA16(val)       bfin_write_TWI0_XMT_DATA16(val)
-#define bfin_read_TWI_RCV_DATA8()            bfin_read_TWI0_RCV_DATA8()
-#define bfin_write_TWI_RCV_DATA8(val)        bfin_write_TWI0_RCV_DATA8(val)
-#define bfin_read_TWI_RCV_DATA16()           bfin_read_TWI0_RCV_DATA16()
-#define bfin_write_TWI_RCV_DATA16(val)       bfin_write_TWI0_RCV_DATA16(val)
-#endif
-
-#ifdef DEBUG_I2C
-#define PRINTD(fmt,args...)	do {	\
-	DECLARE_GLOBAL_DATA_PTR;	\
-	if (gd->have_console)		\
-		printf(fmt ,##args);	\
-	} while (0)
-#else
-#define PRINTD(fmt,args...)
-#endif
-
-#ifndef CONFIG_TWICLK_KHZ
-#define CONFIG_TWICLK_KHZ	50
-#endif
-
-/* All transfers are described by this data structure */
-struct i2c_msg {
-	u16 addr;		/* slave address */
-	u16 flags;
-#define I2C_M_STOP		0x2
-#define I2C_M_RD		0x1
-	u16 len;		/* msg length */
-	u8 *buf;		/* pointer to msg data */
-};
-
-/**
- * i2c_reset: - reset the host controller
- */
-static void i2c_reset(void)
-{
-	/* Disable TWI */
-	bfin_write_TWI_CONTROL(0);
-	SSYNC();
-
-	/* Set TWI internal clock as 10MHz */
-	bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
-
-	/* Set Twi interface clock as specified */
-	if (CONFIG_TWICLK_KHZ > 400)
-		bfin_write_TWI_CLKDIV(((5 * 1024 / 400) << 8) | ((5 * 1024 /
-						400) & 0xFF));
-	else
-		bfin_write_TWI_CLKDIV(((5 * 1024 /
-					CONFIG_TWICLK_KHZ) << 8) | ((5 * 1024 /
-						CONFIG_TWICLK_KHZ)
-						& 0xFF));
-
-	/* Enable TWI */
-	bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
-	SSYNC();
-}
-
-int wait_for_completion(struct i2c_msg *msg, int timeout_count)
-{
-	unsigned short twi_int_stat;
-	unsigned short mast_stat;
-	int i;
-
-	for (i = 0; i < timeout_count; i++) {
-		twi_int_stat = bfin_read_TWI_INT_STAT();
-		mast_stat = bfin_read_TWI_MASTER_STAT();
-
-		if (XMTSERV & twi_int_stat) {
-			/* Transmit next data */
-			if (msg->len > 0) {
-				bfin_write_TWI_XMT_DATA8(*(msg->buf++));
-				msg->len--;
-			} else if (msg->flags & I2C_M_STOP)
-				bfin_write_TWI_MASTER_CTL
-				    (bfin_read_TWI_MASTER_CTL() | STOP);
-			SSYNC();
-			/* Clear status */
-			bfin_write_TWI_INT_STAT(XMTSERV);
-			SSYNC();
-			i = 0;
-		}
-		if (RCVSERV & twi_int_stat) {
-			if (msg->len > 0) {
-				/* Receive next data */
-				*(msg->buf++) = bfin_read_TWI_RCV_DATA8();
-				msg->len--;
-			} else if (msg->flags & I2C_M_STOP) {
-				bfin_write_TWI_MASTER_CTL
-				    (bfin_read_TWI_MASTER_CTL() | STOP);
-				SSYNC();
-			}
-			/* Clear interrupt source */
-			bfin_write_TWI_INT_STAT(RCVSERV);
-			SSYNC();
-			i = 0;
-		}
-		if (MERR & twi_int_stat) {
-			bfin_write_TWI_INT_STAT(MERR);
-			bfin_write_TWI_INT_MASK(0);
-			bfin_write_TWI_MASTER_STAT(0x3e);
-			bfin_write_TWI_MASTER_CTL(0);
-			SSYNC();
-			/*
-			 * if both err and complete int stats are set,
-			 * return proper results.
-			 */
-			if (MCOMP & twi_int_stat) {
-				bfin_write_TWI_INT_STAT(MCOMP);
-				bfin_write_TWI_INT_MASK(0);
-				bfin_write_TWI_MASTER_CTL(0);
-				SSYNC();
-				/*
-				 * If it is a quick transfer,
-				 * only address bug no data, not an err.
-				 */
-				if (msg->len == 0 && mast_stat & BUFRDERR)
-					return 0;
-				/*
-				 * If address not acknowledged return -3,
-				 * else return 0.
-				 */
-				else if (!(mast_stat & ANAK))
-					return 0;
-				else
-					return -3;
-			}
-			return -1;
-		}
-		if (MCOMP & twi_int_stat) {
-			bfin_write_TWI_INT_STAT(MCOMP);
-			SSYNC();
-			bfin_write_TWI_INT_MASK(0);
-			bfin_write_TWI_MASTER_CTL(0);
-			SSYNC();
-			return 0;
-		}
-	}
-	if (msg->flags & I2C_M_RD)
-		return -4;
-	else
-		return -2;
-}
-
-/**
- * i2c_transfer: - Transfer one byte over the i2c bus
- *
- * This function can tranfer a byte over the i2c bus in both directions.
- * It is used by the public API functions.
- *
- * @return:	 0: transfer successful
- *		-1: transfer fail
- *		-2: transmit timeout
- *		-3: ACK missing
- *		-4: receive timeout
- *		-5: controller not ready
- */
-int i2c_transfer(struct i2c_msg *msg)
-{
-	int ret = 0;
-	int timeout_count = 10000;
-	int len = msg->len;
-
-	if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) {
-		ret = -5;
-		goto transfer_error;
-	}
-
-	while (bfin_read_TWI_MASTER_STAT() & BUSBUSY)
-		continue;
-
-	/* Set Transmit device address */
-	bfin_write_TWI_MASTER_ADDR(msg->addr);
-
-	/*
-	 * FIFO Initiation.
-	 * Data in FIFO should be discarded before start a new operation.
-	 */
-	bfin_write_TWI_FIFO_CTL(0x3);
-	SSYNC();
-	bfin_write_TWI_FIFO_CTL(0);
-	SSYNC();
-
-	if (!(msg->flags & I2C_M_RD)) {
-		/* Transmit first data */
-		if (msg->len > 0) {
-			PRINTD("1 in i2c_transfer: buf=%d, len=%d\n", *msg->buf,
-			       len);
-			bfin_write_TWI_XMT_DATA8(*(msg->buf++));
-			msg->len--;
-			SSYNC();
-		}
-	}
-
-	/* clear int stat */
-	bfin_write_TWI_INT_STAT(MERR | MCOMP | XMTSERV | RCVSERV);
-
-	/* Interrupt mask . Enable XMT, RCV interrupt */
-	bfin_write_TWI_INT_MASK(MCOMP | MERR |
-			((msg->flags & I2C_M_RD) ? RCVSERV : XMTSERV));
-	SSYNC();
-
-	if (len > 0 && len <= 255)
-		bfin_write_TWI_MASTER_CTL((len << 6));
-	else if (msg->len > 255) {
-		bfin_write_TWI_MASTER_CTL((0xff << 6));
-		msg->flags &= I2C_M_STOP;
-	} else
-		bfin_write_TWI_MASTER_CTL(0);
-
-	/* Master enable */
-	bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
-			((msg->flags & I2C_M_RD)
-			 ? MDIR : 0) | ((CONFIG_TWICLK_KHZ >
-					 100) ? FAST : 0));
-	SSYNC();
-
-	ret = wait_for_completion(msg, timeout_count);
-	PRINTD("3 in i2c_transfer: ret=%d\n", ret);
-
- transfer_error:
-	switch (ret) {
-	case 1:
-		PRINTD(("i2c_transfer: error: transfer fail\n"));
-		break;
-	case 2:
-		PRINTD(("i2c_transfer: error: transmit timeout\n"));
-		break;
-	case 3:
-		PRINTD(("i2c_transfer: error: ACK missing\n"));
-		break;
-	case 4:
-		PRINTD(("i2c_transfer: error: receive timeout\n"));
-		break;
-	case 5:
-		PRINTD(("i2c_transfer: error: controller not ready\n"));
-		i2c_reset();
-		break;
-	default:
-		break;
-	}
-	return ret;
-
-}
-
-/* ---------------------------------------------------------------------*/
-/* API Functions							*/
-/* ---------------------------------------------------------------------*/
-
-void i2c_init(int speed, int slaveaddr)
-{
-	i2c_reset();
-}
-
-/**
- * i2c_probe: - Test if a chip answers for a given i2c address
- *
- * @chip:	address of the chip which is searched for
- * @return: 	0 if a chip was found, -1 otherwhise
- */
-
-int i2c_probe(uchar chip)
-{
-	struct i2c_msg msg;
-	u8 probebuf;
-
-	i2c_reset();
-
-	probebuf = 0;
-	msg.addr = chip;
-	msg.flags = 0;
-	msg.len = 1;
-	msg.buf = &probebuf;
-	if (i2c_transfer(&msg))
-		return -1;
-
-	msg.addr = chip;
-	msg.flags = I2C_M_RD;
-	msg.len = 1;
-	msg.buf = &probebuf;
-	if (i2c_transfer(&msg))
-		return -1;
-
-	return 0;
-}
-
-/**
- *   i2c_read: - Read multiple bytes from an i2c device
- *
- *   chip:    I2C chip address, range 0..127
- *   addr:    Memory (register) address within the chip
- *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
- *		memories, 0 for register type devices with only one
- *		register)
- *   buffer:  Where to read/write the data
- *   len:     How many bytes to read/write
- *
- *   Returns: 0 on success, not 0 on failure
- */
-
-int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len)
-{
-	struct i2c_msg msg;
-	u8 addr_bytes[3];	/* lowest...highest byte of data address */
-
-	PRINTD("i2c_read: chip=0x%x, addr=0x%x, alen=0x%x, len=0x%x\n", chip,
-			addr, alen, len);
-
-	if (alen > 0) {
-		addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF);
-		addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF);
-		addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF);
-		msg.addr = chip;
-		msg.flags = 0;
-		msg.len = alen;
-		msg.buf = addr_bytes;
-		if (i2c_transfer(&msg))
-			return -1;
-	}
-
-	/* start read sequence */
-	PRINTD(("i2c_read: start read sequence\n"));
-	msg.addr = chip;
-	msg.flags = I2C_M_RD;
-	msg.len = len;
-	msg.buf = buffer;
-	if (i2c_transfer(&msg))
-		return -1;
-
-	return 0;
-}
-
-/**
- *   i2c_write: -  Write multiple bytes to an i2c device
- *
- *   chip:    I2C chip address, range 0..127
- *   addr:    Memory (register) address within the chip
- *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
- *		memories, 0 for register type devices with only one
- *		register)
- *   buffer:  Where to read/write the data
- *   len:     How many bytes to read/write
- *
- *   Returns: 0 on success, not 0 on failure
- */
-
-int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len)
-{
-	struct i2c_msg msg;
-	u8 addr_bytes[3];	/* lowest...highest byte of data address */
-
-	PRINTD
-		("i2c_write: chip=0x%x, addr=0x%x, alen=0x%x, len=0x%x, buf0=0x%x\n",
-		 chip, addr, alen, len, buffer[0]);
-
-	/* chip address write */
-	if (alen > 0) {
-		addr_bytes[0] = (u8) ((addr >> 0) & 0x000000FF);
-		addr_bytes[1] = (u8) ((addr >> 8) & 0x000000FF);
-		addr_bytes[2] = (u8) ((addr >> 16) & 0x000000FF);
-		msg.addr = chip;
-		msg.flags = 0;
-		msg.len = alen;
-		msg.buf = addr_bytes;
-		if (i2c_transfer(&msg))
-			return -1;
-	}
-
-	/* start read sequence */
-	PRINTD(("i2c_write: start write sequence\n"));
-	msg.addr = chip;
-	msg.flags = 0;
-	msg.len = len;
-	msg.buf = buffer;
-	if (i2c_transfer(&msg))
-		return -1;
-
-	return 0;
-
-}
-
-uchar i2c_reg_read(uchar chip, uchar reg)
-{
-	uchar buf;
-
-	PRINTD("i2c_reg_read: chip=0x%02x, reg=0x%02x\n", chip, reg);
-	i2c_read(chip, reg, 0, &buf, 1);
-	return (buf);
-}
-
-void i2c_reg_write(uchar chip, uchar reg, uchar val)
-{
-	PRINTD("i2c_reg_write: chip=0x%02x, reg=0x%02x, val=0x%02x\n", chip,
-			reg, val);
-	i2c_write(chip, reg, 0, &val, 1);
-}
-
-#endif /* CONFIG_HARD_I2C */
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 071ef00..0ad23ef 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk
 
 LIB 	:= $(obj)libi2c.a
 
+COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
 COBJS-y += fsl_i2c.o
 COBJS-y += omap1510_i2c.o
 COBJS-y += omap24xx_i2c.o
diff --git a/drivers/i2c/bfin-twi_i2c.c b/drivers/i2c/bfin-twi_i2c.c
new file mode 100644
index 0000000..9aceb0a
--- /dev/null
+++ b/drivers/i2c/bfin-twi_i2c.c
@@ -0,0 +1,300 @@
+/*
+ * i2c.c - driver for Blackfin on-chip TWI/I2C
+ *
+ * Copyright (c) 2006-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <i2c.h>
+
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/twi.h>
+
+#define debugi(fmt, args...) \
+	debug( \
+		"MSTAT:0x%03x FSTAT:0x%x ISTAT:0x%02x\t" \
+		"%-20s:%-3i: " fmt "\n", \
+		bfin_read_TWI_MASTER_STAT(), bfin_read_TWI_FIFO_STAT(), bfin_read_TWI_INT_STAT(), \
+		__func__, __LINE__, ## args)
+
+#ifdef TWI0_CLKDIV
+#define bfin_write_TWI_CLKDIV(val)           bfin_write_TWI0_CLKDIV(val)
+#define bfin_write_TWI_CONTROL(val)          bfin_write_TWI0_CONTROL(val)
+#define bfin_read_TWI_CONTROL(val)           bfin_read_TWI0_CONTROL(val)
+#define bfin_write_TWI_MASTER_ADDR(val)      bfin_write_TWI0_MASTER_ADDR(val)
+#define bfin_write_TWI_XMT_DATA8(val)        bfin_write_TWI0_XMT_DATA8(val)
+#define bfin_read_TWI_RCV_DATA8()            bfin_read_TWI0_RCV_DATA8()
+#define bfin_read_TWI_INT_STAT()             bfin_read_TWI0_INT_STAT()
+#define bfin_write_TWI_INT_STAT(val)         bfin_write_TWI0_INT_STAT(val)
+#define bfin_read_TWI_MASTER_STAT()          bfin_read_TWI0_MASTER_STAT()
+#define bfin_write_TWI_MASTER_STAT(val)      bfin_write_TWI0_MASTER_STAT(val)
+#define bfin_read_TWI_MASTER_CTL()           bfin_read_TWI0_MASTER_CTL()
+#define bfin_write_TWI_MASTER_CTL(val)       bfin_write_TWI0_MASTER_CTL(val)
+#define bfin_write_TWI_INT_MASK(val)         bfin_write_TWI0_INT_MASK(val)
+#define bfin_write_TWI_FIFO_CTL(val)         bfin_write_TWI0_FIFO_CTL(val)
+#endif
+
+#ifdef CONFIG_TWICLK_KHZ
+# error do not define CONFIG_TWICLK_KHZ ... use CFG_I2C_SPEED
+#endif
+#if CFG_I2C_SPEED > 400000
+# error The Blackfin I2C hardware can only operate at 400KHz max
+#endif
+
+/* All transfers are described by this data structure */
+struct i2c_msg {
+	u8 flags;
+#define I2C_M_COMBO		0x4
+#define I2C_M_STOP		0x2
+#define I2C_M_READ		0x1
+	int len;		/* msg length */
+	u8 *buf;		/* pointer to msg data */
+	int alen;		/* addr length */
+	u8 *abuf;		/* addr buffer */
+};
+
+/**
+ *	wait_for_completion: manage the transfer
+ */
+static int wait_for_completion(struct i2c_msg *msg)
+{
+	uint16_t int_stat;
+
+	while (!ctrlc()) {
+		int_stat = bfin_read_TWI_INT_STAT();
+
+		if (int_stat & XMTSERV) {
+			debugi("processing XMTSERV");
+			bfin_write_TWI_INT_STAT(XMTSERV);
+			SSYNC();
+			if (msg->alen) {
+				bfin_write_TWI_XMT_DATA8(*(msg->abuf++));
+				--msg->alen;
+			} else if (!(msg->flags & I2C_M_COMBO) && msg->len) {
+				bfin_write_TWI_XMT_DATA8(*(msg->buf++));
+				--msg->len;
+			} else {
+				bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
+					(msg->flags & I2C_M_COMBO ? RSTART | MDIR : STOP));
+				SSYNC();
+			}
+		}
+		if (int_stat & RCVSERV) {
+			debugi("processing RCVSERV");
+			bfin_write_TWI_INT_STAT(RCVSERV);
+			SSYNC();
+			if (msg->len) {
+				*(msg->buf++) = bfin_read_TWI_RCV_DATA8();
+				--msg->len;
+			} else if (msg->flags & I2C_M_STOP) {
+				bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | STOP);
+				SSYNC();
+			}
+		}
+		if (int_stat & MERR) {
+			debugi("processing MERR");
+			bfin_write_TWI_INT_STAT(MERR);
+			SSYNC();
+			break;
+		}
+		if (int_stat & MCOMP) {
+			debugi("processing MCOMP");
+			bfin_write_TWI_INT_STAT(MCOMP);
+			SSYNC();
+			if (msg->flags & I2C_M_COMBO && msg->len) {
+				bfin_write_TWI_MASTER_CTL((bfin_read_TWI_MASTER_CTL() & ~RSTART) |
+					(min(msg->len, 0xff) << 6) | MEN | MDIR);
+				SSYNC();
+			} else
+				break;
+		}
+	}
+
+	return msg->len;
+}
+
+/**
+ * i2c_transfer - setup an i2c transfer
+ *
+ *	Here we just get the i2c stuff all prepped and ready, and then tail off
+ *	into wait_for_completion() for all the bits to go.
+ *
+ *	@return:	0 if things worked, non-0 if things failed
+ */
+static int i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer, int len, u8 flags)
+{
+	uchar addr_buffer[] = {
+		(addr >>  0),
+		(addr >>  8),
+		(addr >> 16),
+	};
+	struct i2c_msg msg = {
+		.flags = flags | (len >= 0xff ? I2C_M_STOP : 0),
+		.buf   = buffer,
+		.len   = len,
+		.abuf  = addr_buffer,
+		.alen  = alen,
+	};
+	int ret;
+
+	memset(buffer, 0xff, len);
+	debugi("chip=0x%x addr=0x%02x alen=%i buf[0]=0x%02x len=%i flags=0x%02x[%s] ",
+		chip, addr, alen, buffer[0], len, flags, (flags & I2C_M_READ ? "rd" : "wr"));
+
+	/* wait for things to settle */
+	while (bfin_read_TWI_MASTER_STAT() & BUSBUSY)
+		if (ctrlc())
+			return 1;
+
+	/* Set Transmit device address */
+	bfin_write_TWI_MASTER_ADDR(chip);
+
+	/* Clear the FIFO before starting things */
+	bfin_write_TWI_FIFO_CTL(XMTFLUSH | RCVFLUSH);
+	SSYNC();
+	bfin_write_TWI_FIFO_CTL(0);
+	SSYNC();
+
+	/* prime the pump */
+	if (msg.alen) {
+		len = msg.alen;
+		debugi("first byte=0x%02x", *msg.abuf);
+		bfin_write_TWI_XMT_DATA8(*(msg.abuf++));
+		--msg.alen;
+	} else if (!(msg.flags & I2C_M_READ) && msg.len) {
+		debugi("first byte=0x%02x", *msg.buf);
+		bfin_write_TWI_XMT_DATA8(*(msg.buf++));
+		--msg.len;
+	}
+
+	/* clear int stat */
+	bfin_write_TWI_MASTER_STAT(-1);
+	bfin_write_TWI_INT_STAT(-1);
+	bfin_write_TWI_INT_MASK(0);
+	SSYNC();
+
+	/* Master enable */
+	bfin_write_TWI_MASTER_CTL(
+			(bfin_read_TWI_MASTER_CTL() & FAST) |
+			(min(len, 0xff) << 6) | MEN |
+			((msg.flags & I2C_M_READ) ? MDIR : 0)
+	);
+	SSYNC();
+	debugi("CTL=0x%04x", bfin_read_TWI_MASTER_CTL());
+
+	/* process the rest */
+	ret = wait_for_completion(&msg);
+	debugi("ret=%d", ret);
+
+	if (ret) {
+		bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() & ~MEN);
+		bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA);
+		SSYNC();
+		bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+		SSYNC();
+	}
+
+	return ret;
+}
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed and slave addresses.
+ */
+void i2c_init(int speed, int slaveaddr)
+{
+	uint8_t prescale = ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F;
+
+	debugi("CONTROL:0x%04x CLKDIV:0x%04x", prescale,
+        ((5 * 1024 / (speed / 1000)) << 8) |
+        ((5 * 1024 / (speed / 1000)) & 0xFF));
+
+	/* Set TWI internal clock as 10MHz */
+	bfin_write_TWI_CONTROL(prescale);
+
+	/* Set TWI interface clock as specified */
+	bfin_write_TWI_CLKDIV(
+		((5 * 1024 / (speed / 1000)) << 8) |
+		((5 * 1024 / (speed / 1000)) & 0xFF)
+	);
+
+	/* Don't turn it on */
+	bfin_write_TWI_MASTER_CTL(speed > 100000 ? FAST : 0);
+
+	/* But enable it */
+	bfin_write_TWI_CONTROL(TWI_ENA | prescale);
+	SSYNC();
+
+#if CFG_I2C_SLAVE
+# error I2C slave support not tested/supported
+	/* If they want us as a slave, do it */
+	if (slaveaddr) {
+		bfin_write_TWI_SLAVE_ADDR(slaveaddr);
+		bfin_write_TWI_SLAVE_CTL(SEN);
+	}
+#endif
+}
+
+/**
+ * i2c_probe: - Test if a chip answers for a given i2c address
+ *
+ * @chip:	address of the chip which is searched for
+ * @return: 	0 if a chip was found, -1 otherwhise
+ */
+int i2c_probe(uchar chip)
+{
+	u8 byte;
+	return i2c_read(chip, 0, 0, &byte, 1);
+}
+
+/**
+ *   i2c_read: - Read multiple bytes from an i2c device
+ *
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	return i2c_transfer(chip, addr, alen, buffer, len, (alen ? I2C_M_COMBO : I2C_M_READ));
+}
+
+/**
+ *   i2c_write: -  Write multiple bytes to an i2c device
+ *
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	return i2c_transfer(chip, addr, alen, buffer, len, 0);
+}
+
+/*
+ * Utility routines to read/write registers.
+ */
+uchar i2c_reg_read(uchar chip, uchar reg)
+{
+	uchar buf;
+	i2c_read(chip, reg, 1, &buf, 1);
+	return buf;
+}
+void i2c_reg_write(uchar chip, uchar reg, uchar val)
+{
+	i2c_write(chip, reg, 1, &val, 1);
+}
diff --git a/include/configs/bf533-ezkit.h b/include/configs/bf533-ezkit.h
index 2f551ad..f267301 100644
--- a/include/configs/bf533-ezkit.h
+++ b/include/configs/bf533-ezkit.h
@@ -198,7 +198,7 @@
 #define I2C_DELAY	udelay(5)	/* 1/4 I2C clock duration */
 
 #define CFG_I2C_SPEED		50000
-#define CFG_I2C_SLAVE		0xFE
+#define CFG_I2C_SLAVE		0
 
 #define CFG_BOOTM_LEN		0x4000000	/* Large Image Length, set to 64 Meg */
 
diff --git a/include/configs/bf533-stamp.h b/include/configs/bf533-stamp.h
index 66a0af6..feadf86 100644
--- a/include/configs/bf533-stamp.h
+++ b/include/configs/bf533-stamp.h
@@ -300,7 +300,7 @@
 #define I2C_DELAY		udelay(5)	/* 1/4 I2C clock duration */
 
 #define CFG_I2C_SPEED		50000
-#define CFG_I2C_SLAVE		0xFE
+#define CFG_I2C_SLAVE		0
 #endif /* CONFIG_SOFT_I2C */
 
 /*
diff --git a/include/configs/bf537-stamp.h b/include/configs/bf537-stamp.h
index 39c7359..d4bac82 100644
--- a/include/configs/bf537-stamp.h
+++ b/include/configs/bf537-stamp.h
@@ -306,13 +306,11 @@
 
 /*
  * I2C settings
- * By default PF1 is used as SDA and PF0 as SCL on the Stamp board
  */
-/* #define CONFIG_SOFT_I2C	1*/	/* I2C bit-banged */
-#define CONFIG_HARD_I2C		1	/* I2C TWI */
-#if defined CONFIG_HARD_I2C
-#define CONFIG_TWICLK_KHZ	50
-#endif
+#define CONFIG_HARD_I2C		1
+#define CONFIG_BFIN_TWI_I2C	1
+#define CFG_I2C_SPEED		50000
+#define CFG_I2C_SLAVE		0
 
 #define CONFIG_EBIU_SDRRC_VAL  0x306
 #define CONFIG_EBIU_SDGCTL_VAL 0x91114d
@@ -322,39 +320,6 @@
 #define CONFIG_EBIU_AMBCTL0_VAL		0x7BB07BB0
 #define CONFIG_EBIU_AMBCTL1_VAL		0xFFC27BB0
 
-#if defined CONFIG_SOFT_I2C
-/*
- * Software (bit-bang) I2C driver configuration
- */
-#define PF_SCL			PF0
-#define PF_SDA			PF1
-
-#define I2C_INIT		(*pFIO_DIR |=  PF_SCL); asm("ssync;")
-#define I2C_ACTIVE		(*pFIO_DIR |=  PF_SDA); *pFIO_INEN &= ~PF_SDA; asm("ssync;")
-#define I2C_TRISTATE		(*pFIO_DIR &= ~PF_SDA); *pFIO_INEN |= PF_SDA; asm("ssync;")
-#define I2C_READ		((volatile)(*pFIO_FLAG_D & PF_SDA) != 0); asm("ssync;")
-#define I2C_SDA(bit)		if(bit) { \
-					*pFIO_FLAG_S = PF_SDA; \
-					asm("ssync;"); \
-					} \
-				else    { \
-					*pFIO_FLAG_C = PF_SDA; \
-					asm("ssync;"); \
-					}
-#define I2C_SCL(bit)		if(bit) { \
-					*pFIO_FLAG_S = PF_SCL; \
-					asm("ssync;"); \
-					} \
-				else    { \
-					*pFIO_FLAG_C = PF_SCL; \
-					asm("ssync;"); \
-					}
-#define I2C_DELAY		udelay(5)	/* 1/4 I2C clock duration */
-#endif
-
-#define CFG_I2C_SPEED		50000
-#define CFG_I2C_SLAVE		0xFE
-
 /* 0xFF, 0x7BB07BB0, 0x22547BB0 */
 /* #define AMGCTLVAL		(AMBEN_P0 | AMBEN_P1 | AMBEN_P2 | AMCKEN)
 #define AMBCTL0VAL		(B1WAT_7 | B1RAT_11 | B1HT_2 | B1ST_3 | B1TT_4 | ~B1RDYPOL | \
-- 
1.5.5





More information about the U-Boot mailing list