Commit a20a64d2 authored by Sonic Zhang's avatar Sonic Zhang Committed by Wolfram Sang

i2c: i2c-bfin-twi: Improve the patch for bug "Illegal i2c bus lock upon...

i2c: i2c-bfin-twi: Improve the patch for bug "Illegal i2c bus lock upon certain transfer scenarios".

For transfer counts > 255 bytes i2c-bfin-twi sets the data
transfer counter DCNT to 0xFF indicating unlimited transfers.
It then uses a flag iface->manual_stop to manually issue the STOP
condition, once the required amount of bytes are received.

We found that on I2C receive operation issuing the STOP condition
together with a FULL RCV FIFO (2bytes) will cause SDA and SCL be
constantly driven low.

This patch stops receiving operation immediately in last rx interrupt.
This patch also wakes up waiting process when transfer completes.
Signed-off-by: default avatarSonic Zhang <sonic.zhang@analog.com>
Signed-off-by: default avatarWolfram Sang <w.sang@pengutronix.de>
parent 925594e0
......@@ -130,21 +130,25 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
}
iface->transPtr++;
iface->readNum--;
} else if (iface->manual_stop) {
/* Temporary workaround to avoid possible bus stall -
* Flush FIFO before issuing the STOP condition
*/
read_RCV_DATA16(iface);
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | STOP);
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
iface->cur_msg + 1 < iface->msg_num) {
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | RSTART | MDIR);
else
}
if (iface->readNum == 0) {
if (iface->manual_stop) {
/* Temporary workaround to avoid possible bus stall -
* Flush FIFO before issuing the STOP condition
*/
read_RCV_DATA16(iface);
write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
read_MASTER_CTL(iface) | STOP);
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
iface->cur_msg + 1 < iface->msg_num) {
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | RSTART | MDIR);
else
write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
}
}
}
if (twi_int_status & MERR) {
......@@ -245,12 +249,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
}
}
if (iface->pmsg[iface->cur_msg].len <= 255)
write_MASTER_CTL(iface,
if (iface->pmsg[iface->cur_msg].len <= 255) {
write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) &
(~(0xff << 6))) |
(iface->pmsg[iface->cur_msg].len << 6));
else {
(iface->pmsg[iface->cur_msg].len << 6));
iface->manual_stop = 0;
} else {
write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) |
(0xff << 6)));
......@@ -264,8 +269,8 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
write_INT_MASK(iface, 0);
write_MASTER_CTL(iface, 0);
}
complete(&iface->complete);
}
complete(&iface->complete);
}
/* Interrupt handler */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment