| From 72f79a085f6501dcfaeeb83241c6e9c2f7484942 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 12 Jan 2021 11:02:41 -0800 |
| Subject: i2c: tegra: Create i2c_writesl_vi() to use with VI I2C for filling TX |
| FIFO |
| |
| From: Sowjanya Komatineni <skomatineni@nvidia.com> |
| |
| [ Upstream commit 2f3a0828d46166d4e7df227479ed31766ee67e4a ] |
| |
| VI I2C controller has known hardware bug where immediate multiple |
| writes to TX_FIFO register gets stuck. |
| |
| Recommended software work around is to read I2C register after |
| each write to TX_FIFO register to flush out the data. |
| |
| This patch implements this work around for VI I2C controller. |
| |
| Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com> |
| Reviewed-by: Dmitry Osipenko <digetx@gmail.com> |
| Acked-by: Thierry Reding <treding@nvidia.com> |
| Signed-off-by: Wolfram Sang <wsa@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/i2c/busses/i2c-tegra.c | 22 +++++++++++++++++++++- |
| 1 file changed, 21 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c |
| index 0727383f49402..8b113ae32dc71 100644 |
| --- a/drivers/i2c/busses/i2c-tegra.c |
| +++ b/drivers/i2c/busses/i2c-tegra.c |
| @@ -326,6 +326,8 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned int reg) |
| /* read back register to make sure that register writes completed */ |
| if (reg != I2C_TX_FIFO) |
| readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg)); |
| + else if (i2c_dev->is_vi) |
| + readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, I2C_INT_STATUS)); |
| } |
| |
| static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned int reg) |
| @@ -339,6 +341,21 @@ static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data, |
| writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len); |
| } |
| |
| +static void i2c_writesl_vi(struct tegra_i2c_dev *i2c_dev, void *data, |
| + unsigned int reg, unsigned int len) |
| +{ |
| + u32 *data32 = data; |
| + |
| + /* |
| + * VI I2C controller has known hardware bug where writes get stuck |
| + * when immediate multiple writes happen to TX_FIFO register. |
| + * Recommended software work around is to read I2C register after |
| + * each write to TX_FIFO register to flush out the data. |
| + */ |
| + while (len--) |
| + i2c_writel(i2c_dev, *data32++, reg); |
| +} |
| + |
| static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data, |
| unsigned int reg, unsigned int len) |
| { |
| @@ -811,7 +828,10 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) |
| i2c_dev->msg_buf_remaining = buf_remaining; |
| i2c_dev->msg_buf = buf + words_to_transfer * BYTES_PER_FIFO_WORD; |
| |
| - i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer); |
| + if (i2c_dev->is_vi) |
| + i2c_writesl_vi(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer); |
| + else |
| + i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer); |
| |
| buf += words_to_transfer * BYTES_PER_FIFO_WORD; |
| } |
| -- |
| 2.27.0 |
| |