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: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
This commit is contained in:
parent
925594e035
commit
a20a64d226
|
@ -130,21 +130,25 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||||
}
|
}
|
||||||
iface->transPtr++;
|
iface->transPtr++;
|
||||||
iface->readNum--;
|
iface->readNum--;
|
||||||
} else if (iface->manual_stop) {
|
}
|
||||||
/* Temporary workaround to avoid possible bus stall -
|
|
||||||
* Flush FIFO before issuing the STOP condition
|
if (iface->readNum == 0) {
|
||||||
*/
|
if (iface->manual_stop) {
|
||||||
read_RCV_DATA16(iface);
|
/* Temporary workaround to avoid possible bus stall -
|
||||||
write_MASTER_CTL(iface,
|
* Flush FIFO before issuing the STOP condition
|
||||||
read_MASTER_CTL(iface) | STOP);
|
*/
|
||||||
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
read_RCV_DATA16(iface);
|
||||||
iface->cur_msg + 1 < iface->msg_num) {
|
|
||||||
if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
|
|
||||||
write_MASTER_CTL(iface,
|
write_MASTER_CTL(iface,
|
||||||
read_MASTER_CTL(iface) | RSTART | MDIR);
|
read_MASTER_CTL(iface) | STOP);
|
||||||
else
|
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
|
||||||
write_MASTER_CTL(iface,
|
iface->cur_msg + 1 < iface->msg_num) {
|
||||||
(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
|
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) {
|
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)
|
if (iface->pmsg[iface->cur_msg].len <= 255) {
|
||||||
write_MASTER_CTL(iface,
|
write_MASTER_CTL(iface,
|
||||||
(read_MASTER_CTL(iface) &
|
(read_MASTER_CTL(iface) &
|
||||||
(~(0xff << 6))) |
|
(~(0xff << 6))) |
|
||||||
(iface->pmsg[iface->cur_msg].len << 6));
|
(iface->pmsg[iface->cur_msg].len << 6));
|
||||||
else {
|
iface->manual_stop = 0;
|
||||||
|
} else {
|
||||||
write_MASTER_CTL(iface,
|
write_MASTER_CTL(iface,
|
||||||
(read_MASTER_CTL(iface) |
|
(read_MASTER_CTL(iface) |
|
||||||
(0xff << 6)));
|
(0xff << 6)));
|
||||||
|
@ -264,8 +269,8 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
|
||||||
write_INT_MASK(iface, 0);
|
write_INT_MASK(iface, 0);
|
||||||
write_MASTER_CTL(iface, 0);
|
write_MASTER_CTL(iface, 0);
|
||||||
}
|
}
|
||||||
|
complete(&iface->complete);
|
||||||
}
|
}
|
||||||
complete(&iface->complete);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interrupt handler */
|
/* Interrupt handler */
|
||||||
|
|
Loading…
Reference in New Issue