summaryrefslogtreecommitdiff
path: root/drivers/i2c/omap24xx_i2c.c
diff options
context:
space:
mode:
authorTom Rini <trini@ti.com>2012-02-20 18:49:16 +0000
committerHeiko Schocher <hs@denx.de>2012-02-21 07:28:47 +0100
commitcec487a435ac106d1a611feba1a36043142c839b (patch)
tree49d7786ce87b76ac3bc61df340041124a34c9123 /drivers/i2c/omap24xx_i2c.c
parentc2459a405b2d423b294006e4519beaff28301d5a (diff)
downloadu-boot-imx-cec487a435ac106d1a611feba1a36043142c839b.zip
u-boot-imx-cec487a435ac106d1a611feba1a36043142c839b.tar.gz
u-boot-imx-cec487a435ac106d1a611feba1a36043142c839b.tar.bz2
Revert "ARM: I2C: I2C Multi byte address support"
This reverts commits 2faa76196af4b3e93bcb9e38ed9090cbd3b06db3 as this has introduced some large problems on all other platforms and have more changes in them than the commit message implies. Cc: Heiko Schocher <hs@denx.de> Cc: Patil, Rachna <rachna@ti.com> Signed-off-by: Tom Rini <trini@ti.com>
Diffstat (limited to 'drivers/i2c/omap24xx_i2c.c')
-rw-r--r--drivers/i2c/omap24xx_i2c.c467
1 files changed, 173 insertions, 294 deletions
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 80932ef..a7ffd95 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -29,11 +29,10 @@
DECLARE_GLOBAL_DATA_PTR;
-#define I2C_STAT_TIMEO (1 << 31)
-#define I2C_TIMEOUT 10
+#define I2C_TIMEOUT 1000
-static u32 wait_for_bb(void);
-static u32 wait_for_status_mask(u16 mask);
+static void wait_for_bb(void);
+static u16 wait_for_pin(void);
static void flush_fifo(void);
/*
@@ -51,6 +50,7 @@ void i2c_init(int speed, int slaveadd)
int psc, fsscll, fssclh;
int hsscll = 0, hssclh = 0;
u32 scll, sclh;
+ int timeout = I2C_TIMEOUT;
/* Only handle standard, fast and high speeds */
if ((speed != OMAP_I2C_STANDARD) &&
@@ -112,14 +112,24 @@ void i2c_init(int speed, int slaveadd)
sclh = (unsigned int)fssclh;
}
- if (gd->flags & GD_FLG_RELOC)
- bus_initialized[current_bus] = 1;
-
if (readw(&i2c_base->con) & I2C_CON_EN) {
writew(0, &i2c_base->con);
udelay(50000);
}
+ writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */
+ udelay(1000);
+
+ writew(I2C_CON_EN, &i2c_base->con);
+ while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) {
+ if (timeout <= 0) {
+ puts("ERROR: Timeout in soft-reset\n");
+ return;
+ }
+ udelay(1000);
+ }
+
+ writew(0, &i2c_base->con);
writew(psc, &i2c_base->psc);
writew(scll, &i2c_base->scll);
writew(sclh, &i2c_base->sclh);
@@ -135,6 +145,81 @@ void i2c_init(int speed, int slaveadd)
flush_fifo();
writew(0xFFFF, &i2c_base->stat);
writew(0, &i2c_base->cnt);
+
+ if (gd->flags & GD_FLG_RELOC)
+ bus_initialized[current_bus] = 1;
+}
+
+static int i2c_read_byte(u8 devaddr, u8 regoffset, u8 *value)
+{
+ int i2c_error = 0;
+ u16 status;
+
+ /* wait until bus not busy */
+ wait_for_bb();
+
+ /* one byte only */
+ writew(1, &i2c_base->cnt);
+ /* set slave address */
+ writew(devaddr, &i2c_base->sa);
+ /* no stop bit needed here */
+ writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
+ I2C_CON_TRX, &i2c_base->con);
+
+ /* send register offset */
+ while (1) {
+ status = wait_for_pin();
+ if (status == 0 || status & I2C_STAT_NACK) {
+ i2c_error = 1;
+ goto read_exit;
+ }
+ if (status & I2C_STAT_XRDY) {
+ /* Important: have to use byte access */
+ writeb(regoffset, &i2c_base->data);
+ writew(I2C_STAT_XRDY, &i2c_base->stat);
+ }
+ if (status & I2C_STAT_ARDY) {
+ writew(I2C_STAT_ARDY, &i2c_base->stat);
+ break;
+ }
+ }
+
+ /* set slave address */
+ writew(devaddr, &i2c_base->sa);
+ /* read one byte from slave */
+ writew(1, &i2c_base->cnt);
+ /* need stop bit here */
+ writew(I2C_CON_EN | I2C_CON_MST |
+ I2C_CON_STT | I2C_CON_STP,
+ &i2c_base->con);
+
+ /* receive data */
+ while (1) {
+ status = wait_for_pin();
+ if (status == 0 || status & I2C_STAT_NACK) {
+ i2c_error = 1;
+ goto read_exit;
+ }
+ if (status & I2C_STAT_RRDY) {
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+ defined(CONFIG_OMAP44XX)
+ *value = readb(&i2c_base->data);
+#else
+ *value = readw(&i2c_base->data);
+#endif
+ writew(I2C_STAT_RRDY, &i2c_base->stat);
+ }
+ if (status & I2C_STAT_ARDY) {
+ writew(I2C_STAT_ARDY, &i2c_base->stat);
+ break;
+ }
+ }
+
+read_exit:
+ flush_fifo();
+ writew(0xFFFF, &i2c_base->stat);
+ writew(0, &i2c_base->cnt);
+ return i2c_error;
}
static void flush_fifo(void)
@@ -161,42 +246,32 @@ static void flush_fifo(void)
int i2c_probe(uchar chip)
{
- u32 status;
+ u16 status;
int res = 1; /* default = fail */
if (chip == readw(&i2c_base->oa))
return res;
/* wait until bus not busy */
- status = wait_for_bb();
- /* exit on BUS busy */
- if (status & I2C_STAT_TIMEO)
- return res;
+ wait_for_bb();
/* try to write one byte */
writew(1, &i2c_base->cnt);
/* set slave address */
writew(chip, &i2c_base->sa);
/* stop bit needed here */
- writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT
- | I2C_CON_STP, &i2c_base->con);
- /* enough delay for the NACK bit set */
- udelay(9000);
-
- if (!(readw(&i2c_base->stat) & I2C_STAT_NACK)) {
- res = 0; /* success case */
- flush_fifo();
- writew(0xFFFF, &i2c_base->stat);
- } else {
- /* failure, clear sources*/
- writew(0xFFFF, &i2c_base->stat);
- /* finish up xfer */
- writew(readw(&i2c_base->con) | I2C_CON_STP, &i2c_base->con);
- status = wait_for_bb();
- /* exit on BUS busy */
- if (status & I2C_STAT_TIMEO)
- return res;
- }
+ writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
+ I2C_CON_STP, &i2c_base->con);
+
+ status = wait_for_pin();
+
+ /* check for ACK (!NAK) */
+ if (!(status & I2C_STAT_NACK))
+ res = 0;
+
+ /* abort transfer (force idle state) */
+ writew(0, &i2c_base->con);
+
flush_fifo();
/* don't allow any more data in... we don't want it. */
writew(0, &i2c_base->cnt);
@@ -206,309 +281,111 @@ int i2c_probe(uchar chip)
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
- int i2c_error = 0, i;
- u32 status;
-
- if ((alen > 2) || (alen < 0))
- return 1;
+ int i;
- if (alen < 2) {
- if (addr + len > 256)
- return 1;
- } else if (addr + len > 0xFFFF) {
+ if (alen > 1) {
+ printf("I2C read: addr len %d not supported\n", alen);
return 1;
}
- /* wait until bus not busy */
- status = wait_for_bb();
-
- /* exit on BUS busy */
- if (status & I2C_STAT_TIMEO)
+ if (addr + len > 256) {
+ puts("I2C read: address out of range\n");
return 1;
-
- writew((alen & 0xFF), &i2c_base->cnt);
- /* set slave address */
- writew(chip, &i2c_base->sa);
- /* Clear the Tx & Rx FIFOs */
- writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR |
- I2C_TXFIFO_CLEAR), &i2c_base->buf);
- /* no stop bit needed here */
- writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX |
- I2C_CON_STT, &i2c_base->con);
-
- /* wait for Transmit ready condition */
- status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK);
-
- if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
- i2c_error = 1;
-
- if (!i2c_error) {
- if (status & I2C_STAT_XRDY) {
- switch (alen) {
- case 2:
- /* Send address MSByte */
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- writew(((addr >> 8) & 0xFF), &i2c_base->data);
-
- /* Clearing XRDY event */
- writew((status & I2C_STAT_XRDY),
- &i2c_base->stat);
- /* wait for Transmit ready condition */
- status = wait_for_status_mask(I2C_STAT_XRDY |
- I2C_STAT_NACK);
-
- if (status & (I2C_STAT_NACK |
- I2C_STAT_TIMEO)) {
- i2c_error = 1;
- break;
- }
-#endif
- case 1:
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- /* Send address LSByte */
- writew((addr & 0xFF), &i2c_base->data);
-#else
- /* Send address Short word */
- writew((addr & 0xFFFF), &i2c_base->data);
-#endif
- /* Clearing XRDY event */
- writew((status & I2C_STAT_XRDY),
- &i2c_base->stat);
- /*wait for Transmit ready condition */
- status = wait_for_status_mask(I2C_STAT_ARDY |
- I2C_STAT_NACK);
-
- if (status & (I2C_STAT_NACK |
- I2C_STAT_TIMEO)) {
- i2c_error = 1;
- break;
- }
- }
- } else
- i2c_error = 1;
}
- /* Wait for ARDY to set */
- status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK
- | I2C_STAT_AL);
-
- if (!i2c_error) {
- /* set slave address */
- writew(chip, &i2c_base->sa);
- writew((len & 0xFF), &i2c_base->cnt);
- /* Clear the Tx & Rx FIFOs */
- writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR |
- I2C_TXFIFO_CLEAR), &i2c_base->buf);
- /* need stop bit here */
- writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
- &i2c_base->con);
-
- for (i = 0; i < len; i++) {
- /* wait for Receive condition */
- status = wait_for_status_mask(I2C_STAT_RRDY |
- I2C_STAT_NACK);
- if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) {
- i2c_error = 1;
- break;
- }
-
- if (status & I2C_STAT_RRDY) {
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- buffer[i] = readb(&i2c_base->data);
-#else
- *((u16 *)&buffer[i]) =
- readw(&i2c_base->data) & 0xFFFF;
- i++;
-#endif
- writew((status & I2C_STAT_RRDY),
- &i2c_base->stat);
- udelay(1000);
- } else {
- i2c_error = 1;
- }
+ for (i = 0; i < len; i++) {
+ if (i2c_read_byte(chip, addr + i, &buffer[i])) {
+ puts("I2C read: I/O error\n");
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+ return 1;
}
}
- /* Wait for ARDY to set */
- status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK
- | I2C_STAT_AL);
-
- if (i2c_error) {
- writew(0, &i2c_base->con);
- return 1;
- }
-
- writew(I2C_CON_EN, &i2c_base->con);
-
- while (readw(&i2c_base->stat)
- || (readw(&i2c_base->con) & I2C_CON_MST)) {
- udelay(10000);
- writew(0xFFFF, &i2c_base->stat);
- }
-
- writew(I2C_CON_EN, &i2c_base->con);
- flush_fifo();
- writew(0xFFFF, &i2c_base->stat);
- writew(0, &i2c_base->cnt);
-
return 0;
}
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
+ int i;
+ u16 status;
+ int i2c_error = 0;
- int i, i2c_error = 0;
- u32 status;
- u16 writelen;
-
- if (alen > 2)
+ if (alen > 1) {
+ printf("I2C write: addr len %d not supported\n", alen);
return 1;
+ }
- if (alen < 2) {
- if (addr + len > 256)
- return 1;
- } else if (addr + len > 0xFFFF) {
+ if (addr + len > 256) {
+ printf("I2C write: address 0x%x + 0x%x out of range\n",
+ addr, len);
return 1;
}
/* wait until bus not busy */
- status = wait_for_bb();
-
- /* exiting on BUS busy */
- if (status & I2C_STAT_TIMEO)
- return 1;
+ wait_for_bb();
- writelen = (len & 0xFFFF) + alen;
-
- /* two bytes */
- writew((writelen & 0xFFFF), &i2c_base->cnt);
- /* Clear the Tx & Rx FIFOs */
- writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR |
- I2C_TXFIFO_CLEAR), &i2c_base->buf);
+ /* start address phase - will write regoffset + len bytes data */
+ /* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */
+ writew(alen + len, &i2c_base->cnt);
/* set slave address */
writew(chip, &i2c_base->sa);
/* stop bit needed here */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
I2C_CON_STP, &i2c_base->con);
- /* wait for Transmit ready condition */
- status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK);
+ /* Send address byte */
+ status = wait_for_pin();
- if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
+ if (status == 0 || status & I2C_STAT_NACK) {
i2c_error = 1;
-
- if (!i2c_error) {
- if (status & I2C_STAT_XRDY) {
- switch (alen) {
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- case 2:
- /* send out MSB byte */
- writeb(((addr >> 8) & 0xFF), &i2c_base->data);
-#else
- writeb((addr & 0xFFFF), &i2c_base->data);
- break;
-#endif
- /* Clearing XRDY event */
- writew((status & I2C_STAT_XRDY),
- &i2c_base->stat);
- /*waiting for Transmit ready * condition */
- status = wait_for_status_mask(I2C_STAT_XRDY |
- I2C_STAT_NACK);
-
- if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) {
- i2c_error = 1;
- break;
- }
- case 1:
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- /* send out MSB byte */
- writeb((addr & 0xFF), &i2c_base->data);
-#else
- writew(((buffer[0] << 8) | (addr & 0xFF)),
- &i2c_base->data);
-#endif
- }
-
- /* Clearing XRDY event */
- writew((status & I2C_STAT_XRDY), &i2c_base->stat);
- }
-
- /* waiting for Transmit ready condition */
- status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK);
-
- if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
- i2c_error = 1;
-
- if (!i2c_error) {
- for (i = ((alen > 1) ? 0 : 1); i < len; i++) {
- if (status & I2C_STAT_XRDY) {
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
- writeb((buffer[i] & 0xFF),
- &i2c_base->data);
-#else
- writew((((buffer[i] << 8) |
- buffer[i + 1]) & 0xFFFF),
- &i2c_base->data);
- i++;
-#endif
- } else
- i2c_error = 1;
- /* Clearing XRDY event */
- writew((status & I2C_STAT_XRDY),
- &i2c_base->stat);
- /* waiting for XRDY condition */
- status = wait_for_status_mask(
- I2C_STAT_XRDY |
- I2C_STAT_ARDY |
- I2C_STAT_NACK);
- if (status & (I2C_STAT_NACK |
- I2C_STAT_TIMEO)) {
- i2c_error = 1;
- break;
- }
- if (status & I2C_STAT_ARDY)
- break;
- }
- }
+ printf("error waiting for i2c address ACK (status=0x%x)\n",
+ status);
+ goto write_exit;
}
- status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK |
- I2C_STAT_AL);
-
- if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
+ if (status & I2C_STAT_XRDY) {
+ writeb(addr & 0xFF, &i2c_base->data);
+ writew(I2C_STAT_XRDY, &i2c_base->stat);
+ } else {
i2c_error = 1;
-
- if (i2c_error) {
- writew(0, &i2c_base->con);
- return 1;
+ printf("i2c bus not ready for transmit (status=0x%x)\n",
+ status);
+ goto write_exit;
}
- if (!i2c_error) {
- int eout = 200;
+ /* address phase is over, now write data */
+ for (i = 0; i < len; i++) {
+ status = wait_for_pin();
- writew(I2C_CON_EN, &i2c_base->con);
- while ((status = readw(&i2c_base->stat)) ||
- (readw(&i2c_base->con) & I2C_CON_MST)) {
- udelay(1000);
- /* have to read to clear intrrupt */
- writew(0xFFFF, &i2c_base->stat);
- if (--eout == 0)
- /* better leave with error than hang */
- break;
+ if (status == 0 || status & I2C_STAT_NACK) {
+ i2c_error = 1;
+ printf("i2c error waiting for data ACK (status=0x%x)\n",
+ status);
+ goto write_exit;
+ }
+
+ if (status & I2C_STAT_XRDY) {
+ writeb(buffer[i], &i2c_base->data);
+ writew(I2C_STAT_XRDY, &i2c_base->stat);
+ } else {
+ i2c_error = 1;
+ printf("i2c bus not ready for Tx (i=%d)\n", i);
+ goto write_exit;
}
}
+write_exit:
flush_fifo();
writew(0xFFFF, &i2c_base->stat);
- writew(0, &i2c_base->cnt);
- return 0;
+ return i2c_error;
}
-static u32 wait_for_bb(void)
+static void wait_for_bb(void)
{
int timeout = I2C_TIMEOUT;
- u32 stat;
+ u16 stat;
+ writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/
while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
writew(stat, &i2c_base->stat);
udelay(1000);
@@ -517,28 +394,30 @@ static u32 wait_for_bb(void)
if (timeout <= 0) {
printf("timed out in wait_for_bb: I2C_STAT=%x\n",
readw(&i2c_base->stat));
- stat |= I2C_STAT_TIMEO;
}
writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/
- return stat;
}
-static u32 wait_for_status_mask(u16 mask)
+static u16 wait_for_pin(void)
{
- u32 status;
+ u16 status;
int timeout = I2C_TIMEOUT;
do {
udelay(1000);
status = readw(&i2c_base->stat);
- } while (!(status & mask) && timeout--);
+ } while (!(status &
+ (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
+ I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
+ I2C_STAT_AL)) && timeout--);
if (timeout <= 0) {
- printf("timed out in wait_for_status_mask: I2C_STAT=%x\n",
+ printf("timed out in wait_for_pin: I2C_STAT=%x\n",
readw(&i2c_base->stat));
writew(0xFFFF, &i2c_base->stat);
- status |= I2C_STAT_TIMEO;
+ status = 0;
}
+
return status;
}