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

This reverts commits 2faa76196a 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>
This commit is contained in:
Tom Rini 2012-02-20 18:49:16 +00:00 committed by Heiko Schocher
parent c2459a405b
commit cec487a435
2 changed files with 176 additions and 299 deletions

View file

@ -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)
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)
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)
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)
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();
/* check for ACK (!NAK) */
if (!(status & I2C_STAT_NACK))
res = 0;
/* abort transfer (force idle state) */
writew(0, &i2c_base->con);
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;
}
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)
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)) if (alen > 1) {
printf("I2C read: addr len %d not supported\n", alen);
return 1; return 1;
}
if (alen < 2) { if (addr + len > 256) {
if (addr + len > 256) puts("I2C read: address out of range\n");
return 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; return 1;
} else if (addr + len > 0xFFFF) {
return 1;
}
/* wait until bus not busy */
status = wait_for_bb();
/* exit on BUS busy */
if (status & I2C_STAT_TIMEO)
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;
}
} }
} }
/* 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 */ /* start address phase - will write regoffset + len bytes data */
if (status & I2C_STAT_TIMEO) /* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */
return 1; writew(alen + len, &i2c_base->cnt);
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);
/* 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",
status);
goto write_exit;
}
if (!i2c_error) { if (status & I2C_STAT_XRDY) {
if (status & I2C_STAT_XRDY) { writeb(addr & 0xFF, &i2c_base->data);
switch (alen) { writew(I2C_STAT_XRDY, &i2c_base->stat);
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) } else {
case 2: i2c_error = 1;
/* send out MSB byte */ printf("i2c bus not ready for transmit (status=0x%x)\n",
writeb(((addr >> 8) & 0xFF), &i2c_base->data); status);
#else goto write_exit;
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)) { /* address phase is over, now write data */
i2c_error = 1; for (i = 0; i < len; i++) {
break; status = wait_for_pin();
}
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 */ if (status == 0 || status & I2C_STAT_NACK) {
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; i2c_error = 1;
printf("i2c error waiting for data ACK (status=0x%x)\n",
status);
goto write_exit;
}
if (!i2c_error) { if (status & I2C_STAT_XRDY) {
for (i = ((alen > 1) ? 0 : 1); i < len; i++) { writeb(buffer[i], &i2c_base->data);
if (status & I2C_STAT_XRDY) { writew(I2C_STAT_XRDY, &i2c_base->stat);
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) } else {
writeb((buffer[i] & 0xFF), i2c_error = 1;
&i2c_base->data); printf("i2c bus not ready for Tx (i=%d)\n", i);
#else goto write_exit;
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 |
I2C_STAT_AL);
if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
i2c_error = 1;
if (i2c_error) {
writew(0, &i2c_base->con);
return 1;
}
if (!i2c_error) {
int eout = 200;
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;
} }
} }
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)
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;
} }

View file

@ -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): */