From 8ec038a6a590c8ac66137502766ba10334c531e9 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Thu, 28 Jun 2012 04:30:22 +0000 Subject: i2c: deblock i2c bus also if accessed before realocation If we switch to a different i2c bus in changing the mux config for the i2c mux, we have to be sure to deblock the bus also before realocation. Signed-off-by: Holger Brunck cc: Heiko Schocher cc: Valentin Longchamp --- common/cmd_i2c.c | 1 + 1 file changed, 1 insertion(+) diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index 2cdc4eda8b5..795814d88f4 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -1445,6 +1445,7 @@ int i2c_mux_ident_muxstring_f (uchar *buf) oldpos = pos; } + i2c_init_board(); return 0; } -- cgit v1.3.1 From 1c076dba277fa35384b512841b0b284bdd579383 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:02 +0000 Subject: 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 Acked-by: Marek Vasut Acked-by: Stefano Babic --- 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 fc68062b118..c0c45fd36a1 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); -- cgit v1.3.1 From 24cd738bc420630f5362e2845a9f8aa4076273e5 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:03 +0000 Subject: mxc_i2c: remove ifdef of CONFIG_HARD_I2C This is always selected when CONFIG_I2C_MXC is selected, so it adds no value. Signed-off-by: Troy Kisky Acked-by: Marek Vasut --- 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 c0c45fd36a1..0b46c9c7aa4 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -31,12 +31,9 @@ */ #include -#include - -#if defined(CONFIG_HARD_I2C) - #include #include +#include #include 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 */ -- cgit v1.3.1 From cea60b0c6ce77a8dffd7177fca31fa7610aa6923 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:04 +0000 Subject: mxc_i2c: create tx_byte function Use tx_byte function instead of having 3 copies of the code. Signed-off-by: Troy Kisky Acked-by: Marek Vasut --- 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 0b46c9c7aa4..d147dd5f345 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -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; } /* @@ -270,30 +275,6 @@ void i2c_imx_stop(void) writeb(0, &i2c_regs->i2cr); } -/* - * 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 */ @@ -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; } -- cgit v1.3.1 From ea572d853eb03c6ac2021c21aae60891b5f92655 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:05 +0000 Subject: mxc_i2c: clear i2sr before waiting for bit 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 Acked-by: Marek Vasut --- 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 d147dd5f345..57027ad4db5 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); } -- cgit v1.3.1 From b230ddc267be2b9166421869549882d15b92e2ff Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:06 +0000 Subject: mxc_i2c: create i2c_init_transfer Initial code of i2c_read and i2c_write is identical, move to subroutine. Signed-off-by: Troy Kisky Acked-by: Marek Vasut Acked-by: Stefano Babic --- 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 57027ad4db5..4ce695a52d0 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) -- cgit v1.3.1 From c4330d283cefbd3574366e82910da3e918324b86 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:07 +0000 Subject: mxc_i2c: call i2c_imx_stop on error in i2c_read/i2c_write Signed-off-by: Troy Kisky --- 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 4ce695a52d0..55a688a8028 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(); -- cgit v1.3.1 From cfbb88d338f8a4ff5a0b165521ffc030efe72f31 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:08 +0000 Subject: mxc_i2c.c: code i2c_probe as a 0 length i2c_write Signed-off-by: Troy Kisky Acked-by: Marek Vasut Acked-by: Stefano Babic --- 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 55a688a8028..626e13eb11e 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -301,23 +301,6 @@ exit: return ret; } -/* - * 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 */ @@ -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); +} -- cgit v1.3.1 From 7aa57a01c0b5589c6f757b7a5106e09f9ba8fb10 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:09 +0000 Subject: mxc_i2c: combine i2c_imx_bus_busy and i2c_imx_trx_complete into wait_for_sr_state 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 Acked-by: Marek Vasut ---- 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 Acked-by: Marek Vasut Acked-by: Stefano Babic --- 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 626e13eb11e..01a64081d7e 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -36,6 +36,7 @@ #include #include #include +#include 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; } /* -- cgit v1.3.1 From d45e75b10cff8b388c9ec2e9fe3d4484bf1ba943 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:10 +0000 Subject: mxc_i2c: remove redundant read wait_for_sr_state returns i2sr on success so no need to read again. Signed-off-by: Troy Kisky Acked-by: Marek Vasut --- 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 01a64081d7e..83c2fab0897 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; -- cgit v1.3.1 From 71e9f3cbeb99ad696b2034748092dfc93f67bf73 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:11 +0000 Subject: mxc_i2c: place imx_start code inline imx_start is only referenced once so move to that location. Signed-off-by: Troy Kisky Acked-by: Marek Vasut --- 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 83c2fab0897..9efa9bdae54 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -200,37 +200,6 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) return 0; } -/* - * 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 */ @@ -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) -- cgit v1.3.1 From 83a1a19038b0bf36c966b7c7b67708e19b45c3b5 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:12 +0000 Subject: mxc_i2c: place i2c_reset code inline imx_reset is only referenced once so move to that location. Signed-off-by: Troy Kisky Acked-by: Marek Vasut --- 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 9efa9bdae54..717bc7ae015 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -113,17 +113,6 @@ static uint8_t i2c_imx_get_clk(unsigned int rate) return clk_div; } -/* - * 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 */ @@ -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); } /* -- cgit v1.3.1 From 90a5b70f5914a3ac79cac3dd386cc98ce42bfd8e Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:13 +0000 Subject: mxc_i2c: don't disable controller after every transaction This helps in a multiple bus master environment which is why I also added a wait for bus idle. Signed-off-by: Troy Kisky --- 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 717bc7ae015..1a5e379c2f1 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; -- cgit v1.3.1 From ca741da106de2b3d1432a333b3da0af6849c4e9a Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:14 +0000 Subject: mxc_i2c: change slave addr if conflicts with destination. The i2c controller cannot be both master and slave in the same transaction. Signed-off-by: Troy Kisky --- 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 1a5e379c2f1..ba2aad3d0dc 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) -- cgit v1.3.1 From d5383a63cd1286392a9792f3bd9e9b0d87e02171 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:15 +0000 Subject: mxc_i2c: check for arbitration lost No need to continue waiting if arbitration lost. Signed-off-by: Troy Kisky Acked-by: Marek Vasut --- 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 ba2aad3d0dc..093a73f1c52 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(); -- cgit v1.3.1 From a7f1a0051078052cb81ba1ff5985b908f39cefd5 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:16 +0000 Subject: mxc_i2c: add retries Retry unexpected hardware errors. This will not retry a received NAK. Signed-off-by: Troy Kisky --- 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 093a73f1c52..cbb0fffb85c 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; } -- cgit v1.3.1 From 27a5da02c094c9b73c01aa699f13591b824d5436 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:17 +0000 Subject: mxc_i2c: add i2c_regs argument to i2c_imx_stop This is prep work for CONFIG_I2C_MULTI_BUS. Signed-off-by: Troy Kisky Acked-by: Marek Vasut --- 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 cbb0fffb85c..44a04b57d64 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; } -- cgit v1.3.1 From e4ff525f91f813456cf42a29227ee4a0fe01788b Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:18 +0000 Subject: mxc_i2c: prep work for multiple busses support Signed-off-by: Troy Kisky --- 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 44a04b57d64..ead6e209b25 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()); } -- cgit v1.3.1 From 96c19bd3ef45394acd846d561657bba4c1dc613f Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:19 +0000 Subject: mxc_i2c: add bus recovery support 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 --- 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 ead6e209b25..c00ead1f56b 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); -- cgit v1.3.1 From 9815326d043b08f7ad355e53b8b7027634507879 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:20 +0000 Subject: mxc_i2c: finish adding CONFIG_I2C_MULTI_BUS support Signed-off-by: Troy Kisky --- 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 c00ead1f56b..73d89587019 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); -- cgit v1.3.1 From d3394ec198f107a11a21402cbb3bd34b843a40ed Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:21 +0000 Subject: iomux-v3: remove include of mx6x_pins.h This include is not needed. Signed-off-by: Troy Kisky Acked-by: Jason Liu --- 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 87855321635..a0c4b1567e1 100644 --- a/arch/arm/cpu/armv7/mx6/iomux-v3.c +++ b/arch/arm/cpu/armv7/mx6/iomux-v3.c @@ -23,7 +23,6 @@ #include #include #include -#include #include static void *base = (void *)IOMUXC_BASE_ADDR; -- cgit v1.3.1 From af2a35fb1f432c78e6181172ff4df34d37ff5154 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:22 +0000 Subject: i.mx: iomux-v3.h: move to imx-common include directory Signed-off-by: Troy Kisky --- arch/arm/cpu/armv7/mx6/iomux-v3.c | 2 +- arch/arm/include/asm/arch-mx6/iomux-v3.h | 214 -------------------------- arch/arm/include/asm/arch-mx6/mx6x_pins.h | 2 +- arch/arm/include/asm/imx-common/iomux-v3.h | 214 ++++++++++++++++++++++++++ board/freescale/mx6qarm2/mx6qarm2.c | 2 +- board/freescale/mx6qsabrelite/mx6qsabrelite.c | 4 +- drivers/usb/host/ehci-mx6.c | 2 +- 7 files changed, 220 insertions(+), 220 deletions(-) delete mode 100644 arch/arm/include/asm/arch-mx6/iomux-v3.h create mode 100644 arch/arm/include/asm/imx-common/iomux-v3.h diff --git a/arch/arm/cpu/armv7/mx6/iomux-v3.c b/arch/arm/cpu/armv7/mx6/iomux-v3.c index a0c4b1567e1..da093fbe148 100644 --- a/arch/arm/cpu/armv7/mx6/iomux-v3.c +++ b/arch/arm/cpu/armv7/mx6/iomux-v3.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include static void *base = (void *)IOMUXC_BASE_ADDR; diff --git a/arch/arm/include/asm/arch-mx6/iomux-v3.h b/arch/arm/include/asm/arch-mx6/iomux-v3.h deleted file mode 100644 index 788b413219c..00000000000 --- a/arch/arm/include/asm/arch-mx6/iomux-v3.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Based on Linux i.MX iomux-v3.h file: - * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH, - * - * - * Copyright (C) 2011 Freescale Semiconductor, Inc. - * - * 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 __MACH_IOMUX_V3_H__ -#define __MACH_IOMUX_V3_H__ - -/* - * build IOMUX_PAD structure - * - * This iomux scheme is based around pads, which are the physical balls - * on the processor. - * - * - Each pad has a pad control register (IOMUXC_SW_PAD_CTRL_x) which controls - * things like driving strength and pullup/pulldown. - * - Each pad can have but not necessarily does have an output routing register - * (IOMUXC_SW_MUX_CTL_PAD_x). - * - Each pad can have but not necessarily does have an input routing register - * (IOMUXC_x_SELECT_INPUT) - * - * The three register sets do not have a fixed offset to each other, - * hence we order this table by pad control registers (which all pads - * have) and put the optional i/o routing registers into additional - * fields. - * - * The naming convention for the pad modes is SOC_PAD___ - * If or refers to a GPIO, it is named GPIO__ - * - * IOMUX/PAD Bit field definitions - * - * MUX_CTRL_OFS: 0..11 (12) - * PAD_CTRL_OFS: 12..23 (12) - * SEL_INPUT_OFS: 24..35 (12) - * MUX_MODE + SION: 36..40 (5) - * PAD_CTRL + NO_PAD_CTRL: 41..58 (18) - * SEL_INP: 59..62 (4) - * reserved: 63 (1) -*/ - -typedef u64 iomux_v3_cfg_t; - -#define MUX_CTRL_OFS_SHIFT 0 -#define MUX_CTRL_OFS_MASK ((iomux_v3_cfg_t)0xfff << MUX_CTRL_OFS_SHIFT) -#define MUX_PAD_CTRL_OFS_SHIFT 12 -#define MUX_PAD_CTRL_OFS_MASK ((iomux_v3_cfg_t)0xfff << \ - MUX_PAD_CTRL_OFS_SHIFT) -#define MUX_SEL_INPUT_OFS_SHIFT 24 -#define MUX_SEL_INPUT_OFS_MASK ((iomux_v3_cfg_t)0xfff << \ - MUX_SEL_INPUT_OFS_SHIFT) - -#define MUX_MODE_SHIFT 36 -#define MUX_MODE_MASK ((iomux_v3_cfg_t)0x1f << MUX_MODE_SHIFT) -#define MUX_PAD_CTRL_SHIFT 41 -#define MUX_PAD_CTRL_MASK ((iomux_v3_cfg_t)0x3ffff << MUX_PAD_CTRL_SHIFT) -#define MUX_SEL_INPUT_SHIFT 59 -#define MUX_SEL_INPUT_MASK ((iomux_v3_cfg_t)0xf << MUX_SEL_INPUT_SHIFT) - -#define MUX_PAD_CTRL(x) ((iomux_v3_cfg_t)(x) << MUX_PAD_CTRL_SHIFT) - -#define IOMUX_PAD(pad_ctrl_ofs, mux_ctrl_ofs, mux_mode, sel_input_ofs, \ - sel_input, pad_ctrl) \ - (((iomux_v3_cfg_t)(mux_ctrl_ofs) << MUX_CTRL_OFS_SHIFT) | \ - ((iomux_v3_cfg_t)(mux_mode) << MUX_MODE_SHIFT) | \ - ((iomux_v3_cfg_t)(pad_ctrl_ofs) << MUX_PAD_CTRL_OFS_SHIFT) | \ - ((iomux_v3_cfg_t)(pad_ctrl) << MUX_PAD_CTRL_SHIFT) | \ - ((iomux_v3_cfg_t)(sel_input_ofs) << MUX_SEL_INPUT_OFS_SHIFT)| \ - ((iomux_v3_cfg_t)(sel_input) << MUX_SEL_INPUT_SHIFT)) - -#define NO_PAD_CTRL (1 << 17) -#define GPIO_PIN_MASK 0x1f -#define GPIO_PORT_SHIFT 5 -#define GPIO_PORT_MASK (0x7 << GPIO_PORT_SHIFT) -#define GPIO_PORTA (0 << GPIO_PORT_SHIFT) -#define GPIO_PORTB (1 << GPIO_PORT_SHIFT) -#define GPIO_PORTC (2 << GPIO_PORT_SHIFT) -#define GPIO_PORTD (3 << GPIO_PORT_SHIFT) -#define GPIO_PORTE (4 << GPIO_PORT_SHIFT) -#define GPIO_PORTF (5 << GPIO_PORT_SHIFT) - -#define MUX_CONFIG_SION (0x1 << 4) - -int imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad); -int imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t *pad_list, unsigned count); - -/* - * IOMUXC_GPR13 bit fields - */ -#define IOMUXC_GPR13_SDMA_STOP_REQ (1<<30) -#define IOMUXC_GPR13_CAN2_STOP_REQ (1<<29) -#define IOMUXC_GPR13_CAN1_STOP_REQ (1<<28) -#define IOMUXC_GPR13_ENET_STOP_REQ (1<<27) -#define IOMUXC_GPR13_SATA_PHY_8_MASK (7<<24) -#define IOMUXC_GPR13_SATA_PHY_7_MASK (0x1f<<19) -#define IOMUXC_GPR13_SATA_PHY_6_SHIFT 16 -#define IOMUXC_GPR13_SATA_PHY_6_MASK (7< +#include /* Use to set PAD control */ #define PAD_CTL_HYS (1 << 16) diff --git a/arch/arm/include/asm/imx-common/iomux-v3.h b/arch/arm/include/asm/imx-common/iomux-v3.h new file mode 100644 index 00000000000..788b413219c --- /dev/null +++ b/arch/arm/include/asm/imx-common/iomux-v3.h @@ -0,0 +1,214 @@ +/* + * Based on Linux i.MX iomux-v3.h file: + * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH, + * + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * + * 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 __MACH_IOMUX_V3_H__ +#define __MACH_IOMUX_V3_H__ + +/* + * build IOMUX_PAD structure + * + * This iomux scheme is based around pads, which are the physical balls + * on the processor. + * + * - Each pad has a pad control register (IOMUXC_SW_PAD_CTRL_x) which controls + * things like driving strength and pullup/pulldown. + * - Each pad can have but not necessarily does have an output routing register + * (IOMUXC_SW_MUX_CTL_PAD_x). + * - Each pad can have but not necessarily does have an input routing register + * (IOMUXC_x_SELECT_INPUT) + * + * The three register sets do not have a fixed offset to each other, + * hence we order this table by pad control registers (which all pads + * have) and put the optional i/o routing registers into additional + * fields. + * + * The naming convention for the pad modes is SOC_PAD___ + * If or refers to a GPIO, it is named GPIO__ + * + * IOMUX/PAD Bit field definitions + * + * MUX_CTRL_OFS: 0..11 (12) + * PAD_CTRL_OFS: 12..23 (12) + * SEL_INPUT_OFS: 24..35 (12) + * MUX_MODE + SION: 36..40 (5) + * PAD_CTRL + NO_PAD_CTRL: 41..58 (18) + * SEL_INP: 59..62 (4) + * reserved: 63 (1) +*/ + +typedef u64 iomux_v3_cfg_t; + +#define MUX_CTRL_OFS_SHIFT 0 +#define MUX_CTRL_OFS_MASK ((iomux_v3_cfg_t)0xfff << MUX_CTRL_OFS_SHIFT) +#define MUX_PAD_CTRL_OFS_SHIFT 12 +#define MUX_PAD_CTRL_OFS_MASK ((iomux_v3_cfg_t)0xfff << \ + MUX_PAD_CTRL_OFS_SHIFT) +#define MUX_SEL_INPUT_OFS_SHIFT 24 +#define MUX_SEL_INPUT_OFS_MASK ((iomux_v3_cfg_t)0xfff << \ + MUX_SEL_INPUT_OFS_SHIFT) + +#define MUX_MODE_SHIFT 36 +#define MUX_MODE_MASK ((iomux_v3_cfg_t)0x1f << MUX_MODE_SHIFT) +#define MUX_PAD_CTRL_SHIFT 41 +#define MUX_PAD_CTRL_MASK ((iomux_v3_cfg_t)0x3ffff << MUX_PAD_CTRL_SHIFT) +#define MUX_SEL_INPUT_SHIFT 59 +#define MUX_SEL_INPUT_MASK ((iomux_v3_cfg_t)0xf << MUX_SEL_INPUT_SHIFT) + +#define MUX_PAD_CTRL(x) ((iomux_v3_cfg_t)(x) << MUX_PAD_CTRL_SHIFT) + +#define IOMUX_PAD(pad_ctrl_ofs, mux_ctrl_ofs, mux_mode, sel_input_ofs, \ + sel_input, pad_ctrl) \ + (((iomux_v3_cfg_t)(mux_ctrl_ofs) << MUX_CTRL_OFS_SHIFT) | \ + ((iomux_v3_cfg_t)(mux_mode) << MUX_MODE_SHIFT) | \ + ((iomux_v3_cfg_t)(pad_ctrl_ofs) << MUX_PAD_CTRL_OFS_SHIFT) | \ + ((iomux_v3_cfg_t)(pad_ctrl) << MUX_PAD_CTRL_SHIFT) | \ + ((iomux_v3_cfg_t)(sel_input_ofs) << MUX_SEL_INPUT_OFS_SHIFT)| \ + ((iomux_v3_cfg_t)(sel_input) << MUX_SEL_INPUT_SHIFT)) + +#define NO_PAD_CTRL (1 << 17) +#define GPIO_PIN_MASK 0x1f +#define GPIO_PORT_SHIFT 5 +#define GPIO_PORT_MASK (0x7 << GPIO_PORT_SHIFT) +#define GPIO_PORTA (0 << GPIO_PORT_SHIFT) +#define GPIO_PORTB (1 << GPIO_PORT_SHIFT) +#define GPIO_PORTC (2 << GPIO_PORT_SHIFT) +#define GPIO_PORTD (3 << GPIO_PORT_SHIFT) +#define GPIO_PORTE (4 << GPIO_PORT_SHIFT) +#define GPIO_PORTF (5 << GPIO_PORT_SHIFT) + +#define MUX_CONFIG_SION (0x1 << 4) + +int imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad); +int imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t *pad_list, unsigned count); + +/* + * IOMUXC_GPR13 bit fields + */ +#define IOMUXC_GPR13_SDMA_STOP_REQ (1<<30) +#define IOMUXC_GPR13_CAN2_STOP_REQ (1<<29) +#define IOMUXC_GPR13_CAN1_STOP_REQ (1<<28) +#define IOMUXC_GPR13_ENET_STOP_REQ (1<<27) +#define IOMUXC_GPR13_SATA_PHY_8_MASK (7<<24) +#define IOMUXC_GPR13_SATA_PHY_7_MASK (0x1f<<19) +#define IOMUXC_GPR13_SATA_PHY_6_SHIFT 16 +#define IOMUXC_GPR13_SATA_PHY_6_MASK (7< #include #include -#include #include #include +#include #include #include #include diff --git a/board/freescale/mx6qsabrelite/mx6qsabrelite.c b/board/freescale/mx6qsabrelite/mx6qsabrelite.c index 0eae96d3a37..34f65e98e47 100644 --- a/board/freescale/mx6qsabrelite/mx6qsabrelite.c +++ b/board/freescale/mx6qsabrelite/mx6qsabrelite.c @@ -22,12 +22,12 @@ #include #include +#include #include #include -#include -#include #include #include +#include #include #include #include diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index 42c77fe333d..028024298d3 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include "ehci.h" #include "ehci-core.h" -- cgit v1.3.1 From 18c0ad27c1e75e0a4695bb293cf8e3849538c36f Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:23 +0000 Subject: i.mx: iomux-v3.c: move to imx-common directory Signed-off-by: Troy Kisky --- arch/arm/cpu/armv7/imx-common/Makefile | 2 +- arch/arm/cpu/armv7/imx-common/iomux-v3.c | 70 ++++++++++++++++++++++++++++++++ arch/arm/cpu/armv7/mx6/Makefile | 2 +- arch/arm/cpu/armv7/mx6/iomux-v3.c | 70 -------------------------------- 4 files changed, 72 insertions(+), 72 deletions(-) create mode 100644 arch/arm/cpu/armv7/imx-common/iomux-v3.c delete mode 100644 arch/arm/cpu/armv7/mx6/iomux-v3.c diff --git a/arch/arm/cpu/armv7/imx-common/Makefile b/arch/arm/cpu/armv7/imx-common/Makefile index e5ff375c12e..53296fa2301 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/imx-common/iomux-v3.c b/arch/arm/cpu/armv7/imx-common/iomux-v3.c new file mode 100644 index 00000000000..da093fbe148 --- /dev/null +++ b/arch/arm/cpu/armv7/imx-common/iomux-v3.c @@ -0,0 +1,70 @@ +/* + * Based on the iomux-v3.c from Linux kernel: + * Copyright (C) 2008 by Sascha Hauer + * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH, + * + * + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. + * + * 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. + */ +#include +#include +#include +#include + +static void *base = (void *)IOMUXC_BASE_ADDR; + +/* + * configures a single pad in the iomuxer + */ +int imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad) +{ + u32 mux_ctrl_ofs = (pad & MUX_CTRL_OFS_MASK) >> MUX_CTRL_OFS_SHIFT; + u32 mux_mode = (pad & MUX_MODE_MASK) >> MUX_MODE_SHIFT; + u32 sel_input_ofs = + (pad & MUX_SEL_INPUT_OFS_MASK) >> MUX_SEL_INPUT_OFS_SHIFT; + u32 sel_input = + (pad & MUX_SEL_INPUT_MASK) >> MUX_SEL_INPUT_SHIFT; + u32 pad_ctrl_ofs = + (pad & MUX_PAD_CTRL_OFS_MASK) >> MUX_PAD_CTRL_OFS_SHIFT; + u32 pad_ctrl = (pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT; + + if (mux_ctrl_ofs) + __raw_writel(mux_mode, base + mux_ctrl_ofs); + + if (sel_input_ofs) + __raw_writel(sel_input, base + sel_input_ofs); + + if (!(pad_ctrl & NO_PAD_CTRL) && pad_ctrl_ofs) + __raw_writel(pad_ctrl, base + pad_ctrl_ofs); + + return 0; +} + +int imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t *pad_list, unsigned count) +{ + iomux_v3_cfg_t *p = pad_list; + int i; + int ret; + + for (i = 0; i < count; i++) { + ret = imx_iomux_v3_setup_pad(*p); + if (ret) + return ret; + p++; + } + return 0; +} diff --git a/arch/arm/cpu/armv7/mx6/Makefile b/arch/arm/cpu/armv7/mx6/Makefile index b0da028da6a..cbce411cca6 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) diff --git a/arch/arm/cpu/armv7/mx6/iomux-v3.c b/arch/arm/cpu/armv7/mx6/iomux-v3.c deleted file mode 100644 index da093fbe148..00000000000 --- a/arch/arm/cpu/armv7/mx6/iomux-v3.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Based on the iomux-v3.c from Linux kernel: - * Copyright (C) 2008 by Sascha Hauer - * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH, - * - * - * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. - * - * 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. - */ -#include -#include -#include -#include - -static void *base = (void *)IOMUXC_BASE_ADDR; - -/* - * configures a single pad in the iomuxer - */ -int imx_iomux_v3_setup_pad(iomux_v3_cfg_t pad) -{ - u32 mux_ctrl_ofs = (pad & MUX_CTRL_OFS_MASK) >> MUX_CTRL_OFS_SHIFT; - u32 mux_mode = (pad & MUX_MODE_MASK) >> MUX_MODE_SHIFT; - u32 sel_input_ofs = - (pad & MUX_SEL_INPUT_OFS_MASK) >> MUX_SEL_INPUT_OFS_SHIFT; - u32 sel_input = - (pad & MUX_SEL_INPUT_MASK) >> MUX_SEL_INPUT_SHIFT; - u32 pad_ctrl_ofs = - (pad & MUX_PAD_CTRL_OFS_MASK) >> MUX_PAD_CTRL_OFS_SHIFT; - u32 pad_ctrl = (pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT; - - if (mux_ctrl_ofs) - __raw_writel(mux_mode, base + mux_ctrl_ofs); - - if (sel_input_ofs) - __raw_writel(sel_input, base + sel_input_ofs); - - if (!(pad_ctrl & NO_PAD_CTRL) && pad_ctrl_ofs) - __raw_writel(pad_ctrl, base + pad_ctrl_ofs); - - return 0; -} - -int imx_iomux_v3_setup_multiple_pads(iomux_v3_cfg_t *pad_list, unsigned count) -{ - iomux_v3_cfg_t *p = pad_list; - int i; - int ret; - - for (i = 0; i < count; i++) { - ret = imx_iomux_v3_setup_pad(*p); - if (ret) - return ret; - p++; - } - return 0; -} -- cgit v1.3.1 From df369dcdb05729304761748856a2513d9ddac272 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:24 +0000 Subject: i.mx53: add definition for I2C3_BASE_ADDR Signed-off-by: Troy Kisky --- 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 8117f4f91ae..7f66b61b3c8 100644 --- a/arch/arm/include/asm/arch-mx5/imx-regs.h +++ b/arch/arm/include/asm/arch-mx5/imx-regs.h @@ -96,6 +96,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 /* -- cgit v1.3.1 From cc54a0f7cccf976d350801d39c406e75465ebdd1 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:25 +0000 Subject: imx-common: add i2c.c for bus recovery support Signed-off-by: Troy Kisky --- 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 53296fa2301..bf36be57673 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 00000000000..da2b26f43f4 --- /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 +#include +#include +#include +#include +#include +#include + +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 64862b31f1f..c67c3cfc483 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 52d5dc4d90b..fddb3733ae2 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 35ee8155de9..36ea03082fa 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 b91d8bf4502..c55c18d51ba 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 00000000000..9a5187d4648 --- /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 + +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 -- cgit v1.3.1 From 9c06782863a9add2e75e940cf375ebb44a273212 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 19 Jul 2012 08:18:26 +0000 Subject: mx6qsabrelite: add i2c multi-bus support This includes bus recovery support. Signed-off-by: Troy Kisky Acked-by: Jason Liu --- 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 34f65e98e47..01e508354aa 100644 --- a/board/freescale/mx6qsabrelite/mx6qsabrelite.c +++ b/board/freescale/mx6qsabrelite/mx6qsabrelite.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -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 e42fe6b00b4..0d376ba5cf6 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 -- cgit v1.3.1 From 989feb8c52aa2ba5914b14ce04fd49e99a555f38 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 23 Jul 2012 21:23:48 +0000 Subject: EXYNOS: CLK: Add i2c clock This adds i2c clock information for EXYNOS5. Signed-off-by: Alim Akhtar Signed-off-by: Doug Anderson Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass --- arch/arm/cpu/armv7/exynos/clock.c | 33 +++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/clk.h | 1 + 2 files changed, 34 insertions(+) diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 330bd75da9a..f7829b2cc76 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -578,6 +578,29 @@ void exynos4_set_mipi_clk(void) writel(cfg, &clk->div_lcd0); } +/* + * I2C + * + * exynos5: obtaining the I2C clock + */ +static unsigned long exynos5_get_i2c_clk(void) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + unsigned long aclk_66, aclk_66_pre, sclk; + unsigned int ratio; + + sclk = get_pll_clk(MPLL); + + ratio = (readl(&clk->div_top1)) >> 24; + ratio &= 0x7; + aclk_66_pre = sclk / (ratio + 1); + ratio = readl(&clk->div_top0); + ratio &= 0x7; + aclk_66 = aclk_66_pre / (ratio + 1); + return aclk_66; +} + unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) @@ -594,6 +617,16 @@ unsigned long get_arm_clk(void) return exynos4_get_arm_clk(); } +unsigned long get_i2c_clk(void) +{ + if (cpu_is_exynos5()) { + return exynos5_get_i2c_clk(); + } else { + debug("I2C clock is not set for this CPU\n"); + return 0; + } +} + unsigned long get_pwm_clk(void) { if (cpu_is_exynos5()) diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 637fb4bd145..72dc655ec1d 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -30,6 +30,7 @@ unsigned long get_pll_clk(int pllreg); unsigned long get_arm_clk(void); +unsigned long get_i2c_clk(void); unsigned long get_pwm_clk(void); unsigned long get_uart_clk(int dev_index); void set_mmc_clk(int dev_index, unsigned int div); -- cgit v1.3.1 From 1a758aec3d4b9bf8e545fa29dcb3c75662ab399c Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 23 Jul 2012 21:23:49 +0000 Subject: EXYNOS: Add I2C base address. This patch adds the base address for I2C. Signed-off-by: Alim Akhtar Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass --- arch/arm/include/asm/arch-exynos/cpu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index 0c341d4318d..ab46b70f302 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -49,6 +49,7 @@ #define EXYNOS4_USB_HOST_EHCI_BASE 0x12580000 #define EXYNOS4_USBPHY_BASE 0x125B0000 #define EXYNOS4_UART_BASE 0x13800000 +#define EXYNOS4_I2C_BASE 0x13860000 #define EXYNOS4_ADC_BASE 0x13910000 #define EXYNOS4_PWMTIMER_BASE 0x139D0000 #define EXYNOS4_MODEM_BASE 0x13A00000 @@ -76,6 +77,7 @@ #define EXYNOS5_MMC_BASE 0x12200000 #define EXYNOS5_SROMC_BASE 0x12250000 #define EXYNOS5_UART_BASE 0x12C00000 +#define EXYNOS5_I2C_BASE 0x12C60000 #define EXYNOS5_PWMTIMER_BASE 0x12DD0000 #define EXYNOS5_GPIO_PART2_BASE 0x13400000 #define EXYNOS5_FIMD_BASE 0x14400000 @@ -148,6 +150,7 @@ SAMSUNG_BASE(adc, ADC_BASE) SAMSUNG_BASE(clock, CLOCK_BASE) SAMSUNG_BASE(sysreg, SYSREG_BASE) SAMSUNG_BASE(fimd, FIMD_BASE) +SAMSUNG_BASE(i2c, I2C_BASE) SAMSUNG_BASE(mipi_dsim, MIPI_DSIM_BASE) SAMSUNG_BASE(gpio_part1, GPIO_PART1_BASE) SAMSUNG_BASE(gpio_part2, GPIO_PART2_BASE) -- cgit v1.3.1 From 8da3eb1b22f881b72a934b34bf97659f2d1502f0 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 23 Jul 2012 21:23:50 +0000 Subject: EXYNOS5: define EXYNOS5_I2C_SPACING This patch defined EXYNOS5_I2C_SPACING used to calculate I2C channel base address. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass --- arch/arm/include/asm/arch-exynos/cpu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index ab46b70f302..0e6ea870798 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -58,6 +58,8 @@ #define EXYNOS4_GPIO_PART4_BASE DEVICE_NOT_AVAILABLE /* EXYNOS5 */ +#define EXYNOS5_I2C_SPACING 0x10000 + #define EXYNOS5_GPIO_PART4_BASE 0x03860000 #define EXYNOS5_PRO_ID 0x10000000 #define EXYNOS5_CLOCK_BASE 0x10010000 -- cgit v1.3.1 From c65c05f57f0ea98c3397dfd41c3bfa29252256f2 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 23 Jul 2012 21:23:51 +0000 Subject: EXYNOS: PINMUX: Add pinmux support for I2C This patch adds pinmux code for I2C. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass --- arch/arm/cpu/armv7/exynos/pinmux.c | 52 +++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/periph.h | 8 +++++ 2 files changed, 60 insertions(+) diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index d2b7d2cba7f..d28f05557fe 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -184,6 +184,48 @@ static void exynos5_sromc_config(int flags) } } +static void exynos5_i2c_config(int peripheral, int flags) +{ + + struct exynos5_gpio_part1 *gpio1 = + (struct exynos5_gpio_part1 *) samsung_get_base_gpio_part1(); + + switch (peripheral) { + case PERIPH_ID_I2C0: + s5p_gpio_cfg_pin(&gpio1->b3, 0, GPIO_FUNC(0x2)); + s5p_gpio_cfg_pin(&gpio1->b3, 1, GPIO_FUNC(0x2)); + break; + case PERIPH_ID_I2C1: + s5p_gpio_cfg_pin(&gpio1->b3, 2, GPIO_FUNC(0x2)); + s5p_gpio_cfg_pin(&gpio1->b3, 3, GPIO_FUNC(0x2)); + break; + case PERIPH_ID_I2C2: + s5p_gpio_cfg_pin(&gpio1->a0, 6, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->a0, 7, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C3: + s5p_gpio_cfg_pin(&gpio1->a1, 2, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->a1, 3, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C4: + s5p_gpio_cfg_pin(&gpio1->a2, 0, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->a2, 1, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C5: + s5p_gpio_cfg_pin(&gpio1->a2, 2, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->a2, 3, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C6: + s5p_gpio_cfg_pin(&gpio1->b1, 3, GPIO_FUNC(0x4)); + s5p_gpio_cfg_pin(&gpio1->b1, 4, GPIO_FUNC(0x4)); + break; + case PERIPH_ID_I2C7: + s5p_gpio_cfg_pin(&gpio1->b2, 2, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->b2, 3, GPIO_FUNC(0x3)); + break; + } +} + static int exynos5_pinmux_config(int peripheral, int flags) { switch (peripheral) { @@ -201,6 +243,16 @@ static int exynos5_pinmux_config(int peripheral, int flags) case PERIPH_ID_SROMC: exynos5_sromc_config(flags); break; + case PERIPH_ID_I2C0: + case PERIPH_ID_I2C1: + case PERIPH_ID_I2C2: + case PERIPH_ID_I2C3: + case PERIPH_ID_I2C4: + case PERIPH_ID_I2C5: + case PERIPH_ID_I2C6: + case PERIPH_ID_I2C7: + exynos5_i2c_config(peripheral, flags); + break; default: debug("%s: invalid peripheral %d", __func__, peripheral); return -1; diff --git a/arch/arm/include/asm/arch-exynos/periph.h b/arch/arm/include/asm/arch-exynos/periph.h index 5db25aa88a7..b861d7d5842 100644 --- a/arch/arm/include/asm/arch-exynos/periph.h +++ b/arch/arm/include/asm/arch-exynos/periph.h @@ -30,6 +30,14 @@ * */ enum periph_id { + PERIPH_ID_I2C0, + PERIPH_ID_I2C1, + PERIPH_ID_I2C2, + PERIPH_ID_I2C3, + PERIPH_ID_I2C4, + PERIPH_ID_I2C5, + PERIPH_ID_I2C6, + PERIPH_ID_I2C7, PERIPH_ID_SDMMC0, PERIPH_ID_SDMMC1, PERIPH_ID_SDMMC2, -- cgit v1.3.1 From 91dffb16ffd047458982f70f5cb18c864473a462 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 23 Jul 2012 21:23:52 +0000 Subject: I2C: Move struct s3c24x0_i2c to a common place. struct s3c24x0_i2c is being moved to common local header file so that the same can be used by s3c series and exynos series SoCs. Signed-off-by: Alim Akhtar Signed-off-by: Doug Anderson Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass --- arch/arm/include/asm/arch-s3c24x0/s3c24x0.h | 10 --------- drivers/i2c/s3c24x0_i2c.h | 33 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 drivers/i2c/s3c24x0_i2c.h diff --git a/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h b/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h index ca978c9bbcc..0f75c311f5a 100644 --- a/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h +++ b/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h @@ -343,16 +343,6 @@ struct s3c24x0_watchdog { u32 wtcnt; }; - -/* IIC (see manual chapter 20) */ -struct s3c24x0_i2c { - u32 iiccon; - u32 iicstat; - u32 iicadd; - u32 iicds; -}; - - /* IIS (see manual chapter 21) */ struct s3c24x0_i2s { #ifdef __BIG_ENDIAN diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h new file mode 100644 index 00000000000..2dd4b06a232 --- /dev/null +++ b/drivers/i2c/s3c24x0_i2c.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * 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 + */ + +#ifndef _S3C24X0_I2C_H +#define _S3C24X0_I2C_H + +struct s3c24x0_i2c { + u32 iiccon; + u32 iicstat; + u32 iicadd; + u32 iicds; + u32 iiclc; +}; +#endif /* _S3C24X0_I2C_H */ -- cgit v1.3.1 From ab7e52bb240c15ad4426cad64396589beadc9f04 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 23 Jul 2012 21:23:53 +0000 Subject: I2C: Modify the I2C driver for EXYNOS5 This patch modifies the S3C I2C driver to suppport EXYNOS5. The cahnges made to driver are as follows: - I2C base address is passed as a parameter to many functions to avoid multiple #ifdef - Channel initialisation is moved to a commom funation as it is required by i2c_init. - Hardcoding for I2CCON_ACKGEN removed. - Replaced printf with debug. - Checkpatch issues resolved. - Pinmux setting will be done in board/samsung/smdk5250/smdk5250.c to avoid repeated setting of gpio lines, as it have multi bus support. Signed-off-by: Alim Akhtar Signed-off-by: Doug Anderson Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass --- drivers/i2c/s3c24x0_i2c.c | 194 ++++++++++++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 77 deletions(-) diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index ba6f39bee11..26c075513d7 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,10 +27,15 @@ */ #include +#ifdef CONFIG_EXYNOS5 +#include +#include +#else #include - +#endif #include #include +#include "s3c24x0_i2c.h" #ifdef CONFIG_HARD_I2C @@ -45,6 +50,7 @@ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ +#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ #define I2CCON_IRPND 0x10 /* Interrupt pending bit */ #define I2C_MODE_MT 0xC0 /* Master Transmit Mode */ #define I2C_MODE_MR 0x80 /* Master Receive Mode */ @@ -53,6 +59,10 @@ #define I2C_TIMEOUT 1 /* 1 second */ + +static unsigned int g_current_bus; /* Stores Current I2C Bus */ + +#ifndef CONFIG_EXYNOS5 static int GetI2CSDA(void) { struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); @@ -77,16 +87,17 @@ static void SetI2CSCL(int x) struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); #ifdef CONFIG_S3C2410 - writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat); + writel((readl(&gpio->gpedat) & ~0x4000) | + (x & 1) << 14, &gpio->gpedat); #endif #ifdef CONFIG_S3C2400 writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat); #endif } +#endif -static int WaitForXfer(void) +static int WaitForXfer(struct s3c24x0_i2c *i2c) { - struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); int i; i = I2C_TIMEOUT * 10000; @@ -98,35 +109,75 @@ static int WaitForXfer(void) return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; } -static int IsACK(void) +static int IsACK(struct s3c24x0_i2c *i2c) { - struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); - return !(readl(&i2c->iicstat) & I2CSTAT_NACK); } -static void ReadWriteByte(void) +static void ReadWriteByte(struct s3c24x0_i2c *i2c) { - struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); - writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); } +static struct s3c24x0_i2c *get_base_i2c(void) +{ +#ifdef CONFIG_EXYNOS5 + struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c() + + (EXYNOS5_I2C_SPACING + * g_current_bus)); + return i2c; +#else + return s3c24x0_get_base_i2c(); +#endif +} + +static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) +{ + ulong freq, pres = 16, div; +#ifdef CONFIG_EXYNOS5 + freq = get_i2c_clk(); +#else + freq = get_PCLK(); +#endif + /* calculate prescaler and divisor values */ + if ((freq / pres / (16 + 1)) > speed) + /* set prescaler to 512 */ + pres = 512; + + div = 0; + while ((freq / pres / (div + 1)) > speed) + div++; + + /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */ + writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon); + + /* init to SLAVE REVEIVE and set slaveaddr */ + writel(0, &i2c->iicstat); + writel(slaveadd, &i2c->iicadd); + /* program Master Transmit (and implicit STOP) */ + writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); +} + void i2c_init(int speed, int slaveadd) { - struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); + struct s3c24x0_i2c *i2c; +#ifndef CONFIG_EXYNOS5 struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); - ulong freq, pres = 16, div; +#endif int i; - /* wait for some time to give previous transfer a chance to finish */ + /* By default i2c channel 0 is the current bus */ + g_current_bus = 0; + i2c = get_base_i2c(); + /* wait for some time to give previous transfer a chance to finish */ i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) && I2CSTAT_BSY) && (i > 0)) { + while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { udelay(1000); i--; } +#ifndef CONFIG_EXYNOS5 if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) { #ifdef CONFIG_S3C2410 ulong old_gpecon = readl(&gpio->gpecon); @@ -170,27 +221,8 @@ void i2c_init(int speed, int slaveadd) writel(old_gpecon, &gpio->pgcon); #endif } - - /* calculate prescaler and divisor values */ - freq = get_PCLK(); - if ((freq / pres / (16 + 1)) > speed) - /* set prescaler to 512 */ - pres = 512; - - div = 0; - while ((freq / pres / (div + 1)) > speed) - div++; - - /* set prescaler, divisor according to freq, also set - * ACKGEN, IRQ */ - writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon); - - /* init to SLAVE REVEIVE and set slaveaddr */ - writel(0, &i2c->iicstat); - writel(slaveadd, &i2c->iicadd); - /* program Master Transmit (and implicit STOP) */ - writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); - +#endif /* #ifndef CONFIG_EXYNOS5 */ + i2c_ch_init(i2c, speed, slaveadd); } /* @@ -200,19 +232,19 @@ void i2c_init(int speed, int slaveadd) * by the char, we could make it larger if needed. If it is * 0 we skip the address write cycle. */ -static -int i2c_transfer(unsigned char cmd_type, - unsigned char chip, - unsigned char addr[], - unsigned char addr_len, - unsigned char data[], unsigned short data_len) +static int i2c_transfer(struct s3c24x0_i2c *i2c, + unsigned char cmd_type, + unsigned char chip, + unsigned char addr[], + unsigned char addr_len, + unsigned char data[], + unsigned short data_len) { - struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c(); int i, result; if (data == 0 || data_len == 0) { /*Don't support data transfer of no length or to address 0 */ - printf("i2c_transfer: bad call\n"); + debug("i2c_transfer: bad call\n"); return I2C_NOK; } @@ -226,7 +258,7 @@ int i2c_transfer(unsigned char cmd_type, if (readl(&i2c->iicstat) & I2CSTAT_BSY) return I2C_NOK_TOUT; - writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon); + writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon); result = I2C_OK; switch (cmd_type) { @@ -238,16 +270,16 @@ int i2c_transfer(unsigned char cmd_type, &i2c->iicstat); i = 0; while ((i < addr_len) && (result == I2C_OK)) { - result = WaitForXfer(); + result = WaitForXfer(i2c); writel(addr[i], &i2c->iicds); - ReadWriteByte(); + ReadWriteByte(i2c); i++; } i = 0; while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer(); + result = WaitForXfer(i2c); writel(data[i], &i2c->iicds); - ReadWriteByte(); + ReadWriteByte(i2c); i++; } } else { @@ -257,19 +289,19 @@ int i2c_transfer(unsigned char cmd_type, &i2c->iicstat); i = 0; while ((i < data_len) && (result = I2C_OK)) { - result = WaitForXfer(); + result = WaitForXfer(i2c); writel(data[i], &i2c->iicds); - ReadWriteByte(); + ReadWriteByte(i2c); i++; } } if (result == I2C_OK) - result = WaitForXfer(); + result = WaitForXfer(i2c); /* send STOP */ writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(); + ReadWriteByte(i2c); break; case I2C_READ: @@ -279,13 +311,13 @@ int i2c_transfer(unsigned char cmd_type, /* send START */ writel(readl(&i2c->iicstat) | I2C_START_STOP, &i2c->iicstat); - result = WaitForXfer(); - if (IsACK()) { + result = WaitForXfer(i2c); + if (IsACK(i2c)) { i = 0; while ((i < addr_len) && (result == I2C_OK)) { writel(addr[i], &i2c->iicds); - ReadWriteByte(); - result = WaitForXfer(); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); i++; } @@ -293,16 +325,17 @@ int i2c_transfer(unsigned char cmd_type, /* resend START */ writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP, &i2c->iicstat); - ReadWriteByte(); - result = WaitForXfer(); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); i = 0; while ((i < data_len) && (result == I2C_OK)) { /* disable ACK for final READ */ if (i == data_len - 1) writel(readl(&i2c->iiccon) - & ~0x80, &i2c->iiccon); - ReadWriteByte(); - result = WaitForXfer(); + & ~I2CCON_ACKGEN, + &i2c->iiccon); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); data[i] = readl(&i2c->iicds); i++; } @@ -316,17 +349,18 @@ int i2c_transfer(unsigned char cmd_type, /* send START */ writel(readl(&i2c->iicstat) | I2C_START_STOP, &i2c->iicstat); - result = WaitForXfer(); + result = WaitForXfer(i2c); - if (IsACK()) { + if (IsACK(i2c)) { i = 0; while ((i < data_len) && (result == I2C_OK)) { /* disable ACK for final READ */ if (i == data_len - 1) writel(readl(&i2c->iiccon) & - ~0x80, &i2c->iiccon); - ReadWriteByte(); - result = WaitForXfer(); + ~I2CCON_ACKGEN, + &i2c->iiccon); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); data[i] = readl(&i2c->iicds); i++; } @@ -337,22 +371,24 @@ int i2c_transfer(unsigned char cmd_type, /* send STOP */ writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(); + ReadWriteByte(i2c); break; default: - printf("i2c_transfer: bad call\n"); + debug("i2c_transfer: bad call\n"); result = I2C_NOK; break; } - return (result); + return result; } int i2c_probe(uchar chip) { + struct s3c24x0_i2c *i2c; uchar buf[1]; + i2c = get_base_i2c(); buf[0] = 0; /* @@ -360,16 +396,17 @@ int i2c_probe(uchar chip) * address was ed (i.e. there was a chip at that address which * drove the data line low). */ - return i2c_transfer(I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; + return i2c_transfer(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; } int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { + struct s3c24x0_i2c *i2c; uchar xaddr[4]; int ret; if (alen > 4) { - printf("I2C read: addr len %d not supported\n", alen); + debug("I2C read: addr len %d not supported\n", alen); return 1; } @@ -396,10 +433,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); #endif - if ((ret = - i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen, - buffer, len)) != 0) { - printf("I2c read: failed %d\n", ret); + i2c = get_base_i2c(); + ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen, + buffer, len); + if (ret != 0) { + debug("I2c read: failed %d\n", ret); return 1; } return 0; @@ -407,10 +445,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { + struct s3c24x0_i2c *i2c; uchar xaddr[4]; if (alen > 4) { - printf("I2C write: addr len %d not supported\n", alen); + debug("I2C write: addr len %d not supported\n", alen); return 1; } @@ -436,8 +475,9 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); #endif + i2c = get_base_i2c(); return (i2c_transfer - (I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, + (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, len) != 0); } #endif /* CONFIG_HARD_I2C */ -- cgit v1.3.1 From 178239de194a0e84d07b8e48fb74cb156f654d75 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 23 Jul 2012 21:23:54 +0000 Subject: I2C: Add support for Multi channel This adds multiple i2c channel support for I2C. Signed-off-by: Alim Akhtar Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass --- drivers/i2c/s3c24x0_i2c.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 26c075513d7..9bc4c7f1d1c 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -158,6 +158,33 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); } +/* + * MULTI BUS I2C support + */ + +#ifdef CONFIG_I2C_MULTI_BUS +int i2c_set_bus_num(unsigned int bus) +{ + struct s3c24x0_i2c *i2c; + + if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { + debug("Bad bus: %d\n", bus); + return -1; + } + + g_current_bus = bus; + i2c = get_base_i2c(); + i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + return 0; +} + +unsigned int i2c_get_bus_num(void) +{ + return g_current_bus; +} +#endif + void i2c_init(int speed, int slaveadd) { struct s3c24x0_i2c *i2c; -- cgit v1.3.1 From c82b050ead18081a594a66c913124b4e5e6c004c Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 23 Jul 2012 21:23:55 +0000 Subject: CONFIG: SMDK5250: I2C: Enable I2C This enables I2C support on smdk5250. Pinmux setting moved to board file to avoid repeated setting of gpio lines. Signed-off-by: Alim Akhtar Signed-off-by: Doug Anderson Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass --- board/samsung/smdk5250/smdk5250.c | 30 +++++++++++++++++++++++++++++- include/configs/smdk5250.h | 10 ++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index 3b078da65d8..fae7d6f0ed6 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -172,9 +173,36 @@ static int board_uart_init(void) return 0; } +#ifdef CONFIG_SYS_I2C_INIT_BOARD +static int board_i2c_init(void) +{ + int i, err; + + for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) { + err = exynos_pinmux_config((PERIPH_ID_I2C0 + i), + PINMUX_FLAG_NONE); + if (err) { + debug("I2C%d not configured\n", (PERIPH_ID_I2C0 + i)); + return err; + } + } + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + return 0; +} +#endif + #ifdef CONFIG_BOARD_EARLY_INIT_F int board_early_init_f(void) { - return board_uart_init(); + int err; + err = board_uart_init(); + if (err) { + debug("UART init failed\n"); + return err; + } +#ifdef CONFIG_SYS_I2C_INIT_BOARD + err = board_i2c_init(); +#endif + return err; } #endif diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h index d47881bcb27..eb1466c52bd 100644 --- a/include/configs/smdk5250.h +++ b/include/configs/smdk5250.h @@ -193,6 +193,16 @@ #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_LOAD_ADDR - 0x1000000) +/* I2C */ +#define CONFIG_SYS_I2C_INIT_BOARD +#define CONFIG_HARD_I2C +#define CONFIG_CMD_I2C +#define CONFIG_SYS_I2C_SPEED 100000 /* 100 Kbps */ +#define CONFIG_DRIVER_S3C24X0_I2C +#define CONFIG_I2C_MULTI_BUS +#define CONFIG_MAX_I2C_NUM 8 +#define CONFIG_SYS_I2C_SLAVE 0x0 + /* Ethernet Controllor Driver */ #ifdef CONFIG_CMD_NET #define CONFIG_SMC911X -- cgit v1.3.1 From e69e482bbf16795539af112d6a21d4ddaee35105 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Fri, 27 Jul 2012 04:58:13 +0000 Subject: km/common: remove printfs for i2c deblocking code This code will also be used before reallocation and during this time we are not allowed to do these printings. Signed-off-by: Holger Brunck Acked-by: Prafulla Wadaskar Acked-by: Heiko Schocher --- board/keymile/common/common.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c index 1013f42e11e..a90f1124fbe 100644 --- a/board/keymile/common/common.c +++ b/board/keymile/common/common.c @@ -151,7 +151,6 @@ int i2c_make_abort(void) sda_state = get_sda(); if (scl_state && sda_state) { ret = 0; - printf("[INFO] i2c abort after %d clocks\n", i); break; } } @@ -159,8 +158,6 @@ int i2c_make_abort(void) if (ret == 0) for (i = 0; i < 5; i++) i2c_write_start_seq(); - else - printf("[ERROR] i2c abort failed\n"); /* respect stop setup time */ udelay(DELAY_ABORT_SEQ); -- cgit v1.3.1