Update the DMA initialization and checks to support GPCDMA. Also add a mechanism to fall back to PIO mode, if DMA is not available or if initialization returns error. Signed-off-by: Akhil R <akhilrajeev@xxxxxxxxxx> --- drivers/i2c/busses/i2c-tegra.c | 39 ++++++++++++++++------------------ 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 031c78ac42e6..8c4610c78b54 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -188,7 +188,6 @@ enum msg_end_type { * allowing 0 length transfers. * @supports_bus_clear: Bus Clear support to recover from bus hang during * SDA stuck low from device for some unknown reasons. - * @has_apb_dma: Support of APBDMA on corresponding Tegra chip. * @tlow_std_mode: Low period of the clock in standard mode. * @thigh_std_mode: High period of the clock in standard mode. * @tlow_fast_fastplus_mode: Low period of the clock in fast/fast-plus modes. @@ -215,7 +214,6 @@ struct tegra_i2c_hw_feature { bool has_mst_fifo; const struct i2c_adapter_quirks *quirks; bool supports_bus_clear; - bool has_apb_dma; u32 tlow_std_mode; u32 thigh_std_mode; u32 tlow_fast_fastplus_mode; @@ -253,6 +251,7 @@ struct tegra_i2c_hw_feature { * @dma_phys: handle to DMA resources * @dma_buf: pointer to allocated DMA buffer * @dma_buf_size: DMA buffer size + * @dma_support: indicates if DMA can be enabled * @dma_mode: indicates active DMA transfer * @dma_complete: DMA completion notifier * @atomic_mode: indicates active atomic transfer @@ -289,6 +288,7 @@ struct tegra_i2c_dev { bool multimaster_mode; bool atomic_mode; + bool dma_support; bool dma_mode; bool msg_read; bool is_dvc; @@ -443,13 +443,8 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev) u32 *dma_buf; int err; - if (!i2c_dev->hw->has_apb_dma || i2c_dev->is_vi) - return 0; - - if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) { - dev_dbg(i2c_dev->dev, "DMA support not enabled\n"); - return 0; - } + if (!i2c_dev->dma_support) + return -EOPNOTSUPP; chan = dma_request_chan(i2c_dev->dev, "rx"); if (IS_ERR(chan)) { @@ -486,6 +481,7 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev) err_out: tegra_i2c_release_dma(i2c_dev); if (err != -EPROBE_DEFER) { + i2c_dev->dma_support = false; dev_err(i2c_dev->dev, "cannot use DMA: %d\n", err); dev_err(i2c_dev->dev, "falling back to PIO\n"); return 0; @@ -1251,7 +1247,16 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD); i2c_dev->dma_mode = xfer_size > I2C_PIO_MODE_PREFERRED_LEN && - i2c_dev->dma_buf && !i2c_dev->atomic_mode; + i2c_dev->dma_support && !i2c_dev->atomic_mode; + + /* If DMA is not initialized, initialize it now. + * Fall back to PIO mode, if it fails. + */ + if (i2c_dev->dma_mode && !i2c_dev->dma_buf) { + err = tegra_i2c_init_dma(i2c_dev); + if (err) + i2c_dev->dma_mode = false; + } tegra_i2c_config_fifo_trig(i2c_dev, xfer_size); @@ -1473,7 +1478,6 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_mst_fifo = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = false, - .has_apb_dma = true, .tlow_std_mode = 0x4, .thigh_std_mode = 0x2, .tlow_fast_fastplus_mode = 0x4, @@ -1497,7 +1501,6 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { .has_mst_fifo = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = false, - .has_apb_dma = true, .tlow_std_mode = 0x4, .thigh_std_mode = 0x2, .tlow_fast_fastplus_mode = 0x4, @@ -1521,7 +1524,6 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { .has_mst_fifo = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = true, - .has_apb_dma = true, .tlow_std_mode = 0x4, .thigh_std_mode = 0x2, .tlow_fast_fastplus_mode = 0x4, @@ -1545,7 +1547,6 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { .has_mst_fifo = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = true, - .has_apb_dma = true, .tlow_std_mode = 0x4, .thigh_std_mode = 0x2, .tlow_fast_fastplus_mode = 0x4, @@ -1569,7 +1570,6 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { .has_mst_fifo = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = true, - .has_apb_dma = true, .tlow_std_mode = 0x4, .thigh_std_mode = 0x2, .tlow_fast_fastplus_mode = 0x4, @@ -1593,7 +1593,6 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = { .has_mst_fifo = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = true, - .has_apb_dma = false, .tlow_std_mode = 0x4, .thigh_std_mode = 0x3, .tlow_fast_fastplus_mode = 0x4, @@ -1617,7 +1616,6 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { .has_mst_fifo = true, .quirks = &tegra194_i2c_quirks, .supports_bus_clear = true, - .has_apb_dma = false, .tlow_std_mode = 0x8, .thigh_std_mode = 0x7, .tlow_fast_fastplus_mode = 0x2, @@ -1657,6 +1655,8 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) if (of_device_is_compatible(np, "nvidia,tegra210-i2c-vi")) i2c_dev->is_vi = true; + else + i2c_dev->dma_support = !!(of_find_property(np, "dmas", NULL)); } static int tegra_i2c_init_reset(struct tegra_i2c_dev *i2c_dev) @@ -1789,9 +1789,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) if (err) return err; - err = tegra_i2c_init_dma(i2c_dev); - if (err) - goto release_clocks; + tegra_i2c_init_dma(i2c_dev); /* * VI I2C is in VE power domain which is not always ON and not @@ -1838,7 +1836,6 @@ static int tegra_i2c_probe(struct platform_device *pdev) pm_runtime_disable(i2c_dev->dev); tegra_i2c_release_dma(i2c_dev); -release_clocks: tegra_i2c_release_clocks(i2c_dev); return err; -- 2.17.1