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;
#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);
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);
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();
/* 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;
int i;
if ((alen > 2) || (alen < 0))
if (alen > 1) {
printf("I2C read: addr len %d not supported\n", alen);
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;
} 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;
}
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();
wait_for_bb();
/* exiting on BUS busy */
if (status & I2C_STAT_TIMEO)
return 1;
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;
printf("error waiting for i2c address ACK (status=0x%x)\n",
status);
goto write_exit;
}
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_XRDY) {
writeb(addr & 0xFF, &i2c_base->data);
writew(I2C_STAT_XRDY, &i2c_base->stat);
} else {
i2c_error = 1;
printf("i2c bus not ready for transmit (status=0x%x)\n",
status);
goto write_exit;
}
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
}
/* address phase is over, now write data */
for (i = 0; i < len; i++) {
status = wait_for_pin();
/* 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))
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 (!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 |
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;
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;
}

View File

@ -60,9 +60,7 @@
/* I2C Buffer Configuration Register (I2C_BUF): */
#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_TXFIFO_CLEAR (1 << 6) /* TX FIFO clear */
/* I2C Configuration Register (I2C_CON): */