Skip to content

Commit

Permalink
i2c: designware: fix IO timeout issue for AMD controller
Browse files Browse the repository at this point in the history
Because of some hardware limitation, AMD I2C controller can't
trigger pending interrupt if interrupt status has been changed
after clearing interrupt status bits. Then, I2C will lost
interrupt and IO timeout.

According to hardware design, this patch implements a workaround
to disable i2c controller interrupt and re-enable i2c interrupt
before exiting ISR.

To reduce the performance impacts on other vendors, use unlikely
function to check flag in ISR.

Signed-off-by: Xiangliang Yu <Xiangliang.Yu@amd.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Cc: stable@kernel.org
  • Loading branch information
Xiangliang Yu authored and Wolfram Sang committed Dec 12, 2015
1 parent 5212f9a commit 2d244c8
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 1 deletion.
6 changes: 6 additions & 0 deletions drivers/i2c/busses/i2c-designware-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,12 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
tx_aborted:
if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
complete(&dev->cmd_complete);
else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
/* workaround to trigger pending interrupt */
stat = dw_readl(dev, DW_IC_INTR_MASK);
i2c_dw_disable_int(dev);
dw_writel(dev, stat, DW_IC_INTR_MASK);
}

return IRQ_HANDLED;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/i2c/busses/i2c-designware-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ struct dw_i2c_dev {

#define ACCESS_SWAP 0x00000001
#define ACCESS_16BIT 0x00000002
#define ACCESS_INTR_MASK 0x00000004

extern int i2c_dw_init(struct dw_i2c_dev *dev);
extern void i2c_dw_disable(struct dw_i2c_dev *dev);
Expand Down
7 changes: 6 additions & 1 deletion drivers/i2c/busses/i2c-designware-platdrv.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
static int dw_i2c_acpi_configure(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
const struct acpi_device_id *id;

dev->adapter.nr = -1;
dev->tx_fifo_depth = 32;
Expand All @@ -106,6 +107,10 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
&dev->sda_hold_time);

id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (id && id->driver_data)
dev->accessor_flags |= (u32)id->driver_data;

return 0;
}

Expand All @@ -116,7 +121,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT3433", 0 },
{ "80860F41", 0 },
{ "808622C1", 0 },
{ "AMD0010", 0 },
{ "AMD0010", ACCESS_INTR_MASK },
{ }
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
Expand Down

0 comments on commit 2d244c8

Please sign in to comment.