aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorShinya Kuribayashi <shinya.kuribayashi@necel.com>2009-11-06 07:51:18 -0500
committerBen Dooks <ben-linux@fluff.org>2009-12-08 19:19:12 -0500
commit8f588e40c788e63756ca1028c253f9f663d7d1c5 (patch)
treedbebba165e7e926206b5d244ea26da4b32d966e8 /drivers/i2c
parent69151e532c97f983b498ea03e20b1598a5487318 (diff)
i2c-designware: i2c_dw_xfer_msg: Fix error handling procedures
Current error handling procedures are not good in two respects: * Forgot to mark dev->cmd_complete as "completed" on errors Once an I2C transaction is initiated, wait_for_completion_ interruptible_timeout() waits for dev->cmd_complete to be completed. We have to take care of it whenever an error is detected, otherwise we will have a needless HZ timeout. * Forgot to disable interrupts In the previous patch, interrupt mask operations have been changed. We don't disable interrupts at the end of the interrupt handler any more, and try to keep RX_FULL (and TX_EMPTY if required) enabled during the transaction so that we can send longer data than the size of Tx/Rx FIFO. If an error is detected, we need to disable interrupts before quitting current transaction. We can work around above points using dev->msg_err effectively. Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-designware.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
index 6acbe846e9c6..cb83671ff5fc 100644
--- a/drivers/i2c/busses/i2c-designware.c
+++ b/drivers/i2c/busses/i2c-designware.c
@@ -380,14 +380,18 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
380 * reprogram the target address in the i2c 380 * reprogram the target address in the i2c
381 * adapter when we are done with this transfer 381 * adapter when we are done with this transfer
382 */ 382 */
383 if (msgs[dev->msg_write_idx].addr != addr) 383 if (msgs[dev->msg_write_idx].addr != addr) {
384 return; 384 dev_err(dev->dev,
385 "%s: invalid target address\n", __func__);
386 dev->msg_err = -EINVAL;
387 break;
388 }
385 389
386 if (msgs[dev->msg_write_idx].len == 0) { 390 if (msgs[dev->msg_write_idx].len == 0) {
387 dev_err(dev->dev, 391 dev_err(dev->dev,
388 "%s: invalid message length\n", __func__); 392 "%s: invalid message length\n", __func__);
389 dev->msg_err = -EINVAL; 393 dev->msg_err = -EINVAL;
390 return; 394 break;
391 } 395 }
392 396
393 if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { 397 if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
@@ -426,6 +430,9 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
426 if (dev->msg_write_idx == dev->msgs_num) 430 if (dev->msg_write_idx == dev->msgs_num)
427 intr_mask &= ~DW_IC_INTR_TX_EMPTY; 431 intr_mask &= ~DW_IC_INTR_TX_EMPTY;
428 432
433 if (dev->msg_err)
434 intr_mask = 0;
435
429 writel(intr_mask, dev->base + DW_IC_INTR_MASK); 436 writel(intr_mask, dev->base + DW_IC_INTR_MASK);
430} 437}
431 438
@@ -628,7 +635,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
628 * the current transmit status. 635 * the current transmit status.
629 */ 636 */
630 637
631 if (stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) 638 if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
632 complete(&dev->cmd_complete); 639 complete(&dev->cmd_complete);
633 640
634 return IRQ_HANDLED; 641 return IRQ_HANDLED;