Skip to content
Snippets Groups Projects
Commit cec487a4 authored by Tom Rini's avatar Tom Rini Committed by Heiko Schocher
Browse files

Revert "ARM: I2C: I2C Multi byte address support"


This reverts commits 2faa7619 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: default avatarTom Rini <trini@ti.com>
parent c2459a40
No related branches found
No related tags found
No related merge requests found
...@@ -29,11 +29,10 @@ ...@@ -29,11 +29,10 @@
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
#define I2C_STAT_TIMEO (1 << 31) #define I2C_TIMEOUT 1000
#define I2C_TIMEOUT 10
static u32 wait_for_bb(void); static void wait_for_bb(void);
static u32 wait_for_status_mask(u16 mask); static u16 wait_for_pin(void);
static void flush_fifo(void); static void flush_fifo(void);
/* /*
...@@ -51,6 +50,7 @@ void i2c_init(int speed, int slaveadd) ...@@ -51,6 +50,7 @@ void i2c_init(int speed, int slaveadd)
int psc, fsscll, fssclh; int psc, fsscll, fssclh;
int hsscll = 0, hssclh = 0; int hsscll = 0, hssclh = 0;
u32 scll, sclh; u32 scll, sclh;
int timeout = I2C_TIMEOUT;
/* Only handle standard, fast and high speeds */ /* Only handle standard, fast and high speeds */
if ((speed != OMAP_I2C_STANDARD) && if ((speed != OMAP_I2C_STANDARD) &&
...@@ -112,14 +112,24 @@ void i2c_init(int speed, int slaveadd) ...@@ -112,14 +112,24 @@ void i2c_init(int speed, int slaveadd)
sclh = (unsigned int)fssclh; sclh = (unsigned int)fssclh;
} }
if (gd->flags & GD_FLG_RELOC)
bus_initialized[current_bus] = 1;
if (readw(&i2c_base->con) & I2C_CON_EN) { if (readw(&i2c_base->con) & I2C_CON_EN) {
writew(0, &i2c_base->con); writew(0, &i2c_base->con);
udelay(50000); 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(psc, &i2c_base->psc);
writew(scll, &i2c_base->scll); writew(scll, &i2c_base->scll);
writew(sclh, &i2c_base->sclh); writew(sclh, &i2c_base->sclh);
...@@ -135,6 +145,81 @@ void i2c_init(int speed, int slaveadd) ...@@ -135,6 +145,81 @@ void i2c_init(int speed, int slaveadd)
flush_fifo(); flush_fifo();
writew(0xFFFF, &i2c_base->stat); writew(0xFFFF, &i2c_base->stat);
writew(0, &i2c_base->cnt); 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) static void flush_fifo(void)
...@@ -161,42 +246,32 @@ static void flush_fifo(void) ...@@ -161,42 +246,32 @@ static void flush_fifo(void)
int i2c_probe(uchar chip) int i2c_probe(uchar chip)
{ {
u32 status; u16 status;
int res = 1; /* default = fail */ int res = 1; /* default = fail */
if (chip == readw(&i2c_base->oa)) if (chip == readw(&i2c_base->oa))
return res; return res;
/* wait until bus not busy */ /* wait until bus not busy */
status = wait_for_bb(); wait_for_bb();
/* exit on BUS busy */
if (status & I2C_STAT_TIMEO)
return res;
/* try to write one byte */ /* try to write one byte */
writew(1, &i2c_base->cnt); writew(1, &i2c_base->cnt);
/* set slave address */ /* set slave address */
writew(chip, &i2c_base->sa); writew(chip, &i2c_base->sa);
/* stop bit needed here */ /* stop bit needed here */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
| I2C_CON_STP, &i2c_base->con); I2C_CON_STP, &i2c_base->con);
/* enough delay for the NACK bit set */
udelay(9000); status = wait_for_pin();
if (!(readw(&i2c_base->stat) & I2C_STAT_NACK)) { /* check for ACK (!NAK) */
res = 0; /* success case */ if (!(status & I2C_STAT_NACK))
flush_fifo(); res = 0;
writew(0xFFFF, &i2c_base->stat);
} else { /* abort transfer (force idle state) */
/* failure, clear sources*/ writew(0, &i2c_base->con);
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;
}
flush_fifo(); flush_fifo();
/* don't allow any more data in... we don't want it. */ /* don't allow any more data in... we don't want it. */
writew(0, &i2c_base->cnt); writew(0, &i2c_base->cnt);
...@@ -206,309 +281,111 @@ int i2c_probe(uchar chip) ...@@ -206,309 +281,111 @@ int i2c_probe(uchar chip)
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{ {
int i2c_error = 0, i; int i;
u32 status;
if ((alen > 2) || (alen < 0))
return 1;
if (alen < 2) { if (alen > 1) {
if (addr + len > 256) printf("I2C read: addr len %d not supported\n", alen);
return 1;
} else if (addr + len > 0xFFFF) {
return 1; return 1;
} }
/* wait until bus not busy */ if (addr + len > 256) {
status = wait_for_bb(); puts("I2C read: address out of range\n");
/* exit on BUS busy */
if (status & I2C_STAT_TIMEO)
return 1; 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 */ for (i = 0; i < len; i++) {
status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK if (i2c_read_byte(chip, addr + i, &buffer[i])) {
| I2C_STAT_AL); puts("I2C read: I/O error\n");
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
if (!i2c_error) { return 1;
/* 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;
}
} }
} }
/* 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; return 0;
} }
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) 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; if (alen > 1) {
u32 status; printf("I2C write: addr len %d not supported\n", alen);
u16 writelen;
if (alen > 2)
return 1; return 1;
}
if (alen < 2) { if (addr + len > 256) {
if (addr + len > 256) printf("I2C write: address 0x%x + 0x%x out of range\n",
return 1; addr, len);
} else if (addr + len > 0xFFFF) {
return 1; return 1;
} }
/* wait until bus not busy */ /* wait until bus not busy */
status = wait_for_bb(); wait_for_bb();
/* exiting on BUS busy */
if (status & I2C_STAT_TIMEO)
return 1;
writelen = (len & 0xFFFF) + alen; /* start address phase - will write regoffset + len bytes data */
/* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */
/* two bytes */ writew(alen + len, &i2c_base->cnt);
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);
/* set slave address */ /* set slave address */
writew(chip, &i2c_base->sa); writew(chip, &i2c_base->sa);
/* stop bit needed here */ /* stop bit needed here */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
I2C_CON_STP, &i2c_base->con); I2C_CON_STP, &i2c_base->con);
/* wait for Transmit ready condition */ /* Send address byte */
status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK); status = wait_for_pin();
if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) if (status == 0 || status & I2C_STAT_NACK) {
i2c_error = 1; i2c_error = 1;
printf("error waiting for i2c address ACK (status=0x%x)\n",
if (!i2c_error) { status);
if (status & I2C_STAT_XRDY) { goto write_exit;
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;
}
}
} }
status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK | if (status & I2C_STAT_XRDY) {
I2C_STAT_AL); writeb(addr & 0xFF, &i2c_base->data);
writew(I2C_STAT_XRDY, &i2c_base->stat);
if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) } else {
i2c_error = 1; i2c_error = 1;
printf("i2c bus not ready for transmit (status=0x%x)\n",
if (i2c_error) { status);
writew(0, &i2c_base->con); goto write_exit;
return 1;
} }
if (!i2c_error) { /* address phase is over, now write data */
int eout = 200; for (i = 0; i < len; i++) {
status = wait_for_pin();
writew(I2C_CON_EN, &i2c_base->con); if (status == 0 || status & I2C_STAT_NACK) {
while ((status = readw(&i2c_base->stat)) || i2c_error = 1;
(readw(&i2c_base->con) & I2C_CON_MST)) { printf("i2c error waiting for data ACK (status=0x%x)\n",
udelay(1000); status);
/* have to read to clear intrrupt */ goto write_exit;
writew(0xFFFF, &i2c_base->stat); }
if (--eout == 0)
/* better leave with error than hang */ if (status & I2C_STAT_XRDY) {
break; 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(); flush_fifo();
writew(0xFFFF, &i2c_base->stat); writew(0xFFFF, &i2c_base->stat);
writew(0, &i2c_base->cnt); return i2c_error;
return 0;
} }
static u32 wait_for_bb(void) static void wait_for_bb(void)
{ {
int timeout = I2C_TIMEOUT; 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--) { while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
writew(stat, &i2c_base->stat); writew(stat, &i2c_base->stat);
udelay(1000); udelay(1000);
...@@ -517,28 +394,30 @@ static u32 wait_for_bb(void) ...@@ -517,28 +394,30 @@ static u32 wait_for_bb(void)
if (timeout <= 0) { if (timeout <= 0) {
printf("timed out in wait_for_bb: I2C_STAT=%x\n", printf("timed out in wait_for_bb: I2C_STAT=%x\n",
readw(&i2c_base->stat)); readw(&i2c_base->stat));
stat |= I2C_STAT_TIMEO;
} }
writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/ 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; int timeout = I2C_TIMEOUT;
do { do {
udelay(1000); udelay(1000);
status = readw(&i2c_base->stat); 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) { 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)); readw(&i2c_base->stat));
writew(0xFFFF, &i2c_base->stat); writew(0xFFFF, &i2c_base->stat);
status |= I2C_STAT_TIMEO; status = 0;
} }
return status; return status;
} }
......
...@@ -60,9 +60,7 @@ ...@@ -60,9 +60,7 @@
/* I2C Buffer Configuration Register (I2C_BUF): */ /* I2C Buffer Configuration Register (I2C_BUF): */
#define I2C_BUF_RDMA_EN (1 << 15) /* Receive DMA channel enable */ #define I2C_BUF_RDMA_EN (1 << 15) /* Receive DMA channel enable */
#define I2C_RXFIFO_CLEAR (1 << 14) /* RX FIFO Clear */
#define I2C_BUF_XDMA_EN (1 << 7) /* Transmit DMA channel enable */ #define I2C_BUF_XDMA_EN (1 << 7) /* Transmit DMA channel enable */
#define I2C_TXFIFO_CLEAR (1 << 6) /* TX FIFO clear */
/* I2C Configuration Register (I2C_CON): */ /* I2C Configuration Register (I2C_CON): */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment