[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