[U-Boot] [PATCH V3 01/25] mxc_i2c: fix i2c_imx_stop

Instead of clearing 2 bits, all the other bits were set because '|=' was used instead of '&='.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de Acked-by: Stefano Babic sbabic@denx.de
--- V2: add acks
V3: rename toggle to idle_bus in patches 17,18,24 and a rebase
Heiko, can you take 1-19 if no comments Stefano, can you take 20-23
24 and 25 will wait until both sets are in same tree
--- drivers/i2c/mxc_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index fc68062..c0c45fd 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -264,7 +264,7 @@ void i2c_imx_stop(void)
/* Stop I2C transaction */ temp = readb(&i2c_regs->i2cr); - temp |= ~(I2CR_MSTA | I2CR_MTX); + temp &= ~(I2CR_MSTA | I2CR_MTX); writeb(temp, &i2c_regs->i2cr);
i2c_imx_bus_busy(0);

This is always selected when CONFIG_I2C_MXC is selected, so it adds no value.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de
--- v2: add ack --- drivers/i2c/mxc_i2c.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index c0c45fd..0b46c9c 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -31,12 +31,9 @@ */
#include <common.h> -#include <asm/io.h> - -#if defined(CONFIG_HARD_I2C) - #include <asm/arch/clock.h> #include <asm/arch/imx-regs.h> +#include <asm/io.h> #include <i2c.h>
struct mxc_i2c_regs { @@ -446,4 +443,3 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
return ret; } -#endif /* CONFIG_HARD_I2C */

Use tx_byte function instead of having 3 copies of the code.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de
--- v2: add ack change ret to integer from unsigned --- drivers/i2c/mxc_i2c.c | 82 +++++++++++++++---------------------------------- 1 file changed, 24 insertions(+), 58 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 0b46c9c..d147dd5 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -33,6 +33,7 @@ #include <common.h> #include <asm/arch/clock.h> #include <asm/arch/imx-regs.h> +#include <asm/errno.h> #include <asm/io.h> #include <i2c.h>
@@ -207,17 +208,21 @@ int i2c_imx_trx_complete(void) udelay(1); }
- return 1; + return -ETIMEDOUT; }
-/* - * Check if the transaction was ACKed - */ -int i2c_imx_acked(void) +static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; + int ret;
- return readb(&i2c_regs->i2sr) & I2SR_RX_NO_AK; + writeb(byte, &i2c_regs->i2dr); + ret = i2c_imx_trx_complete(); + if (ret < 0) + return ret; + ret = readb(&i2c_regs->i2sr); + if (ret & I2SR_RX_NO_AK) + return -ENODEV; + return 0; }
/* @@ -271,30 +276,6 @@ void i2c_imx_stop(void) }
/* - * Set chip address and access mode - * - * read = 1: READ access - * read = 0: WRITE access - */ -int i2c_imx_set_chip_addr(uchar chip, int read) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - int ret; - - writeb((chip << 1) | read, &i2c_regs->i2dr); - - ret = i2c_imx_trx_complete(); - if (ret) - return ret; - - ret = i2c_imx_acked(); - if (ret) - return ret; - - return ret; -} - -/* * Write register address */ int i2c_imx_set_reg_addr(uint addr, int alen) @@ -303,14 +284,8 @@ int i2c_imx_set_reg_addr(uint addr, int alen) int ret = 0;
while (alen--) { - writeb((addr >> (alen * 8)) & 0xff, &i2c_regs->i2dr); - - ret = i2c_imx_trx_complete(); - if (ret) - break; - - ret = i2c_imx_acked(); - if (ret) + ret = tx_byte(i2c_regs, (addr >> (alen * 8)) & 0xff); + if (ret < 0) break; }
@@ -322,18 +297,15 @@ int i2c_imx_set_reg_addr(uint addr, int alen) */ int i2c_probe(uchar chip) { + struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; int ret;
ret = i2c_imx_start(); if (ret) return ret;
- ret = i2c_imx_set_chip_addr(chip, 0); - if (ret) - return ret; - + ret = tx_byte(i2c_regs, chip << 1); i2c_imx_stop(); - return ret; }
@@ -352,8 +324,8 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) return ret;
/* write slave address */ - ret = i2c_imx_set_chip_addr(chip, 0); - if (ret) + ret = tx_byte(i2c_regs, chip << 1); + if (ret < 0) return ret;
ret = i2c_imx_set_reg_addr(addr, alen); @@ -364,8 +336,8 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) temp |= I2CR_RSTA; writeb(temp, &i2c_regs->i2cr);
- ret = i2c_imx_set_chip_addr(chip, 1); - if (ret) + ret = tx_byte(i2c_regs, (chip << 1) | 1); + if (ret < 0) return ret;
/* setup bus to read data */ @@ -419,8 +391,8 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) return ret;
/* write slave address */ - ret = i2c_imx_set_chip_addr(chip, 0); - if (ret) + ret = tx_byte(i2c_regs, chip << 1); + if (ret < 0) return ret;
ret = i2c_imx_set_reg_addr(addr, alen); @@ -428,14 +400,8 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) return ret;
for (i = 0; i < len; i++) { - writeb(buf[i], &i2c_regs->i2dr); - - ret = i2c_imx_trx_complete(); - if (ret) - return ret; - - ret = i2c_imx_acked(); - if (ret) + ret = tx_byte(i2c_regs, buf[i]); + if (ret < 0) return ret; }

Let's clear the sr register before waiting for bit to be set, instead of clearing it after hardware sets it. No real operational difference here, but allows combining of i2c_imx_trx_complete and i2c_imx_bus_busy in later patches.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de
--- v2: add ack add clear of i2sr in i2c_read --- drivers/i2c/mxc_i2c.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index d147dd5..57027ad 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -200,10 +200,8 @@ int i2c_imx_trx_complete(void) int timeout = I2C_MAX_TIMEOUT;
while (timeout--) { - if (readb(&i2c_regs->i2sr) & I2SR_IIF) { - writeb(0, &i2c_regs->i2sr); + if (readb(&i2c_regs->i2sr) & I2SR_IIF) return 0; - }
udelay(1); } @@ -215,6 +213,7 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) { int ret;
+ writeb(0, &i2c_regs->i2sr); writeb(byte, &i2c_regs->i2dr); ret = i2c_imx_trx_complete(); if (ret < 0) @@ -346,7 +345,8 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) if (len == 1) temp |= I2CR_TX_NO_AK; writeb(temp, &i2c_regs->i2cr); - readb(&i2c_regs->i2dr); + writeb(0, &i2c_regs->i2sr); + readb(&i2c_regs->i2dr); /* dummy read to clear ICF */
/* read data */ for (i = 0; i < len; i++) { @@ -369,6 +369,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) writeb(temp, &i2c_regs->i2cr); }
+ writeb(0, &i2c_regs->i2sr); buf[i] = readb(&i2c_regs->i2dr); }

Initial code of i2c_read and i2c_write is identical, move to subroutine.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de Acked-by: Stefano Babic sbabic@denx.de
--- v2: add ack --- drivers/i2c/mxc_i2c.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 57027ad..4ce695a 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -275,19 +275,29 @@ void i2c_imx_stop(void) }
/* - * Write register address + * Send start signal, chip address and + * write register address */ -int i2c_imx_set_reg_addr(uint addr, int alen) +static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, + uchar chip, uint addr, int alen) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - int ret = 0; + int ret = i2c_imx_start(); + if (ret) + goto exit; + + /* write slave address */ + ret = tx_byte(i2c_regs, chip << 1); + if (ret < 0) + goto exit;
while (alen--) { ret = tx_byte(i2c_regs, (addr >> (alen * 8)) & 0xff); if (ret < 0) - break; + goto exit; } - + return 0; +exit: + i2c_imx_stop(); return ret; }
@@ -318,19 +328,10 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) unsigned int temp; int i;
- ret = i2c_imx_start(); - if (ret) - return ret; - - /* write slave address */ - ret = tx_byte(i2c_regs, chip << 1); + ret = i2c_init_transfer(i2c_regs, chip, addr, alen); if (ret < 0) return ret;
- ret = i2c_imx_set_reg_addr(addr, alen); - if (ret) - return ret; - temp = readb(&i2c_regs->i2cr); temp |= I2CR_RSTA; writeb(temp, &i2c_regs->i2cr); @@ -387,19 +388,10 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) int ret; int i;
- ret = i2c_imx_start(); - if (ret) - return ret; - - /* write slave address */ - ret = tx_byte(i2c_regs, chip << 1); + ret = i2c_init_transfer(i2c_regs, chip, addr, alen); if (ret < 0) return ret;
- ret = i2c_imx_set_reg_addr(addr, alen); - if (ret) - return ret; - for (i = 0; i < len; i++) { ret = tx_byte(i2c_regs, buf[i]); if (ret < 0)

Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com --- drivers/i2c/mxc_i2c.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 4ce695a..55a688a 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -337,8 +337,10 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) writeb(temp, &i2c_regs->i2cr);
ret = tx_byte(i2c_regs, (chip << 1) | 1); - if (ret < 0) + if (ret < 0) { + i2c_imx_stop(); return ret; + }
/* setup bus to read data */ temp = readb(&i2c_regs->i2cr); @@ -352,8 +354,10 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) /* read data */ for (i = 0; i < len; i++) { ret = i2c_imx_trx_complete(); - if (ret) + if (ret) { + i2c_imx_stop(); return ret; + }
/* * It must generate STOP before read I2DR to prevent @@ -395,7 +399,7 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) for (i = 0; i < len; i++) { ret = tx_byte(i2c_regs, buf[i]); if (ret < 0) - return ret; + break; }
i2c_imx_stop();

Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de Acked-by: Stefano Babic sbabic@denx.de
--- v2: add acks change comment --- --- drivers/i2c/mxc_i2c.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 55a688a..626e13e 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -302,23 +302,6 @@ exit: }
/* - * Try if a chip add given address responds (probe the chip) - */ -int i2c_probe(uchar chip) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - int ret; - - ret = i2c_imx_start(); - if (ret) - return ret; - - ret = tx_byte(i2c_regs, chip << 1); - i2c_imx_stop(); - return ret; -} - -/* * Read data from I2C device */ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) @@ -406,3 +389,11 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
return ret; } + +/* + * Test if a chip at a given address responds (probe the chip) + */ +int i2c_probe(uchar chip) +{ + return i2c_write(chip, 0, 0, NULL, 0); +}

Not using udelay gives a more accurate timeout. The current implementation of udelay in imx-common does not seem to wait at all for a udelay(1).
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de
---- V2: Added WATCHDOG_RESET as suggested by Marek Vasut add error message when stop fails
mxc_i2c: code i2c_probe as a 0 length i2c_write
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de Acked-by: Stefano Babic sbabic@denx.de
--- v2: add acks --- drivers/i2c/mxc_i2c.c | 80 ++++++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 51 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 626e13e..01a6408 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -36,6 +36,7 @@ #include <asm/errno.h> #include <asm/io.h> #include <i2c.h> +#include <watchdog.h>
struct mxc_i2c_regs { uint32_t iadr; @@ -63,8 +64,6 @@ struct mxc_i2c_regs { #error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver" #endif
-#define I2C_MAX_TIMEOUT 10000 - static u16 i2c_clk_div[50][2] = { { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, @@ -164,48 +163,26 @@ unsigned int i2c_get_bus_speed(void) return mxc_get_clock(MXC_IPG_PERCLK) / i2c_clk_div[clk_div][0]; }
-/* - * Wait for bus to be busy (or free if for_busy = 0) - * - * for_busy = 1: Wait for IBB to be asserted - * for_busy = 0: Wait for IBB to be de-asserted - */ -int i2c_imx_bus_busy(int for_busy) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - unsigned int temp; - - int timeout = I2C_MAX_TIMEOUT; - - while (timeout--) { - temp = readb(&i2c_regs->i2sr); - - if (for_busy && (temp & I2SR_IBB)) - return 0; - if (!for_busy && !(temp & I2SR_IBB)) - return 0; - - udelay(1); - } - - return 1; -} +#define ST_BUS_IDLE (0 | (I2SR_IBB << 8)) +#define ST_BUS_BUSY (I2SR_IBB | (I2SR_IBB << 8)) +#define ST_IIF (I2SR_IIF | (I2SR_IIF << 8))
-/* - * Wait for transaction to complete - */ -int i2c_imx_trx_complete(void) +static int wait_for_sr_state(struct mxc_i2c_regs *i2c_regs, unsigned state) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - int timeout = I2C_MAX_TIMEOUT; - - while (timeout--) { - if (readb(&i2c_regs->i2sr) & I2SR_IIF) - return 0; - - udelay(1); + unsigned sr; + ulong elapsed; + ulong start_time = get_timer(0); + for (;;) { + sr = readb(&i2c_regs->i2sr); + if ((sr & (state >> 8)) == (unsigned char)state) + return sr; + WATCHDOG_RESET(); + elapsed = get_timer(start_time); + if (elapsed > (CONFIG_SYS_HZ / 10)) /* .1 seconds */ + break; } - + printf("%s: failed sr=%x cr=%x state=%x\n", __func__, + sr, readb(&i2c_regs->i2cr), state); return -ETIMEDOUT; }
@@ -215,7 +192,7 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte)
writeb(0, &i2c_regs->i2sr); writeb(byte, &i2c_regs->i2dr); - ret = i2c_imx_trx_complete(); + ret = wait_for_sr_state(i2c_regs, ST_IIF); if (ret < 0) return ret; ret = readb(&i2c_regs->i2sr); @@ -245,8 +222,8 @@ int i2c_imx_start(void) temp |= I2CR_MSTA; writeb(temp, &i2c_regs->i2cr);
- result = i2c_imx_bus_busy(1); - if (result) + result = wait_for_sr_state(i2c_regs, ST_BUS_BUSY); + if (result < 0) return result;
temp |= I2CR_MTX | I2CR_TX_NO_AK; @@ -260,6 +237,7 @@ int i2c_imx_start(void) */ void i2c_imx_stop(void) { + int ret; struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; unsigned int temp = 0;
@@ -268,8 +246,9 @@ void i2c_imx_stop(void) temp &= ~(I2CR_MSTA | I2CR_MTX); writeb(temp, &i2c_regs->i2cr);
- i2c_imx_bus_busy(0); - + ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); + if (ret < 0) + printf("%s:trigger stop failed\n", __func__); /* Disable I2C controller */ writeb(0, &i2c_regs->i2cr); } @@ -336,8 +315,8 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
/* read data */ for (i = 0; i < len; i++) { - ret = i2c_imx_trx_complete(); - if (ret) { + ret = wait_for_sr_state(i2c_regs, ST_IIF); + if (ret < 0) { i2c_imx_stop(); return ret; } @@ -350,20 +329,19 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) temp = readb(&i2c_regs->i2cr); temp &= ~(I2CR_MSTA | I2CR_MTX); writeb(temp, &i2c_regs->i2cr); - i2c_imx_bus_busy(0); + wait_for_sr_state(i2c_regs, ST_BUS_IDLE); } else if (i == (len - 2)) { temp = readb(&i2c_regs->i2cr); temp |= I2CR_TX_NO_AK; writeb(temp, &i2c_regs->i2cr); } - writeb(0, &i2c_regs->i2sr); buf[i] = readb(&i2c_regs->i2dr); }
i2c_imx_stop();
- return ret; + return 0; }
/*

wait_for_sr_state returns i2sr on success so no need to read again.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de
--- v2: add ack --- drivers/i2c/mxc_i2c.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 01a6408..83c2fab 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -195,7 +195,6 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) ret = wait_for_sr_state(i2c_regs, ST_IIF); if (ret < 0) return ret; - ret = readb(&i2c_regs->i2sr); if (ret & I2SR_RX_NO_AK) return -ENODEV; return 0;

imx_start is only referenced once so move to that location.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de
--- v2: add ack --- drivers/i2c/mxc_i2c.c | 53 +++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 33 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 83c2fab..9efa9bd 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -201,37 +201,6 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) }
/* - * Start the controller - */ -int i2c_imx_start(void) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - unsigned int temp = 0; - int result; - - /* Enable I2C controller */ - writeb(0, &i2c_regs->i2sr); - writeb(I2CR_IEN, &i2c_regs->i2cr); - - /* Wait controller to be stable */ - udelay(50); - - /* Start I2C transaction */ - temp = readb(&i2c_regs->i2cr); - temp |= I2CR_MSTA; - writeb(temp, &i2c_regs->i2cr); - - result = wait_for_sr_state(i2c_regs, ST_BUS_BUSY); - if (result < 0) - return result; - - temp |= I2CR_MTX | I2CR_TX_NO_AK; - writeb(temp, &i2c_regs->i2cr); - - return 0; -} - -/* * Stop the controller */ void i2c_imx_stop(void) @@ -259,10 +228,28 @@ void i2c_imx_stop(void) static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, uchar chip, uint addr, int alen) { - int ret = i2c_imx_start(); - if (ret) + unsigned int temp; + int ret; + + /* Enable I2C controller */ + writeb(0, &i2c_regs->i2sr); + writeb(I2CR_IEN, &i2c_regs->i2cr); + + /* Wait for controller to be stable */ + udelay(50); + + /* Start I2C transaction */ + temp = readb(&i2c_regs->i2cr); + temp |= I2CR_MSTA; + writeb(temp, &i2c_regs->i2cr); + + ret = wait_for_sr_state(i2c_regs, ST_BUS_BUSY); + if (ret < 0) goto exit;
+ temp |= I2CR_MTX | I2CR_TX_NO_AK; + writeb(temp, &i2c_regs->i2cr); + /* write slave address */ ret = tx_byte(i2c_regs, chip << 1); if (ret < 0)

imx_reset is only referenced once so move to that location.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de
--- v2: add ack --- drivers/i2c/mxc_i2c.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 9efa9bd..717bc7a 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -114,17 +114,6 @@ static uint8_t i2c_imx_get_clk(unsigned int rate) }
/* - * Reset I2C Controller - */ -void i2c_reset(void) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - - writeb(0, &i2c_regs->i2cr); /* Reset module */ - writeb(0, &i2c_regs->i2sr); -} - -/* * Init I2C Bus */ void i2c_init(int speed, int unused) @@ -136,7 +125,9 @@ void i2c_init(int speed, int unused) /* Store divider value */ writeb(idx, &i2c_regs->ifdr);
- i2c_reset(); + /* Reset module */ + writeb(0, &i2c_regs->i2cr); + writeb(0, &i2c_regs->i2sr); }
/*

This helps in a multiple bus master environment which is why I also added a wait for bus idle.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: no change --- drivers/i2c/mxc_i2c.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 717bc7a..1a5e379 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -192,24 +192,19 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) }
/* - * Stop the controller + * Stop I2C transaction */ void i2c_imx_stop(void) { int ret; struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; - unsigned int temp = 0; + unsigned int temp = readb(&i2c_regs->i2cr);
- /* Stop I2C transaction */ - temp = readb(&i2c_regs->i2cr); temp &= ~(I2CR_MSTA | I2CR_MTX); writeb(temp, &i2c_regs->i2cr); - ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); if (ret < 0) printf("%s:trigger stop failed\n", __func__); - /* Disable I2C controller */ - writeb(0, &i2c_regs->i2cr); }
/* @@ -223,11 +218,15 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, int ret;
/* Enable I2C controller */ + if (!(readb(&i2c_regs->i2cr) & I2CR_IEN)) { + writeb(I2CR_IEN, &i2c_regs->i2cr); + /* Wait for controller to be stable */ + udelay(50); + } writeb(0, &i2c_regs->i2sr); - writeb(I2CR_IEN, &i2c_regs->i2cr); - - /* Wait for controller to be stable */ - udelay(50); + ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); + if (ret < 0) + goto exit;
/* Start I2C transaction */ temp = readb(&i2c_regs->i2cr); @@ -254,6 +253,8 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, return 0; exit: i2c_imx_stop(); + /* Disable I2C controller */ + writeb(0, &i2c_regs->i2cr); return ret; }
@@ -303,10 +304,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) * controller from generating another clock cycle */ if (i == (len - 1)) { - temp = readb(&i2c_regs->i2cr); - temp &= ~(I2CR_MSTA | I2CR_MTX); - writeb(temp, &i2c_regs->i2cr); - wait_for_sr_state(i2c_regs, ST_BUS_IDLE); + i2c_imx_stop(); } else if (i == (len - 2)) { temp = readb(&i2c_regs->i2cr); temp |= I2CR_TX_NO_AK;

The i2c controller cannot be both master and slave in the same transaction.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: no change --- drivers/i2c/mxc_i2c.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 1a5e379..ba2aad3 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -223,6 +223,8 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, /* Wait for controller to be stable */ udelay(50); } + if (readb(&i2c_regs->iadr) == (chip << 1)) + writeb((chip << 1) ^ 2, &i2c_regs->iadr); writeb(0, &i2c_regs->i2sr); ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); if (ret < 0)

No need to continue waiting if arbitration lost.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de
--- v2: add ack --- drivers/i2c/mxc_i2c.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index ba2aad3..093a73f 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -55,6 +55,7 @@ struct mxc_i2c_regs {
#define I2SR_ICF (1 << 7) #define I2SR_IBB (1 << 5) +#define I2SR_IAL (1 << 4) #define I2SR_IIF (1 << 1) #define I2SR_RX_NO_AK (1 << 0)
@@ -165,6 +166,12 @@ static int wait_for_sr_state(struct mxc_i2c_regs *i2c_regs, unsigned state) ulong start_time = get_timer(0); for (;;) { sr = readb(&i2c_regs->i2sr); + if (sr & I2SR_IAL) { + writeb(sr & ~I2SR_IAL, &i2c_regs->i2sr); + printf("%s: Arbitration lost sr=%x cr=%x state=%x\n", + __func__, sr, readb(&i2c_regs->i2cr), state); + return -ERESTART; + } if ((sr & (state >> 8)) == (unsigned char)state) return sr; WATCHDOG_RESET();

Retry unexpected hardware errors. This will not retry a received NAK.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: if i2c_init_transfer_ returns no error, then return 0 --- drivers/i2c/mxc_i2c.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 093a73f..cbb0fff 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -218,7 +218,7 @@ void i2c_imx_stop(void) * Send start signal, chip address and * write register address */ -static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, +static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs, uchar chip, uint addr, int alen) { unsigned int temp; @@ -235,7 +235,7 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, writeb(0, &i2c_regs->i2sr); ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); if (ret < 0) - goto exit; + return ret;
/* Start I2C transaction */ temp = readb(&i2c_regs->i2cr); @@ -244,7 +244,7 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs,
ret = wait_for_sr_state(i2c_regs, ST_BUS_BUSY); if (ret < 0) - goto exit; + return ret;
temp |= I2CR_MTX | I2CR_TX_NO_AK; writeb(temp, &i2c_regs->i2cr); @@ -252,18 +252,36 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, /* write slave address */ ret = tx_byte(i2c_regs, chip << 1); if (ret < 0) - goto exit; + return ret;
while (alen--) { ret = tx_byte(i2c_regs, (addr >> (alen * 8)) & 0xff); if (ret < 0) - goto exit; + return ret; } return 0; -exit: - i2c_imx_stop(); - /* Disable I2C controller */ - writeb(0, &i2c_regs->i2cr); +} + +static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, + uchar chip, uint addr, int alen) +{ + int retry; + int ret; + for (retry = 0; retry < 3; retry++) { + ret = i2c_init_transfer_(i2c_regs, chip, addr, alen); + if (ret >= 0) + return 0; + i2c_imx_stop(); + if (ret == -ENODEV) + return ret; + + printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip, + retry); + if (ret != -ERESTART) + writeb(0, &i2c_regs->i2cr); /* Disable controller */ + udelay(100); + } + printf("%s: give up i2c_regs=%p\n", __func__, i2c_regs); return ret; }

This is prep work for CONFIG_I2C_MULTI_BUS.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com Acked-by: Marek Vasut marex@denx.de
--- v2: add ack --- drivers/i2c/mxc_i2c.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index cbb0fff..44a04b5 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -201,10 +201,9 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) /* * Stop I2C transaction */ -void i2c_imx_stop(void) +static void i2c_imx_stop(struct mxc_i2c_regs *i2c_regs) { int ret; - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; unsigned int temp = readb(&i2c_regs->i2cr);
temp &= ~(I2CR_MSTA | I2CR_MTX); @@ -271,7 +270,7 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, ret = i2c_init_transfer_(i2c_regs, chip, addr, alen); if (ret >= 0) return 0; - i2c_imx_stop(); + i2c_imx_stop(i2c_regs); if (ret == -ENODEV) return ret;
@@ -305,7 +304,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
ret = tx_byte(i2c_regs, (chip << 1) | 1); if (ret < 0) { - i2c_imx_stop(); + i2c_imx_stop(i2c_regs); return ret; }
@@ -322,7 +321,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) for (i = 0; i < len; i++) { ret = wait_for_sr_state(i2c_regs, ST_IIF); if (ret < 0) { - i2c_imx_stop(); + i2c_imx_stop(i2c_regs); return ret; }
@@ -331,7 +330,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) * controller from generating another clock cycle */ if (i == (len - 1)) { - i2c_imx_stop(); + i2c_imx_stop(i2c_regs); } else if (i == (len - 2)) { temp = readb(&i2c_regs->i2cr); temp |= I2CR_TX_NO_AK; @@ -340,9 +339,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) writeb(0, &i2c_regs->i2sr); buf[i] = readb(&i2c_regs->i2dr); } - - i2c_imx_stop(); - + i2c_imx_stop(i2c_regs); return 0; }
@@ -364,9 +361,7 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) if (ret < 0) break; } - - i2c_imx_stop(); - + i2c_imx_stop(i2c_regs); return ret; }

Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: moved global data to static ram section available before ram is initialized and removed typedef as suggested by Marek Vasut and Heiko Schocher
make toggle_fn return int.
v3: rename toggle to idle_bus --- drivers/i2c/mxc_i2c.c | 125 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 104 insertions(+), 21 deletions(-)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 44a04b5..ead6e20 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -59,9 +59,7 @@ struct mxc_i2c_regs { #define I2SR_IIF (1 << 1) #define I2SR_RX_NO_AK (1 << 0)
-#ifdef CONFIG_SYS_I2C_BASE -#define I2C_BASE CONFIG_SYS_I2C_BASE -#else +#if defined(CONFIG_HARD_I2C) && !defined(CONFIG_SYS_I2C_BASE) #error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver" #endif
@@ -115,11 +113,11 @@ static uint8_t i2c_imx_get_clk(unsigned int rate) }
/* - * Init I2C Bus + * Set I2C Bus speed */ -void i2c_init(int speed, int unused) +int bus_i2c_set_bus_speed(void *base, int speed) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; + struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; u8 clk_idx = i2c_imx_get_clk(speed); u8 idx = i2c_clk_div[clk_idx][1];
@@ -129,23 +127,15 @@ void i2c_init(int speed, int unused) /* Reset module */ writeb(0, &i2c_regs->i2cr); writeb(0, &i2c_regs->i2sr); -} - -/* - * Set I2C Speed - */ -int i2c_set_bus_speed(unsigned int speed) -{ - i2c_init(speed, 0); return 0; }
/* * Get I2C Speed */ -unsigned int i2c_get_bus_speed(void) +unsigned int bus_i2c_get_bus_speed(void *base) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; + struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; u8 clk_idx = readb(&i2c_regs->ifdr); u8 clk_div;
@@ -287,12 +277,13 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, /* * Read data from I2C device */ -int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) +int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf, + int len) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; int ret; unsigned int temp; int i; + struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;
ret = i2c_init_transfer(i2c_regs, chip, addr, alen); if (ret < 0) @@ -346,11 +337,12 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) /* * Write data to I2C device */ -int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) +int bus_i2c_write(void *base, uchar chip, uint addr, int alen, + const uchar *buf, int len) { - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; int ret; int i; + struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;
ret = i2c_init_transfer(i2c_regs, chip, addr, alen); if (ret < 0) @@ -365,10 +357,101 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) return ret; }
+struct i2c_parms { + void *base; + void *idle_bus_data; + int (*idle_bus_fn)(void *p); +}; + +struct sram_data { + unsigned curr_i2c_bus; + struct i2c_parms i2c_data[3]; +}; + +/* + * For SPL boot some boards need i2c before SDRAM is initialized so force + * variables to live in SRAM + */ +static struct sram_data __attribute__((section(".data"))) srdata; + +void *get_base(void) +{ +#ifdef CONFIG_SYS_I2C_BASE +#ifdef CONFIG_I2C_MULTI_BUS + void *ret = srdata.i2c_data[srdata.curr_i2c_bus].base; + if (ret) + return ret; +#endif + return (void *)CONFIG_SYS_I2C_BASE; +#elif defined(CONFIG_I2C_MULTI_BUS) + return srdata.i2c_data[srdata.curr_i2c_bus].base; +#else + return srdata.i2c_data[0].base; +#endif +} + +int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + return bus_i2c_read(get_base(), chip, addr, alen, buf, len); +} + +int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + return bus_i2c_write(get_base(), chip, addr, alen, buf, len); +} + /* * Test if a chip at a given address responds (probe the chip) */ int i2c_probe(uchar chip) { - return i2c_write(chip, 0, 0, NULL, 0); + return bus_i2c_write(get_base(), chip, 0, 0, NULL, 0); +} + +void bus_i2c_init(void *base, int speed, int unused, + int (*idle_bus_fn)(void *p), void *idle_bus_data) +{ + int i = 0; + struct i2c_parms *p = srdata.i2c_data; + if (!base) + return; + for (;;) { + if (!p->base || (p->base == base)) { + p->base = base; + if (idle_bus_fn) { + p->idle_bus_fn = idle_bus_fn; + p->idle_bus_data = idle_bus_data; + } + break; + } + p++; + i++; + if (i >= ARRAY_SIZE(srdata.i2c_data)) + return; + } + bus_i2c_set_bus_speed(base, speed); +} + +/* + * Init I2C Bus + */ +void i2c_init(int speed, int unused) +{ + bus_i2c_init(get_base(), speed, unused, NULL, NULL); +} + +/* + * Set I2C Speed + */ +int i2c_set_bus_speed(unsigned int speed) +{ + return bus_i2c_set_bus_speed(get_base(), speed); +} + +/* + * Get I2C Speed + */ +unsigned int i2c_get_bus_speed(void) +{ + return bus_i2c_get_bus_speed(get_base()); }

Add support for calling a function that will toggle the SCL line to return the bus to idle condition.
The actual toggling function is added in a later patch.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: commit log change, global data in sram section. make toggle_i2c return int
v3: rename toggle to idle_bus --- drivers/i2c/mxc_i2c.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index ead6e20..c00ead1 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -251,6 +251,8 @@ static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs, return 0; }
+static int i2c_idle_bus(void *base); + static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, uchar chip, uint addr, int alen) { @@ -269,6 +271,8 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, if (ret != -ERESTART) writeb(0, &i2c_regs->i2cr); /* Disable controller */ udelay(100); + if (i2c_idle_bus(i2c_regs) < 0) + break; } printf("%s: give up i2c_regs=%p\n", __func__, i2c_regs); return ret; @@ -390,6 +394,28 @@ void *get_base(void) #endif }
+static struct i2c_parms *i2c_get_parms(void *base) +{ + int i = 0; + struct i2c_parms *p = srdata.i2c_data; + while (i < ARRAY_SIZE(srdata.i2c_data)) { + if (p->base == base) + return p; + p++; + i++; + } + printf("Invalid I2C base: %p\n", base); + return NULL; +} + +static int i2c_idle_bus(void *base) +{ + struct i2c_parms *p = i2c_get_parms(base); + if (p && p->idle_bus_fn) + return p->idle_bus_fn(p->idle_bus_data); + return 0; +} + int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) { return bus_i2c_read(get_base(), chip, addr, alen, buf, len);

Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: global data in sram section --- drivers/i2c/mxc_i2c.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index c00ead1..73d8958 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -416,6 +416,23 @@ static int i2c_idle_bus(void *base) return 0; }
+#ifdef CONFIG_I2C_MULTI_BUS +unsigned int i2c_get_bus_num(void) +{ + return srdata.curr_i2c_bus; +} + +int i2c_set_bus_num(unsigned bus_idx) +{ + if (bus_idx >= ARRAY_SIZE(srdata.i2c_data)) + return -1; + if (!srdata.i2c_data[bus_idx].base) + return -1; + srdata.curr_i2c_bus = bus_idx; + return 0; +} +#endif + int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) { return bus_i2c_read(get_base(), chip, addr, alen, buf, len);

This include is not needed.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: no change --- arch/arm/cpu/armv7/mx6/iomux-v3.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/mx6/iomux-v3.c b/arch/arm/cpu/armv7/mx6/iomux-v3.c index 8785532..a0c4b15 100644 --- a/arch/arm/cpu/armv7/mx6/iomux-v3.c +++ b/arch/arm/cpu/armv7/mx6/iomux-v3.c @@ -23,7 +23,6 @@ #include <common.h> #include <asm/io.h> #include <asm/arch/imx-regs.h> -#include <asm/arch/mx6x_pins.h> #include <asm/arch/iomux-v3.h>
static void *base = (void *)IOMUXC_BASE_ADDR;

-----Original Message----- From: Troy Kisky [mailto:troy.kisky@boundarydevices.com] Sent: Friday, July 20, 2012 2:18 AM To: u-boot@lists.denx.de; Heiko Schocher; sbabic@denx.de Cc: marek.vasut@gmail.com; dirk.behme@googlemail.com; Estevam Fabio- R49496; Liu Hui-R64343; Troy Kisky Subject: [PATCH V3 20/25] iomux-v3: remove include of mx6x_pins.h
This include is not needed.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
v2: no change
arch/arm/cpu/armv7/mx6/iomux-v3.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/arch/arm/cpu/armv7/mx6/iomux-v3.c b/arch/arm/cpu/armv7/mx6/iomux-v3.c index 8785532..a0c4b15 100644 --- a/arch/arm/cpu/armv7/mx6/iomux-v3.c +++ b/arch/arm/cpu/armv7/mx6/iomux-v3.c @@ -23,7 +23,6 @@ #include <common.h> #include <asm/io.h> #include <asm/arch/imx-regs.h> -#include <asm/arch/mx6x_pins.h> #include <asm/arch/iomux-v3.h>
static void *base = (void *)IOMUXC_BASE_ADDR;
Acked-by: Jason Liu r64343@freescale.com
-- 1.7.9.5

Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: no change --- arch/arm/cpu/armv7/mx6/iomux-v3.c | 2 +- arch/arm/include/asm/arch-mx6/mx6x_pins.h | 2 +- .../asm/{arch-mx6 => imx-common}/iomux-v3.h | 0 board/freescale/mx6qarm2/mx6qarm2.c | 2 +- board/freescale/mx6qsabrelite/mx6qsabrelite.c | 4 ++-- drivers/usb/host/ehci-mx6.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename arch/arm/include/asm/{arch-mx6 => imx-common}/iomux-v3.h (100%)
diff --git a/arch/arm/cpu/armv7/mx6/iomux-v3.c b/arch/arm/cpu/armv7/mx6/iomux-v3.c index a0c4b15..da093fb 100644 --- a/arch/arm/cpu/armv7/mx6/iomux-v3.c +++ b/arch/arm/cpu/armv7/mx6/iomux-v3.c @@ -23,7 +23,7 @@ #include <common.h> #include <asm/io.h> #include <asm/arch/imx-regs.h> -#include <asm/arch/iomux-v3.h> +#include <asm/imx-common/iomux-v3.h>
static void *base = (void *)IOMUXC_BASE_ADDR;
diff --git a/arch/arm/include/asm/arch-mx6/mx6x_pins.h b/arch/arm/include/asm/arch-mx6/mx6x_pins.h index cf9103c..3d66d64 100644 --- a/arch/arm/include/asm/arch-mx6/mx6x_pins.h +++ b/arch/arm/include/asm/arch-mx6/mx6x_pins.h @@ -22,7 +22,7 @@ #ifndef __ASM_ARCH_MX6_MX6X_PINS_H__ #define __ASM_ARCH_MX6_MX6X_PINS_H__
-#include <asm/arch/iomux-v3.h> +#include <asm/imx-common/iomux-v3.h>
/* Use to set PAD control */ #define PAD_CTL_HYS (1 << 16) diff --git a/arch/arm/include/asm/arch-mx6/iomux-v3.h b/arch/arm/include/asm/imx-common/iomux-v3.h similarity index 100% rename from arch/arm/include/asm/arch-mx6/iomux-v3.h rename to arch/arm/include/asm/imx-common/iomux-v3.h diff --git a/board/freescale/mx6qarm2/mx6qarm2.c b/board/freescale/mx6qarm2/mx6qarm2.c index 1367b88..340c4c4 100644 --- a/board/freescale/mx6qarm2/mx6qarm2.c +++ b/board/freescale/mx6qarm2/mx6qarm2.c @@ -24,9 +24,9 @@ #include <asm/io.h> #include <asm/arch/imx-regs.h> #include <asm/arch/mx6x_pins.h> -#include <asm/arch/iomux-v3.h> #include <asm/errno.h> #include <asm/gpio.h> +#include <asm/imx-common/iomux-v3.h> #include <mmc.h> #include <fsl_esdhc.h> #include <miiphy.h> diff --git a/board/freescale/mx6qsabrelite/mx6qsabrelite.c b/board/freescale/mx6qsabrelite/mx6qsabrelite.c index 0eae96d..34f65e9 100644 --- a/board/freescale/mx6qsabrelite/mx6qsabrelite.c +++ b/board/freescale/mx6qsabrelite/mx6qsabrelite.c @@ -22,12 +22,12 @@
#include <common.h> #include <asm/io.h> +#include <asm/arch/clock.h> #include <asm/arch/imx-regs.h> #include <asm/arch/mx6x_pins.h> -#include <asm/arch/iomux-v3.h> -#include <asm/arch/clock.h> #include <asm/errno.h> #include <asm/gpio.h> +#include <asm/imx-common/iomux-v3.h> #include <mmc.h> #include <fsl_esdhc.h> #include <micrel.h> diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index 42c77fe..0280242 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -22,7 +22,7 @@ #include <asm/arch/imx-regs.h> #include <asm/arch/clock.h> #include <asm/arch/mx6x_pins.h> -#include <asm/arch/iomux-v3.h> +#include <asm/imx-common/iomux-v3.h>
#include "ehci.h" #include "ehci-core.h"

Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com --- v2: no change --- arch/arm/cpu/armv7/imx-common/Makefile | 2 +- arch/arm/cpu/armv7/{mx6 => imx-common}/iomux-v3.c | 0 arch/arm/cpu/armv7/mx6/Makefile | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename arch/arm/cpu/armv7/{mx6 => imx-common}/iomux-v3.c (100%)
diff --git a/arch/arm/cpu/armv7/imx-common/Makefile b/arch/arm/cpu/armv7/imx-common/Makefile index e5ff375..53296fa 100644 --- a/arch/arm/cpu/armv7/imx-common/Makefile +++ b/arch/arm/cpu/armv7/imx-common/Makefile @@ -27,7 +27,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libimx-common.o
-COBJS = timer.o cpu.o speed.o +COBJS = iomux-v3.o timer.o cpu.o speed.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/arch/arm/cpu/armv7/mx6/iomux-v3.c b/arch/arm/cpu/armv7/imx-common/iomux-v3.c similarity index 100% rename from arch/arm/cpu/armv7/mx6/iomux-v3.c rename to arch/arm/cpu/armv7/imx-common/iomux-v3.c diff --git a/arch/arm/cpu/armv7/mx6/Makefile b/arch/arm/cpu/armv7/mx6/Makefile index b0da028..cbce411 100644 --- a/arch/arm/cpu/armv7/mx6/Makefile +++ b/arch/arm/cpu/armv7/mx6/Makefile @@ -27,7 +27,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).o
-COBJS = soc.o clock.o iomux-v3.o +COBJS = soc.o clock.o SOBJS = lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)

Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: no change --- arch/arm/include/asm/arch-mx5/imx-regs.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/include/asm/arch-mx5/imx-regs.h b/arch/arm/include/asm/arch-mx5/imx-regs.h index 88fb7cb..10f0ced 100644 --- a/arch/arm/include/asm/arch-mx5/imx-regs.h +++ b/arch/arm/include/asm/arch-mx5/imx-regs.h @@ -98,6 +98,7 @@ #define GPIO5_BASE_ADDR (AIPS1_BASE_ADDR + 0x000DC000) #define GPIO6_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E0000) #define GPIO7_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E4000) +#define I2C3_BASE_ADDR (AIPS1_BASE_ADDR + 0x000EC000) #define UART4_BASE_ADDR (AIPS1_BASE_ADDR + 0x000F0000) #endif /*

Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: do nothing if bus is already idle print failure message if appropriate change enable_i2c_clock to enable_i2c_clk clear non-idle bus before calling bus_i2c_init. wait .2 seconds for bus to clear before returning error fix compiler warnings
v3: rename toggle to idle_bus --- arch/arm/cpu/armv7/imx-common/Makefile | 4 +- arch/arm/cpu/armv7/imx-common/i2c.c | 99 +++++++++++++++++++++++++++++ arch/arm/cpu/armv7/mx5/clock.c | 20 ++++++ arch/arm/cpu/armv7/mx6/clock.c | 20 ++++++ arch/arm/include/asm/arch-mx5/clock.h | 1 + arch/arm/include/asm/arch-mx6/clock.h | 1 + arch/arm/include/asm/imx-common/mxc_i2c.h | 42 ++++++++++++ 7 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 arch/arm/cpu/armv7/imx-common/i2c.c create mode 100644 arch/arm/include/asm/imx-common/mxc_i2c.h
diff --git a/arch/arm/cpu/armv7/imx-common/Makefile b/arch/arm/cpu/armv7/imx-common/Makefile index 53296fa..bf36be5 100644 --- a/arch/arm/cpu/armv7/imx-common/Makefile +++ b/arch/arm/cpu/armv7/imx-common/Makefile @@ -27,7 +27,9 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libimx-common.o
-COBJS = iomux-v3.o timer.o cpu.o speed.o +COBJS-y = iomux-v3.o timer.o cpu.o speed.o +COBJS-$(CONFIG_I2C_MXC) += i2c.o +COBJS := $(sort $(COBJS-y))
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/arch/arm/cpu/armv7/imx-common/i2c.c b/arch/arm/cpu/armv7/imx-common/i2c.c new file mode 100644 index 0000000..da2b26f --- /dev/null +++ b/arch/arm/cpu/armv7/imx-common/i2c.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2012 Boundary Devices Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <asm/errno.h> +#include <asm/gpio.h> +#include <asm/imx-common/mxc_i2c.h> +#include <watchdog.h> + +static int force_idle_bus(void *priv) +{ + int i; + int sda, scl; + ulong elapsed, start_time; + struct i2c_pads_info *p = (struct i2c_pads_info *)priv; + int ret = 0; + + gpio_direction_input(p->sda.gp); + gpio_direction_input(p->scl.gp); + + imx_iomux_v3_setup_pad(p->sda.gpio_mode); + imx_iomux_v3_setup_pad(p->scl.gpio_mode); + + sda = gpio_get_value(p->sda.gp); + scl = gpio_get_value(p->scl.gp); + if ((sda & scl) == 1) + goto exit; /* Bus is idle already */ + + printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__, + sda, scl, p->sda.gp, p->scl.gp); + /* Send high and low on the SCL line */ + for (i = 0; i < 9; i++) { + gpio_direction_output(p->scl.gp, 0); + udelay(50); + gpio_direction_input(p->scl.gp); + udelay(50); + } + start_time = get_timer(0); + for (;;) { + sda = gpio_get_value(p->sda.gp); + scl = gpio_get_value(p->scl.gp); + if ((sda & scl) == 1) + break; + WATCHDOG_RESET(); + elapsed = get_timer(start_time); + if (elapsed > (CONFIG_SYS_HZ / 5)) { /* .2 seconds */ + ret = -EBUSY; + printf("%s: failed to clear bus, sda=%d scl=%d\n", + __func__, sda, scl); + break; + } + } +exit: + imx_iomux_v3_setup_pad(p->sda.i2c_mode); + imx_iomux_v3_setup_pad(p->scl.i2c_mode); + return ret; +} + +static void * const i2c_bases[] = { + (void *)I2C1_BASE_ADDR, + (void *)I2C2_BASE_ADDR, +#ifdef I2C3_BASE_ADDR + (void *)I2C3_BASE_ADDR, +#endif +}; + +/* i2c_index can be from 0 - 2 */ +void setup_i2c(unsigned i2c_index, int speed, int slave_addr, + struct i2c_pads_info *p) +{ + if (i2c_index >= ARRAY_SIZE(i2c_bases)) + return; + /* Enable i2c clock */ + enable_i2c_clk(1, i2c_index); + /* Make sure bus is idle */ + force_idle_bus(p); + bus_i2c_init(i2c_bases[i2c_index], speed, slave_addr, + force_idle_bus, p); +} diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c index 64862b3..c67c3cf 100644 --- a/arch/arm/cpu/armv7/mx5/clock.c +++ b/arch/arm/cpu/armv7/mx5/clock.c @@ -117,6 +117,26 @@ void enable_usboh3_clk(unsigned char enable) writel(reg, &mxc_ccm->CCGR2); }
+#ifdef CONFIG_I2C_MXC +/* i2c_num can be from 0 - 2 */ +int enable_i2c_clk(unsigned char enable, unsigned i2c_num) +{ + u32 reg; + u32 mask; + + if (i2c_num > 2) + return -EINVAL; + mask = MXC_CCM_CCGR_CG_MASK << ((i2c_num + 9) << 1); + reg = __raw_readl(&mxc_ccm->CCGR1); + if (enable) + reg |= mask; + else + reg &= ~mask; + __raw_writel(reg, &mxc_ccm->CCGR1); + return 0; +} +#endif + void set_usb_phy1_clk(void) { unsigned int reg; diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c index 52d5dc4..fddb373 100644 --- a/arch/arm/cpu/armv7/mx6/clock.c +++ b/arch/arm/cpu/armv7/mx6/clock.c @@ -50,6 +50,26 @@ void enable_usboh3_clk(unsigned char enable)
}
+#ifdef CONFIG_I2C_MXC +/* i2c_num can be from 0 - 2 */ +int enable_i2c_clk(unsigned char enable, unsigned i2c_num) +{ + u32 reg; + u32 mask; + + if (i2c_num > 2) + return -EINVAL; + mask = MXC_CCM_CCGR_CG_MASK << ((i2c_num + 3) << 1); + reg = __raw_readl(&imx_ccm->CCGR2); + if (enable) + reg |= mask; + else + reg &= ~mask; + __raw_writel(reg, &imx_ccm->CCGR2); + return 0; +} +#endif + static u32 decode_pll(enum pll_clocks pll, u32 infreq) { u32 div; diff --git a/arch/arm/include/asm/arch-mx5/clock.h b/arch/arm/include/asm/arch-mx5/clock.h index 35ee815..36ea030 100644 --- a/arch/arm/include/asm/arch-mx5/clock.h +++ b/arch/arm/include/asm/arch-mx5/clock.h @@ -49,5 +49,6 @@ void enable_usb_phy2_clk(unsigned char enable); void set_usboh3_clk(void); void enable_usboh3_clk(unsigned char enable); void mxc_set_sata_internal_clock(void); +int enable_i2c_clk(unsigned char enable, unsigned i2c_num);
#endif /* __ASM_ARCH_CLOCK_H */ diff --git a/arch/arm/include/asm/arch-mx6/clock.h b/arch/arm/include/asm/arch-mx6/clock.h index b91d8bf..c55c18d 100644 --- a/arch/arm/include/asm/arch-mx6/clock.h +++ b/arch/arm/include/asm/arch-mx6/clock.h @@ -48,5 +48,6 @@ u32 imx_get_fecclk(void); unsigned int mxc_get_clock(enum mxc_clock clk); void enable_usboh3_clk(unsigned char enable); int enable_sata_clock(void); +int enable_i2c_clk(unsigned char enable, unsigned i2c_num);
#endif /* __ASM_ARCH_CLOCK_H */ diff --git a/arch/arm/include/asm/imx-common/mxc_i2c.h b/arch/arm/include/asm/imx-common/mxc_i2c.h new file mode 100644 index 0000000..9a5187d --- /dev/null +++ b/arch/arm/include/asm/imx-common/mxc_i2c.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __ASM_ARCH_MXC_MXC_I2C_H__ +#define __ASM_ARCH_MXC_MXC_I2C_H__ +#include <asm/imx-common/iomux-v3.h> + +struct i2c_pin_ctrl { + iomux_v3_cfg_t i2c_mode; + iomux_v3_cfg_t gpio_mode; + unsigned char gp; + unsigned char spare; +}; + +struct i2c_pads_info { + struct i2c_pin_ctrl scl; + struct i2c_pin_ctrl sda; +}; + +void setup_i2c(unsigned i2c_index, int speed, int slave_addr, + struct i2c_pads_info *p); +void bus_i2c_init(void *base, int speed, int slave_addr, + int (*idle_bus_fn)(void *p), void *p); +int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf, + int len); +int bus_i2c_write(void *base, uchar chip, uint addr, int alen, + const uchar *buf, int len); +#endif

This includes bus recovery support.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
--- v2: no change --- board/freescale/mx6qsabrelite/mx6qsabrelite.c | 50 +++++++++++++++++++++++-- include/configs/mx6qsabrelite.h | 6 +-- 2 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/board/freescale/mx6qsabrelite/mx6qsabrelite.c b/board/freescale/mx6qsabrelite/mx6qsabrelite.c index 34f65e9..01e5083 100644 --- a/board/freescale/mx6qsabrelite/mx6qsabrelite.c +++ b/board/freescale/mx6qsabrelite/mx6qsabrelite.c @@ -28,6 +28,7 @@ #include <asm/errno.h> #include <asm/gpio.h> #include <asm/imx-common/iomux-v3.h> +#include <asm/imx-common/mxc_i2c.h> #include <mmc.h> #include <fsl_esdhc.h> #include <micrel.h> @@ -77,9 +78,48 @@ iomux_v3_cfg_t uart2_pads[] = { MX6Q_PAD_EIM_D27__UART2_RXD | MUX_PAD_CTRL(UART_PAD_CTRL), };
-iomux_v3_cfg_t i2c3_pads[] = { - MX6Q_PAD_GPIO_5__I2C3_SCL | MUX_PAD_CTRL(I2C_PAD_CTRL), - MX6Q_PAD_GPIO_16__I2C3_SDA | MUX_PAD_CTRL(I2C_PAD_CTRL), +#define PC MUX_PAD_CTRL(I2C_PAD_CTRL) + +/* I2C1, SGTL5000 */ +struct i2c_pads_info i2c_pad_info0 = { + .scl = { + .i2c_mode = MX6Q_PAD_EIM_D21__I2C1_SCL | PC, + .gpio_mode = MX6Q_PAD_EIM_D21__GPIO_3_21 | PC, + .gp = GPIO_NUMBER(3, 21) + }, + .sda = { + .i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC, + .gpio_mode = MX6Q_PAD_EIM_D28__GPIO_3_28 | PC, + .gp = GPIO_NUMBER(3, 28) + } +}; + +/* I2C2 Camera, MIPI */ +struct i2c_pads_info i2c_pad_info1 = { + .scl = { + .i2c_mode = MX6Q_PAD_KEY_COL3__I2C2_SCL | PC, + .gpio_mode = MX6Q_PAD_KEY_COL3__GPIO_4_12 | PC, + .gp = GPIO_NUMBER(4, 12) + }, + .sda = { + .i2c_mode = MX6Q_PAD_KEY_ROW3__I2C2_SDA | PC, + .gpio_mode = MX6Q_PAD_KEY_ROW3__GPIO_4_13 | PC, + .gp = GPIO_NUMBER(4, 13) + } +}; + +/* I2C3, J15 - RGB connector */ +struct i2c_pads_info i2c_pad_info2 = { + .scl = { + .i2c_mode = MX6Q_PAD_GPIO_5__I2C3_SCL | PC, + .gpio_mode = MX6Q_PAD_GPIO_5__GPIO_1_5 | PC, + .gp = GPIO_NUMBER(1, 5) + }, + .sda = { + .i2c_mode = MX6Q_PAD_GPIO_16__I2C3_SDA | PC, + .gpio_mode = MX6Q_PAD_GPIO_16__GPIO_7_11 | PC, + .gp = GPIO_NUMBER(7, 11) + } };
iomux_v3_cfg_t usdhc3_pads[] = { @@ -346,7 +386,9 @@ int board_init(void) #ifdef CONFIG_MXC_SPI setup_spi(); #endif - imx_iomux_v3_setup_multiple_pads(i2c3_pads, ARRAY_SIZE(i2c3_pads)); + setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info0); + setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1); + setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info2);
#ifdef CONFIG_CMD_SATA setup_sata(); diff --git a/include/configs/mx6qsabrelite.h b/include/configs/mx6qsabrelite.h index fbd10d6..beb8e3e 100644 --- a/include/configs/mx6qsabrelite.h +++ b/include/configs/mx6qsabrelite.h @@ -60,11 +60,9 @@
/* I2C Configs */ #define CONFIG_CMD_I2C -#define CONFIG_HARD_I2C +#define CONFIG_I2C_MULTI_BUS #define CONFIG_I2C_MXC -#define CONFIG_SYS_I2C_BASE I2C3_BASE_ADDR -#define CONFIG_SYS_I2C_SPEED 100000 -#define CONFIG_SYS_I2C_SLAVE 0xfe +#define CONFIG_SYS_I2C_SPEED 100000
/* MMC Configs */ #define CONFIG_FSL_ESDHC

-----Original Message----- From: Troy Kisky [mailto:troy.kisky@boundarydevices.com] Sent: Friday, July 20, 2012 2:18 AM To: u-boot@lists.denx.de; Heiko Schocher; sbabic@denx.de Cc: marek.vasut@gmail.com; dirk.behme@googlemail.com; Estevam Fabio- R49496; Liu Hui-R64343; Troy Kisky Subject: [PATCH V3 25/25] mx6qsabrelite: add i2c multi-bus support
This includes bus recovery support.
It’s better to give a short description about how to do the bus recovery with this patch.
Signed-off-by: Troy Kisky troy.kisky@boundarydevices.com
v2: no change
board/freescale/mx6qsabrelite/mx6qsabrelite.c | 50 +++++++++++++++++++++++-- include/configs/mx6qsabrelite.h | 6 +-- 2 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/board/freescale/mx6qsabrelite/mx6qsabrelite.c b/board/freescale/mx6qsabrelite/mx6qsabrelite.c index 34f65e9..01e5083 100644 --- a/board/freescale/mx6qsabrelite/mx6qsabrelite.c +++ b/board/freescale/mx6qsabrelite/mx6qsabrelite.c @@ -28,6 +28,7 @@ #include <asm/errno.h> #include <asm/gpio.h> #include <asm/imx-common/iomux-v3.h> +#include <asm/imx-common/mxc_i2c.h> #include <mmc.h> #include <fsl_esdhc.h> #include <micrel.h> @@ -77,9 +78,48 @@ iomux_v3_cfg_t uart2_pads[] = { MX6Q_PAD_EIM_D27__UART2_RXD | MUX_PAD_CTRL(UART_PAD_CTRL), };
-iomux_v3_cfg_t i2c3_pads[] = {
- MX6Q_PAD_GPIO_5__I2C3_SCL | MUX_PAD_CTRL(I2C_PAD_CTRL),
- MX6Q_PAD_GPIO_16__I2C3_SDA | MUX_PAD_CTRL(I2C_PAD_CTRL),
+#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
+/* I2C1, SGTL5000 */ +struct i2c_pads_info i2c_pad_info0 = {
- .scl = {
.i2c_mode = MX6Q_PAD_EIM_D21__I2C1_SCL | PC,
.gpio_mode = MX6Q_PAD_EIM_D21__GPIO_3_21 | PC,
.gp = GPIO_NUMBER(3, 21)
- },
- .sda = {
.i2c_mode = MX6Q_PAD_EIM_D28__I2C1_SDA | PC,
.gpio_mode = MX6Q_PAD_EIM_D28__GPIO_3_28 | PC,
.gp = GPIO_NUMBER(3, 28)
- }
+};
+/* I2C2 Camera, MIPI */ +struct i2c_pads_info i2c_pad_info1 = {
- .scl = {
.i2c_mode = MX6Q_PAD_KEY_COL3__I2C2_SCL | PC,
.gpio_mode = MX6Q_PAD_KEY_COL3__GPIO_4_12 | PC,
.gp = GPIO_NUMBER(4, 12)
- },
- .sda = {
.i2c_mode = MX6Q_PAD_KEY_ROW3__I2C2_SDA | PC,
.gpio_mode = MX6Q_PAD_KEY_ROW3__GPIO_4_13 | PC,
.gp = GPIO_NUMBER(4, 13)
- }
+};
+/* I2C3, J15 - RGB connector */ +struct i2c_pads_info i2c_pad_info2 = {
- .scl = {
.i2c_mode = MX6Q_PAD_GPIO_5__I2C3_SCL | PC,
.gpio_mode = MX6Q_PAD_GPIO_5__GPIO_1_5 | PC,
.gp = GPIO_NUMBER(1, 5)
- },
- .sda = {
.i2c_mode = MX6Q_PAD_GPIO_16__I2C3_SDA | PC,
.gpio_mode = MX6Q_PAD_GPIO_16__GPIO_7_11 | PC,
.gp = GPIO_NUMBER(7, 11)
- }
};
iomux_v3_cfg_t usdhc3_pads[] = { @@ -346,7 +386,9 @@ int board_init(void) #ifdef CONFIG_MXC_SPI setup_spi(); #endif
- imx_iomux_v3_setup_multiple_pads(i2c3_pads,
ARRAY_SIZE(i2c3_pads));
- setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info0);
- setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
- setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info2);
#ifdef CONFIG_CMD_SATA setup_sata(); diff --git a/include/configs/mx6qsabrelite.h b/include/configs/mx6qsabrelite.h index fbd10d6..beb8e3e 100644 --- a/include/configs/mx6qsabrelite.h +++ b/include/configs/mx6qsabrelite.h @@ -60,11 +60,9 @@
/* I2C Configs */ #define CONFIG_CMD_I2C -#define CONFIG_HARD_I2C +#define CONFIG_I2C_MULTI_BUS #define CONFIG_I2C_MXC -#define CONFIG_SYS_I2C_BASE I2C3_BASE_ADDR -#define CONFIG_SYS_I2C_SPEED 100000 -#define CONFIG_SYS_I2C_SLAVE 0xfe +#define CONFIG_SYS_I2C_SPEED 100000
Acked-by: Jason Liu r64343@freescale.com
/* MMC Configs */
#define CONFIG_FSL_ESDHC
1.7.9.5
participants (2)
-
Liu Hui-R64343
-
Troy Kisky