Skip to content

Commit e348031

Browse files
committed
Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c fixes from Wolfram Sang: "Here is a revert and two bugfixes for the I2C designware driver. Please note that we are still hunting down a regression for the i2c-octeon driver. While there is a fix pending, we have unclear feedback from the testers currently. An rc8 would be quite helpful for this case" * 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: Revert "i2c: designware: do not disable adapter after transfer" i2c: designware: fix rx fifo depth tracking i2c: designware: report short transfers
2 parents a56f3eb + 89119f0 commit e348031

File tree

1 file changed

+25
-39
lines changed

1 file changed

+25
-39
lines changed

drivers/i2c/busses/i2c-designware-core.c

Lines changed: 25 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,7 @@
9191
DW_IC_INTR_TX_ABRT | \
9292
DW_IC_INTR_STOP_DET)
9393

94-
#define DW_IC_STATUS_ACTIVITY 0x1
95-
#define DW_IC_STATUS_TFE BIT(2)
96-
#define DW_IC_STATUS_MST_ACTIVITY BIT(5)
94+
#define DW_IC_STATUS_ACTIVITY 0x1
9795

9896
#define DW_IC_SDA_HOLD_RX_SHIFT 16
9997
#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
@@ -478,25 +476,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
478476
{
479477
struct i2c_msg *msgs = dev->msgs;
480478
u32 ic_tar = 0;
481-
bool enabled;
482479

483-
enabled = dw_readl(dev, DW_IC_ENABLE_STATUS) & 1;
484-
485-
if (enabled) {
486-
u32 ic_status;
487-
488-
/*
489-
* Only disable adapter if ic_tar and ic_con can't be
490-
* dynamically updated
491-
*/
492-
ic_status = dw_readl(dev, DW_IC_STATUS);
493-
if (!dev->dynamic_tar_update_enabled ||
494-
(ic_status & DW_IC_STATUS_MST_ACTIVITY) ||
495-
!(ic_status & DW_IC_STATUS_TFE)) {
496-
__i2c_dw_enable_and_wait(dev, false);
497-
enabled = false;
498-
}
499-
}
480+
/* Disable the adapter */
481+
__i2c_dw_enable_and_wait(dev, false);
500482

501483
/* if the slave address is ten bit address, enable 10BITADDR */
502484
if (dev->dynamic_tar_update_enabled) {
@@ -526,8 +508,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
526508
/* enforce disabled interrupts (due to HW issues) */
527509
i2c_dw_disable_int(dev);
528510

529-
if (!enabled)
530-
__i2c_dw_enable(dev, true);
511+
/* Enable the adapter */
512+
__i2c_dw_enable(dev, true);
531513

532514
/* Clear and enable interrupts */
533515
dw_readl(dev, DW_IC_CLR_INTR);
@@ -611,7 +593,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
611593
if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
612594

613595
/* avoid rx buffer overrun */
614-
if (rx_limit - dev->rx_outstanding <= 0)
596+
if (dev->rx_outstanding >= dev->rx_fifo_depth)
615597
break;
616598

617599
dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
@@ -708,8 +690,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
708690
}
709691

710692
/*
711-
* Prepare controller for a transaction and start transfer by calling
712-
* i2c_dw_xfer_init()
693+
* Prepare controller for a transaction and call i2c_dw_xfer_msg
713694
*/
714695
static int
715696
i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
@@ -752,13 +733,23 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
752733
goto done;
753734
}
754735

736+
/*
737+
* We must disable the adapter before returning and signaling the end
738+
* of the current transfer. Otherwise the hardware might continue
739+
* generating interrupts which in turn causes a race condition with
740+
* the following transfer. Needs some more investigation if the
741+
* additional interrupts are a hardware bug or this driver doesn't
742+
* handle them correctly yet.
743+
*/
744+
__i2c_dw_enable(dev, false);
745+
755746
if (dev->msg_err) {
756747
ret = dev->msg_err;
757748
goto done;
758749
}
759750

760751
/* no error */
761-
if (likely(!dev->cmd_err)) {
752+
if (likely(!dev->cmd_err && !dev->status)) {
762753
ret = num;
763754
goto done;
764755
}
@@ -768,6 +759,11 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
768759
ret = i2c_dw_handle_tx_abort(dev);
769760
goto done;
770761
}
762+
763+
if (dev->status)
764+
dev_err(dev->dev,
765+
"transfer terminated early - interrupt latency too high?\n");
766+
771767
ret = -EIO;
772768

773769
done:
@@ -888,19 +884,9 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
888884
*/
889885

890886
tx_aborted:
891-
if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET))
892-
|| dev->msg_err) {
893-
/*
894-
* We must disable interruts before returning and signaling
895-
* the end of the current transfer. Otherwise the hardware
896-
* might continue generating interrupts for non-existent
897-
* transfers.
898-
*/
899-
i2c_dw_disable_int(dev);
900-
dw_readl(dev, DW_IC_CLR_INTR);
901-
887+
if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
902888
complete(&dev->cmd_complete);
903-
} else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
889+
else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
904890
/* workaround to trigger pending interrupt */
905891
stat = dw_readl(dev, DW_IC_INTR_MASK);
906892
i2c_dw_disable_int(dev);

0 commit comments

Comments
 (0)