diff options
| author | Jarkko Nikula <jarkko.nikula@linux.intel.com> | 2016-11-25 10:22:27 -0500 |
|---|---|---|
| committer | Wolfram Sang <wsa@the-dreams.de> | 2016-11-25 17:23:25 -0500 |
| commit | 89119f08354b628548118cacd686a7700372ad19 (patch) | |
| tree | 5c7e9ad9a00f412ccda1bd5976a8658f092f4316 | |
| parent | 4d6d5f1d08d2138dc43b28966eb6200e3db2e623 (diff) | |
Revert "i2c: designware: do not disable adapter after transfer"
This reverts commit 0317e6c0f1dc1ba86b8d9dccc010c5e77b8355fa.
Srinivas reported recently touchscreen and touchpad stopped working in
Haswell based machine in Linux 4.9-rc series with timeout errors from
i2c_designware:
[ 16.508013] i2c_designware INT33C3:00: controller timed out
[ 16.508302] i2c_hid i2c-MSFT0001:02: failed to change power setting.
[ 17.532016] i2c_designware INT33C3:00: controller timed out
[ 18.556022] i2c_designware INT33C3:00: controller timed out
[ 18.556315] i2c_hid i2c-ATML1000:00: failed to retrieve report from device.
I managed to reproduce similar errors on another Haswell based machine
where touchscreen initialization fails maybe in every 1/5 - 1/2 boots.
Since root cause for these errors is not clear yet and debugging is
ongoing it's better to revert this commit as we are near to release.
Reported-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
| -rw-r--r-- | drivers/i2c/busses/i2c-designware-core.c | 55 |
1 files changed, 18 insertions, 37 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index c53058d6139c..b403fa5ecf49 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c | |||
| @@ -91,9 +91,7 @@ | |||
| 91 | DW_IC_INTR_TX_ABRT | \ | 91 | DW_IC_INTR_TX_ABRT | \ |
| 92 | DW_IC_INTR_STOP_DET) | 92 | DW_IC_INTR_STOP_DET) |
| 93 | 93 | ||
| 94 | #define DW_IC_STATUS_ACTIVITY 0x1 | 94 | #define DW_IC_STATUS_ACTIVITY 0x1 |
| 95 | #define DW_IC_STATUS_TFE BIT(2) | ||
| 96 | #define DW_IC_STATUS_MST_ACTIVITY BIT(5) | ||
| 97 | 95 | ||
| 98 | #define DW_IC_SDA_HOLD_RX_SHIFT 16 | 96 | #define DW_IC_SDA_HOLD_RX_SHIFT 16 |
| 99 | #define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT) | 97 | #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) | |||
| 478 | { | 476 | { |
| 479 | struct i2c_msg *msgs = dev->msgs; | 477 | struct i2c_msg *msgs = dev->msgs; |
| 480 | u32 ic_tar = 0; | 478 | u32 ic_tar = 0; |
| 481 | bool enabled; | ||
| 482 | 479 | ||
| 483 | enabled = dw_readl(dev, DW_IC_ENABLE_STATUS) & 1; | 480 | /* Disable the adapter */ |
| 484 | 481 | __i2c_dw_enable_and_wait(dev, false); | |
| 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 | } | ||
| 500 | 482 | ||
| 501 | /* if the slave address is ten bit address, enable 10BITADDR */ | 483 | /* if the slave address is ten bit address, enable 10BITADDR */ |
| 502 | if (dev->dynamic_tar_update_enabled) { | 484 | if (dev->dynamic_tar_update_enabled) { |
| @@ -526,8 +508,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) | |||
| 526 | /* enforce disabled interrupts (due to HW issues) */ | 508 | /* enforce disabled interrupts (due to HW issues) */ |
| 527 | i2c_dw_disable_int(dev); | 509 | i2c_dw_disable_int(dev); |
| 528 | 510 | ||
| 529 | if (!enabled) | 511 | /* Enable the adapter */ |
| 530 | __i2c_dw_enable(dev, true); | 512 | __i2c_dw_enable(dev, true); |
| 531 | 513 | ||
| 532 | /* Clear and enable interrupts */ | 514 | /* Clear and enable interrupts */ |
| 533 | dw_readl(dev, DW_IC_CLR_INTR); | 515 | dw_readl(dev, DW_IC_CLR_INTR); |
| @@ -708,8 +690,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) | |||
| 708 | } | 690 | } |
| 709 | 691 | ||
| 710 | /* | 692 | /* |
| 711 | * Prepare controller for a transaction and start transfer by calling | 693 | * Prepare controller for a transaction and call i2c_dw_xfer_msg |
| 712 | * i2c_dw_xfer_init() | ||
| 713 | */ | 694 | */ |
| 714 | static int | 695 | static int |
| 715 | i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | 696 | i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) |
| @@ -752,6 +733,16 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | |||
| 752 | goto done; | 733 | goto done; |
| 753 | } | 734 | } |
| 754 | 735 | ||
| 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 | |||
| 755 | if (dev->msg_err) { | 746 | if (dev->msg_err) { |
| 756 | ret = dev->msg_err; | 747 | ret = dev->msg_err; |
| 757 | goto done; | 748 | goto done; |
| @@ -893,19 +884,9 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) | |||
| 893 | */ | 884 | */ |
| 894 | 885 | ||
| 895 | tx_aborted: | 886 | tx_aborted: |
| 896 | if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) | 887 | if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) |
| 897 | || dev->msg_err) { | ||
| 898 | /* | ||
| 899 | * We must disable interruts before returning and signaling | ||
| 900 | * the end of the current transfer. Otherwise the hardware | ||
| 901 | * might continue generating interrupts for non-existent | ||
| 902 | * transfers. | ||
| 903 | */ | ||
| 904 | i2c_dw_disable_int(dev); | ||
| 905 | dw_readl(dev, DW_IC_CLR_INTR); | ||
| 906 | |||
| 907 | complete(&dev->cmd_complete); | 888 | complete(&dev->cmd_complete); |
| 908 | } else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) { | 889 | else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) { |
| 909 | /* workaround to trigger pending interrupt */ | 890 | /* workaround to trigger pending interrupt */ |
| 910 | stat = dw_readl(dev, DW_IC_INTR_MASK); | 891 | stat = dw_readl(dev, DW_IC_INTR_MASK); |
| 911 | i2c_dw_disable_int(dev); | 892 | i2c_dw_disable_int(dev); |
