From 8419c8debdc600b71fb89f0ffad80a6f436d80fe Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 28 May 2013 18:41:09 +0800 Subject: i2c: bfin-twi: Read and write the FIFO in loop TWI transfer interrupts may be lost when system is heavily handling other interrupts, while current transfer handler depends on each accurate interrupt and misses some data in this case. Because there are 2 2-byte FIFOs in blackfin TWI controller, the occurrence of the data loss can be reduced by reading till the RX FIFO is empty and writing till the TX FIFO is full. Reported-by: Bob Maris Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 47 ++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 20 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 05080c449c6b..13ea1c29873d 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -39,33 +39,40 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, unsigned short mast_stat = read_MASTER_STAT(iface); if (twi_int_status & XMTSERV) { + if (iface->writeNum <= 0) { + /* start receive immediately after complete sending in + * combine mode. + */ + if (iface->cur_mode == TWI_I2C_MODE_COMBINED) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | MDIR); + else if (iface->manual_stop) + 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) | + MDIR); + else + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) & + ~MDIR); + } + } /* Transmit next data */ - if (iface->writeNum > 0) { + while (iface->writeNum > 0 && + (read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) { SSYNC(); write_XMT_DATA8(iface, *(iface->transPtr++)); iface->writeNum--; } - /* start receive immediately after complete sending in - * combine mode. - */ - else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | MDIR); - else if (iface->manual_stop) - 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) | MDIR); - else - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) & ~MDIR); - } } if (twi_int_status & RCVSERV) { - if (iface->readNum > 0) { + while (iface->readNum > 0 && + (read_FIFO_STAT(iface) & RCVSTAT)) { /* Receive next data */ *(iface->transPtr) = read_RCV_DATA8(iface); if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { -- cgit v1.2.3