aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-bfin-twi.c
diff options
context:
space:
mode:
authorSonic Zhang <sonic.zhang@analog.com>2012-06-13 04:22:41 -0400
committerWolfram Sang <w.sang@pengutronix.de>2012-07-13 02:27:31 -0400
commita20a64d226be36808b24d2205b5d35e80c49e8be (patch)
tree577632d86b31b12fb51bb646e968367064b47e59 /drivers/i2c/busses/i2c-bfin-twi.c
parent925594e03550f1825647ea5408a32bb9803d90f1 (diff)
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>
Diffstat (limited to 'drivers/i2c/busses/i2c-bfin-twi.c')
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c43
1 files changed, 24 insertions, 19 deletions
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index c2e6b7849e8d..4799c6886946 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -130,21 +130,25 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
130 } 130 }
131 iface->transPtr++; 131 iface->transPtr++;
132 iface->readNum--; 132 iface->readNum--;
133 } else if (iface->manual_stop) { 133 }
134 /* Temporary workaround to avoid possible bus stall - 134
135 * Flush FIFO before issuing the STOP condition 135 if (iface->readNum == 0) {
136 */ 136 if (iface->manual_stop) {
137 read_RCV_DATA16(iface); 137 /* Temporary workaround to avoid possible bus stall -
138 write_MASTER_CTL(iface, 138 * Flush FIFO before issuing the STOP condition
139 read_MASTER_CTL(iface) | STOP); 139 */
140 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && 140 read_RCV_DATA16(iface);
141 iface->cur_msg + 1 < iface->msg_num) {
142 if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
143 write_MASTER_CTL(iface,
144 read_MASTER_CTL(iface) | RSTART | MDIR);
145 else
146 write_MASTER_CTL(iface, 141 write_MASTER_CTL(iface,
147 (read_MASTER_CTL(iface) | RSTART) & ~MDIR); 142 read_MASTER_CTL(iface) | STOP);
143 } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
144 iface->cur_msg + 1 < iface->msg_num) {
145 if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
146 write_MASTER_CTL(iface,
147 read_MASTER_CTL(iface) | RSTART | MDIR);
148 else
149 write_MASTER_CTL(iface,
150 (read_MASTER_CTL(iface) | RSTART) & ~MDIR);
151 }
148 } 152 }
149 } 153 }
150 if (twi_int_status & MERR) { 154 if (twi_int_status & MERR) {
@@ -245,12 +249,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
245 } 249 }
246 } 250 }
247 251
248 if (iface->pmsg[iface->cur_msg].len <= 255) 252 if (iface->pmsg[iface->cur_msg].len <= 255) {
249 write_MASTER_CTL(iface, 253 write_MASTER_CTL(iface,
250 (read_MASTER_CTL(iface) & 254 (read_MASTER_CTL(iface) &
251 (~(0xff << 6))) | 255 (~(0xff << 6))) |
252 (iface->pmsg[iface->cur_msg].len << 6)); 256 (iface->pmsg[iface->cur_msg].len << 6));
253 else { 257 iface->manual_stop = 0;
258 } else {
254 write_MASTER_CTL(iface, 259 write_MASTER_CTL(iface,
255 (read_MASTER_CTL(iface) | 260 (read_MASTER_CTL(iface) |
256 (0xff << 6))); 261 (0xff << 6)));
@@ -264,8 +269,8 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
264 write_INT_MASK(iface, 0); 269 write_INT_MASK(iface, 0);
265 write_MASTER_CTL(iface, 0); 270 write_MASTER_CTL(iface, 0);
266 } 271 }
272 complete(&iface->complete);
267 } 273 }
268 complete(&iface->complete);
269} 274}
270 275
271/* Interrupt handler */ 276/* Interrupt handler */