diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-tegra.c')
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 54 |
1 files changed, 31 insertions, 23 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index cbc2ad49043e..8280ac7cc1b7 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -123,10 +123,6 @@ #define I2C_THIGH_SHIFT 8 #define I2C_INTERFACE_TIMING_1 0x98 -#define I2C_STANDARD_MODE 100000 -#define I2C_FAST_MODE 400000 -#define I2C_FAST_PLUS_MODE 1000000 - /* Packet header size in bytes */ #define I2C_PACKET_HEADER_SIZE 12 @@ -737,8 +733,8 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit) I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT; i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR); - if (i2c_dev->bus_clk_rate > I2C_STANDARD_MODE && - i2c_dev->bus_clk_rate <= I2C_FAST_PLUS_MODE) { + if (i2c_dev->bus_clk_rate > I2C_MAX_STANDARD_MODE_FREQ && + i2c_dev->bus_clk_rate <= I2C_MAX_FAST_MODE_PLUS_FREQ) { tlow = i2c_dev->hw->tlow_fast_fastplus_mode; thigh = i2c_dev->hw->thigh_fast_fastplus_mode; tsu_thd = i2c_dev->hw->setup_hold_time_fast_fast_plus_mode; @@ -1000,14 +996,13 @@ tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev, do { u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS); - if (status) { + if (status) tegra_i2c_isr(i2c_dev->irq, i2c_dev); - if (completion_done(complete)) { - s64 delta = ktime_ms_delta(ktimeout, ktime); + if (completion_done(complete)) { + s64 delta = ktime_ms_delta(ktimeout, ktime); - return msecs_to_jiffies(delta) ?: 1; - } + return msecs_to_jiffies(delta) ?: 1; } ktime = ktime_get(); @@ -1034,14 +1029,18 @@ tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev, disable_irq(i2c_dev->irq); /* - * There is a chance that completion may happen after IRQ - * synchronization, which is done by disable_irq(). + * Under some rare circumstances (like running KASAN + + * NFS root) CPU, which handles interrupt, may stuck in + * uninterruptible state for a significant time. In this + * case we will get timeout if I2C transfer is running on + * a sibling CPU, despite of IRQ being raised. + * + * In order to handle this rare condition, the IRQ status + * needs to be checked after timeout. */ - if (ret == 0 && completion_done(complete)) { - dev_warn(i2c_dev->dev, - "completion done after timeout\n"); - ret = 1; - } + if (ret == 0) + ret = tegra_i2c_poll_completion_timeout(i2c_dev, + complete, 0); } return ret; @@ -1220,6 +1219,15 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, time_left = tegra_i2c_wait_completion_timeout( i2c_dev, &i2c_dev->dma_complete, xfer_time); + /* + * Synchronize DMA first, since dmaengine_terminate_sync() + * performs synchronization after the transfer's termination + * and we want to get a completion if transfer succeeded. + */ + dmaengine_synchronize(i2c_dev->msg_read ? + i2c_dev->rx_dma_chan : + i2c_dev->tx_dma_chan); + dmaengine_terminate_sync(i2c_dev->msg_read ? i2c_dev->rx_dma_chan : i2c_dev->tx_dma_chan); @@ -1341,7 +1349,7 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) ret = of_property_read_u32(np, "clock-frequency", &i2c_dev->bus_clk_rate); if (ret) - i2c_dev->bus_clk_rate = 100000; /* default clock rate */ + i2c_dev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; /* default clock rate */ multi_mode = of_property_read_bool(np, "multi-master"); i2c_dev->is_multimaster_mode = multi_mode; @@ -1640,12 +1648,12 @@ static int tegra_i2c_probe(struct platform_device *pdev) } } - if (i2c_dev->bus_clk_rate > I2C_FAST_MODE && - i2c_dev->bus_clk_rate <= I2C_FAST_PLUS_MODE) + if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ && + i2c_dev->bus_clk_rate <= I2C_MAX_FAST_MODE_PLUS_FREQ) i2c_dev->clk_divisor_non_hs_mode = i2c_dev->hw->clk_divisor_fast_plus_mode; - else if (i2c_dev->bus_clk_rate > I2C_STANDARD_MODE && - i2c_dev->bus_clk_rate <= I2C_FAST_MODE) + else if (i2c_dev->bus_clk_rate > I2C_MAX_STANDARD_MODE_FREQ && + i2c_dev->bus_clk_rate <= I2C_MAX_FAST_MODE_FREQ) i2c_dev->clk_divisor_non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode; else |