aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-designware.c
diff options
context:
space:
mode:
authorShinya Kuribayashi <shinya.kuribayashi@necel.com>2009-11-06 07:50:40 -0500
committerBen Dooks <ben-linux@fluff.org>2009-12-08 19:19:12 -0500
commit201d6a70b72d1e6ca5a8e03f5f41a7741241401a (patch)
tree4e14e3f9ed1eb0f4aac57890d59d653f8b1e5641 /drivers/i2c/busses/i2c-designware.c
parent41c4e35037337cfcd297322f3f60770955156683 (diff)
i2c-designware: Process all i2c_msg messages in the interrupt handler
Currently we process the first i2c_dw_xfer_msg() in i2c_dw_xfer(), but in this case there is a possibility to be interrupted by certain interrupts. As described before in this patchset, we need to keep providing new transmit data within a given time period, otherwise Tx FIFO underrun takes place and STOP condition will be generated on the bus, even if we have more bytes to be written. In order to exclude all such possibilities, change TX_EMPTY interrupt usage as below: * DW_IC_INTR_DEFAULT_MASK: Define a default interrupt mask set, and put TX_EMPTY there. * i2c_dw_xfer_init: Enable DW_IC_INTR_DEFAULT_MASK prior to initiating a new I2C transaction. The first TX_EMPTY will be triggered shortly. With the help of it, we can make the first call to i2c_dw_xfer_msg() in the interrupt handler. * i2c_dw_xfer_msg: Fixup intr_mask operation accordingly. Make sure that TX_EMPTY operations need to be reversed. * request_irq: Set IRQF_DISABLED so that we could load transmit data into Tx FIFO without being distracted by other interrupts. * Remove i2c_dw_xfer_msg() in i2c_dw_xfer(). Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com> Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Diffstat (limited to 'drivers/i2c/busses/i2c-designware.c')
-rw-r--r--drivers/i2c/busses/i2c-designware.c26
1 files changed, 17 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c
index 5a3bd74c81d5..f184d822d3d4 100644
--- a/drivers/i2c/busses/i2c-designware.c
+++ b/drivers/i2c/busses/i2c-designware.c
@@ -90,6 +90,11 @@
90#define DW_IC_INTR_START_DET 0x400 90#define DW_IC_INTR_START_DET 0x400
91#define DW_IC_INTR_GEN_CALL 0x800 91#define DW_IC_INTR_GEN_CALL 0x800
92 92
93#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
94 DW_IC_INTR_TX_EMPTY | \
95 DW_IC_INTR_TX_ABRT | \
96 DW_IC_INTR_STOP_DET)
97
93#define DW_IC_STATUS_ACTIVITY 0x1 98#define DW_IC_STATUS_ACTIVITY 0x1
94 99
95#define DW_IC_ERR_TX_ABRT 0x1 100#define DW_IC_ERR_TX_ABRT 0x1
@@ -347,13 +352,16 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
347 352
348 /* Enable the adapter */ 353 /* Enable the adapter */
349 writel(1, dev->base + DW_IC_ENABLE); 354 writel(1, dev->base + DW_IC_ENABLE);
355
356 /* Enable interrupts */
357 writel(DW_IC_INTR_DEFAULT_MASK, dev->base + DW_IC_INTR_MASK);
350} 358}
351 359
352/* 360/*
353 * Initiate low level master read/write transaction. 361 * Initiate (and continue) low level master read/write transaction.
354 * This function is called from i2c_dw_xfer when starting a transfer. 362 * This function is only called from i2c_dw_isr, and pumping i2c_msg
355 * This function is also called from i2c_dw_isr to continue a transfer 363 * messages into the tx buffer. Even if the size of i2c_msg data is
356 * that is longer than the size of the TX FIFO. 364 * longer than the size of the tx buffer, it handles everything.
357 */ 365 */
358static void 366static void
359i2c_dw_xfer_msg(struct dw_i2c_dev *dev) 367i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
@@ -365,7 +373,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
365 u32 buf_len = dev->tx_buf_len; 373 u32 buf_len = dev->tx_buf_len;
366 u8 *buf = dev->tx_buf;; 374 u8 *buf = dev->tx_buf;;
367 375
368 intr_mask = DW_IC_INTR_STOP_DET | DW_IC_INTR_TX_ABRT | DW_IC_INTR_RX_FULL; 376 intr_mask = DW_IC_INTR_DEFAULT_MASK;
369 377
370 for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) { 378 for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
371 /* if target address has changed, we need to 379 /* if target address has changed, we need to
@@ -405,11 +413,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
405 413
406 if (buf_len > 0) { 414 if (buf_len > 0) {
407 /* more bytes to be written */ 415 /* more bytes to be written */
408 intr_mask |= DW_IC_INTR_TX_EMPTY;
409 dev->status |= STATUS_WRITE_IN_PROGRESS; 416 dev->status |= STATUS_WRITE_IN_PROGRESS;
410 break; 417 break;
411 } else 418 } else {
412 dev->status &= ~STATUS_WRITE_IN_PROGRESS; 419 dev->status &= ~STATUS_WRITE_IN_PROGRESS;
420 intr_mask &= ~DW_IC_INTR_TX_EMPTY;
421 }
413 } 422 }
414 423
415 writel(intr_mask, dev->base + DW_IC_INTR_MASK); 424 writel(intr_mask, dev->base + DW_IC_INTR_MASK);
@@ -479,7 +488,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
479 488
480 /* start the transfers */ 489 /* start the transfers */
481 i2c_dw_xfer_init(dev); 490 i2c_dw_xfer_init(dev);
482 i2c_dw_xfer_msg(dev);
483 491
484 /* wait for tx to complete */ 492 /* wait for tx to complete */
485 ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ); 493 ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
@@ -687,7 +695,7 @@ static int __devinit dw_i2c_probe(struct platform_device *pdev)
687 i2c_dw_init(dev); 695 i2c_dw_init(dev);
688 696
689 writel(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */ 697 writel(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */
690 r = request_irq(dev->irq, i2c_dw_isr, 0, pdev->name, dev); 698 r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev);
691 if (r) { 699 if (r) {
692 dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); 700 dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
693 goto err_iounmap; 701 goto err_iounmap;