linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V15 1/6] i2c: tegra: sort all the include headers alphabetically
@ 2019-02-07 21:47 Sowjanya Komatineni
  2019-02-07 21:47 ` [PATCH V15 2/6] i2c: tegra: add bus clear Master Support Sowjanya Komatineni
                   ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-07 21:47 UTC (permalink / raw)
  To: thierry.reding, jonathanh, mkarthik, smohammed, talho
  Cc: digetx, linux-tegra, linux-kernel, linux-i2c, Sowjanya Komatineni

This patch sorts all the include headers alphabetically for the
I2C Tegra driver.

Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 [V9/V10/V11/V12/V13/V14/V15] : Rebased to 5.0-rc4
 [V3/V4/V5/V7/V8] : Removed unsued headers in tegra I2C
 [V2] 		  : Added this in V2 to sort the headers in tegra I2C

 drivers/i2c/busses/i2c-tegra.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index c77adbbea0c7..79c6aa87499b 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -6,24 +6,21 @@
  * Author: Colin Cross <ccross@android.com>
  */
 
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
-#include <linux/io.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/reset.h>
+#include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
-#include <linux/iopoll.h>
-
-#include <asm/unaligned.h>
+#include <linux/reset.h>
 
 #define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000))
 #define BYTES_PER_FIFO_WORD 4
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH V15 2/6] i2c: tegra: add bus clear Master Support
  2019-02-07 21:47 [PATCH V15 1/6] i2c: tegra: sort all the include headers alphabetically Sowjanya Komatineni
@ 2019-02-07 21:47 ` Sowjanya Komatineni
  2019-02-07 21:47 ` [PATCH V15 3/6] i2c: tegra: fix maximum transfer size Sowjanya Komatineni
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-07 21:47 UTC (permalink / raw)
  To: thierry.reding, jonathanh, mkarthik, smohammed, talho
  Cc: digetx, linux-tegra, linux-kernel, linux-i2c, Sowjanya Komatineni

Bus clear feature of Tegra I2C controller helps to recover from
bus hang when I2C master loses the bus arbitration due to the
slave device holding SDA LOW continuously for some unknown reasons.

Per I2C specification, the device that held the bus LOW should
release it within 9 clock pulses.

During bus clear operation, Tegra I2C controller sends 9 clock
pulses and terminates the transaction with STOP condition.
Upon successful bus clear operation, bus goes to idle state and
driver retries the transaction.

Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 [V9/V10/V11/V12/V13/V14/V15] : Rebased to 5.0-rc4
 [V5/V6/V7/V8]	  : Same as V4
 [V4]		  : Added I2C Bus Clear support patch to this version of series.


 drivers/i2c/busses/i2c-tegra.c | 73 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 79c6aa87499b..3758c7a2c781 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -51,6 +51,7 @@
 #define I2C_FIFO_STATUS_RX_SHIFT		0
 #define I2C_INT_MASK				0x064
 #define I2C_INT_STATUS				0x068
+#define I2C_INT_BUS_CLR_DONE			BIT(11)
 #define I2C_INT_PACKET_XFER_COMPLETE		BIT(7)
 #define I2C_INT_ALL_PACKETS_XFER_COMPLETE	BIT(6)
 #define I2C_INT_TX_FIFO_OVERFLOW		BIT(5)
@@ -93,6 +94,15 @@
 #define I2C_HEADER_MASTER_ADDR_SHIFT		12
 #define I2C_HEADER_SLAVE_ADDR_SHIFT		1
 
+#define I2C_BUS_CLEAR_CNFG			0x084
+#define I2C_BC_SCLK_THRESHOLD			9
+#define I2C_BC_SCLK_THRESHOLD_SHIFT		16
+#define I2C_BC_STOP_COND			BIT(2)
+#define I2C_BC_TERMINATE			BIT(1)
+#define I2C_BC_ENABLE				BIT(0)
+#define I2C_BUS_CLEAR_STATUS			0x088
+#define I2C_BC_STATUS				BIT(0)
+
 #define I2C_CONFIG_LOAD				0x08C
 #define I2C_MSTR_CONFIG_LOAD			BIT(0)
 #define I2C_SLV_CONFIG_LOAD			BIT(1)
@@ -154,6 +164,8 @@ enum msg_end_type {
  *		be transferred in one go.
  * @quirks: i2c adapter quirks for limiting write/read transfer size and not
  *		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.
  */
 struct tegra_i2c_hw_feature {
 	bool has_continue_xfer_support;
@@ -167,6 +179,7 @@ struct tegra_i2c_hw_feature {
 	bool has_slcg_override_reg;
 	bool has_mst_fifo;
 	const struct i2c_adapter_quirks *quirks;
+	bool supports_bus_clear;
 };
 
 /**
@@ -640,6 +653,13 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
 		goto err;
 	}
 
+	/*
+	 * I2C transfer is terminated during the bus clear so skip
+	 * processing the other interrupts.
+	 */
+	if (i2c_dev->hw->supports_bus_clear && (status & I2C_INT_BUS_CLR_DONE))
+		goto err;
+
 	if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) {
 		if (i2c_dev->msg_buf_remaining)
 			tegra_i2c_empty_rx_fifo(i2c_dev);
@@ -668,6 +688,8 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
 	tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST |
 		I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
 		I2C_INT_RX_FIFO_DATA_REQ);
+	if (i2c_dev->hw->supports_bus_clear)
+		tegra_i2c_mask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
 	i2c_writel(i2c_dev, status, I2C_INT_STATUS);
 	if (i2c_dev->is_dvc)
 		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
@@ -678,6 +700,43 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static int tegra_i2c_issue_bus_clear(struct tegra_i2c_dev *i2c_dev)
+{
+	int err;
+	unsigned long time_left;
+	u32 reg;
+
+	if (i2c_dev->hw->supports_bus_clear) {
+		reinit_completion(&i2c_dev->msg_complete);
+		reg = (I2C_BC_SCLK_THRESHOLD << I2C_BC_SCLK_THRESHOLD_SHIFT) |
+		      I2C_BC_STOP_COND | I2C_BC_TERMINATE;
+		i2c_writel(i2c_dev, reg, I2C_BUS_CLEAR_CNFG);
+		if (i2c_dev->hw->has_config_load_reg) {
+			err = tegra_i2c_wait_for_config_load(i2c_dev);
+			if (err)
+				return err;
+		}
+		reg |= I2C_BC_ENABLE;
+		i2c_writel(i2c_dev, reg, I2C_BUS_CLEAR_CNFG);
+		tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
+
+		time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
+							TEGRA_I2C_TIMEOUT);
+		if (time_left == 0) {
+			dev_err(i2c_dev->dev, "timed out for bus clear\n");
+			return -ETIMEDOUT;
+		}
+		reg = i2c_readl(i2c_dev, I2C_BUS_CLEAR_STATUS);
+		if (!(reg & I2C_BC_STATUS)) {
+			dev_err(i2c_dev->dev,
+				"un-recovered arbitration lost\n");
+			return -EIO;
+		}
+	}
+
+	return -EAGAIN;
+}
+
 static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 	struct i2c_msg *msg, enum msg_end_type end_state)
 {
@@ -759,6 +818,13 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 		return 0;
 
 	tegra_i2c_init(i2c_dev);
+	/* start recovery upon arbitration loss in single master mode */
+	if (i2c_dev->msg_err == I2C_ERR_ARBITRATION_LOST) {
+		if (!i2c_dev->is_multimaster_mode)
+			return tegra_i2c_issue_bus_clear(i2c_dev);
+		return -EAGAIN;
+	}
+
 	if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
 		if (msg->flags & I2C_M_IGNORE_NAK)
 			return 0;
@@ -853,6 +919,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
 	.has_slcg_override_reg = false,
 	.has_mst_fifo = false,
 	.quirks = &tegra_i2c_quirks,
+	.supports_bus_clear = false,
 };
 
 static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
@@ -867,6 +934,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
 	.has_slcg_override_reg = false,
 	.has_mst_fifo = false,
 	.quirks = &tegra_i2c_quirks,
+	.supports_bus_clear = false,
 };
 
 static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
@@ -881,6 +949,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
 	.has_slcg_override_reg = false,
 	.has_mst_fifo = false,
 	.quirks = &tegra_i2c_quirks,
+	.supports_bus_clear = true,
 };
 
 static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
@@ -895,6 +964,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
 	.has_slcg_override_reg = true,
 	.has_mst_fifo = false,
 	.quirks = &tegra_i2c_quirks,
+	.supports_bus_clear = true,
 };
 
 static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
@@ -909,6 +979,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
 	.has_slcg_override_reg = true,
 	.has_mst_fifo = false,
 	.quirks = &tegra_i2c_quirks,
+	.supports_bus_clear = true,
 };
 
 static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
@@ -923,6 +994,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
 	.has_slcg_override_reg = true,
 	.has_mst_fifo = true,
 	.quirks = &tegra194_i2c_quirks,
+	.supports_bus_clear = true,
 };
 
 /* Match table for of_platform binding */
@@ -974,6 +1046,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	i2c_dev->base = base;
 	i2c_dev->div_clk = div_clk;
 	i2c_dev->adapter.algo = &tegra_i2c_algo;
+	i2c_dev->adapter.retries = 1;
 	i2c_dev->irq = irq;
 	i2c_dev->cont_id = pdev->id;
 	i2c_dev->dev = &pdev->dev;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH V15 3/6] i2c: tegra: fix maximum transfer size
  2019-02-07 21:47 [PATCH V15 1/6] i2c: tegra: sort all the include headers alphabetically Sowjanya Komatineni
  2019-02-07 21:47 ` [PATCH V15 2/6] i2c: tegra: add bus clear Master Support Sowjanya Komatineni
@ 2019-02-07 21:47 ` Sowjanya Komatineni
  2019-02-07 22:09   ` Dmitry Osipenko
  2019-02-07 21:47 ` [PATCH V15 4/6] i2c: tegra: Add DMA support Sowjanya Komatineni
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-07 21:47 UTC (permalink / raw)
  To: thierry.reding, jonathanh, mkarthik, smohammed, talho
  Cc: digetx, linux-tegra, linux-kernel, linux-i2c, Sowjanya Komatineni

Tegra194 supports maximum 64K bytes transfer per packet.
Tegra186 and prior supports maximum 4K bytes transfer per packet.
This includes 12 bytes of packet header.

This patch fixes max write length to account for packet header size
for transfers.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 [V15]	: This is new patch in this series.

 drivers/i2c/busses/i2c-tegra.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 3758c7a2c781..ab474cc86e0a 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -125,6 +125,9 @@
 #define I2C_MST_FIFO_STATUS_TX_MASK		0xff0000
 #define I2C_MST_FIFO_STATUS_TX_SHIFT		16
 
+/* Packet header size in bytes */
+#define I2C_PACKET_HEADER_SIZE			12
+
 /*
  * msg_end_type: The bus control which need to be send at end of transfer.
  * @MSG_END_STOP: Send stop pulse at end of transfer.
@@ -900,11 +903,13 @@ static const struct i2c_algorithm tegra_i2c_algo = {
 static const struct i2c_adapter_quirks tegra_i2c_quirks = {
 	.flags = I2C_AQ_NO_ZERO_LEN,
 	.max_read_len = 4096,
-	.max_write_len = 4096,
+	.max_write_len = 4096 - I2C_PACKET_HEADER_SIZE,
 };
 
 static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
 	.flags = I2C_AQ_NO_ZERO_LEN,
+	.max_read_len = 65535,
+	.max_write_len = 65535 - I2C_PACKET_HEADER_SIZE,
 };
 
 static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH V15 4/6] i2c: tegra: Add DMA support
  2019-02-07 21:47 [PATCH V15 1/6] i2c: tegra: sort all the include headers alphabetically Sowjanya Komatineni
  2019-02-07 21:47 ` [PATCH V15 2/6] i2c: tegra: add bus clear Master Support Sowjanya Komatineni
  2019-02-07 21:47 ` [PATCH V15 3/6] i2c: tegra: fix maximum transfer size Sowjanya Komatineni
@ 2019-02-07 21:47 ` Sowjanya Komatineni
  2019-02-08 12:47   ` Dmitry Osipenko
  2019-02-07 21:47 ` [PATCH V15 5/6] i2c: tegra: update transfer timeout Sowjanya Komatineni
  2019-02-07 21:47 ` [PATCH V15 6/6] i2c: tegra: add i2c interface timing support Sowjanya Komatineni
  4 siblings, 1 reply; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-07 21:47 UTC (permalink / raw)
  To: thierry.reding, jonathanh, mkarthik, smohammed, talho
  Cc: digetx, linux-tegra, linux-kernel, linux-i2c, Sowjanya Komatineni

This patch adds DMA support for Tegra I2C.

Tegra I2C TX and RX FIFO depth is 8 words. PIO mode is used for
transfer size of the max FIFO depth and DMA mode is used for
transfer size higher than max FIFO depth to save CPU overhead.

PIO mode needs full intervention of CPU to fill or empty FIFO's
and also need to service multiple data requests interrupt for the
same transaction. This adds delay between data bytes of the same
transfer when CPU is fully loaded and some slave devices has
internal timeout for no bus activity and stops transaction to
avoid bus hang. DMA mode is helpful in such cases.

DMA mode is also helpful for Large transfers during downloading or
uploading FW over I2C to some external devices.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 [V15] : Moved Tegra186 hw feature structure from interface timing patch to this DMA
	 patch in V15 patch series.
	 releasing dma resource on probe failure and minor code cleanup.
 [V14] : Switched back to use dma_alloc_coherent as it guarentees contiguous device
	 dma address space.
	 Fixed FIFO Trigger level programming to construct value from scratch.
	 Previous versions does register read-modify-write without masking.
	 T20 has DVC offsets different to I2C. This version has fix to account DVC
	 offset during dma slave configuration.
 [V13] : T20 has DVC used for some power controls. This version has fix for using
	 proper DVC register offsets for DMA programming incase when used in DMA
	 mode.
 [V12] : Replaced dma_alloc_coherent with dma_alloc_attrs to force the allocated
	 buffer to be contiguous also in physical memory as Tegra194 supports max
	 64K and dma_alloc_coherent doesnt guarentee contiguous memory.
	 Changed return code from EIO to EINVAL incase of failure to obtain dma
	 descriptor.
	 Fixed coding style check issues.	 
 [V11] : Replaced deprecated dmaengine_terminate_all with dmaengine_termine_async
	 from non-atomic context and dmaengine_terminate_sync from atomic context.
	 Fixed to program fifo trigger levels properly when transfer falls back to
	 pio mode in case of dma slave configuration failure and other minor fixes.
 [V10] : APBDMA is replaced with GPCDMA on Tegra186 and Tegra194 designs.
	 Added apbdma hw support flag to now allow Tegra186 and later use
	 APBDMA driver.
	 Added explicit flow control enable for DMA slave config and error handling.
	 Moved releasing DMA resources to seperate function to reuse in
	 multiple places.
	 Updated to register tegra_i2c_driver from module level rather than subsys
	 level.
	 Other minor feedback
 [V9] :  Rebased to 5.0-rc4
	 Removed dependency of APB DMA in Kconfig and added conditional check
 	 in I2C driver to decide on using DMA mode.
	 Changed back the allocation of dma buffer during i2c probe.
	 Fixed FIFO triggers depending on DMA Vs PIO.
 [V8] :  Moved back dma init to i2c probe, removed ALL_PACKETS_XFER_COMPLETE
	 interrupt and using PACKETS_XFER_COMPLETE interrupt only and some
	 other fixes
	 Updated Kconfig for APB_DMA dependency
 [V7] :  Same as V6
 [V6] :  Updated for proper buffer allocation/freeing, channel release.
	 Updated to use exact xfer size for syncing dma buffer.
 [V5] :  Same as V4
 [V4] :  Updated to allocate DMA buffer only when DMA mode.
	 Updated to fall back to PIO mode when DMA channel request or
	 buffer allocation fails.
 [V3] :  Updated without additional buffer allocation.
 [V2] :  Updated based on V1 review feedback along with code cleanup for
	 proper implementation of DMA.


 drivers/i2c/busses/i2c-tegra.c | 425 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 378 insertions(+), 47 deletions(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index ab474cc86e0a..96553d4543e0 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -8,6 +8,8 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
@@ -42,8 +44,8 @@
 #define I2C_FIFO_CONTROL			0x05c
 #define I2C_FIFO_CONTROL_TX_FLUSH		BIT(1)
 #define I2C_FIFO_CONTROL_RX_FLUSH		BIT(0)
-#define I2C_FIFO_CONTROL_TX_TRIG_SHIFT		5
-#define I2C_FIFO_CONTROL_RX_TRIG_SHIFT		2
+#define I2C_FIFO_CONTROL_TX_TRIG(x)		(((x) - 1) << 5)
+#define I2C_FIFO_CONTROL_RX_TRIG(x)		(((x) - 1) << 2)
 #define I2C_FIFO_STATUS				0x060
 #define I2C_FIFO_STATUS_TX_MASK			0xF0
 #define I2C_FIFO_STATUS_TX_SHIFT		4
@@ -129,6 +131,13 @@
 #define I2C_PACKET_HEADER_SIZE			12
 
 /*
+ * Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
+ * above this, controller will use DMA to fill FIFO.
+ * MAX PIO len is 20 bytes excluding packet header.
+ */
+#define I2C_PIO_MODE_MAX_LEN			32
+
+/*
  * msg_end_type: The bus control which need to be send at end of transfer.
  * @MSG_END_STOP: Send stop pulse at end of transfer.
  * @MSG_END_REPEAT_START: Send repeat start at end of transfer.
@@ -169,6 +178,7 @@ 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.
  */
 struct tegra_i2c_hw_feature {
 	bool has_continue_xfer_support;
@@ -183,6 +193,7 @@ struct tegra_i2c_hw_feature {
 	bool has_mst_fifo;
 	const struct i2c_adapter_quirks *quirks;
 	bool supports_bus_clear;
+	bool has_apb_dma;
 };
 
 /**
@@ -194,6 +205,7 @@ struct tegra_i2c_hw_feature {
  * @fast_clk: clock reference for fast clock of I2C controller
  * @rst: reset control for the I2C controller
  * @base: ioremapped registers cookie
+ * @base_phys: physical base address of the I2C controller
  * @cont_id: I2C controller ID, used for packet header
  * @irq: IRQ number of transfer complete interrupt
  * @irq_disabled: used to track whether or not the interrupt is enabled
@@ -207,6 +219,13 @@ struct tegra_i2c_hw_feature {
  * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
  * @is_multimaster_mode: track if I2C controller is in multi-master mode
  * @xfer_lock: lock to serialize transfer submission and processing
+ * @tx_dma_chan: DMA transmit channel
+ * @rx_dma_chan: DMA receive channel
+ * @dma_phys: handle to DMA resources
+ * @dma_buf: pointer to allocated DMA buffer
+ * @dma_buf_size: DMA buffer size
+ * @is_curr_dma_xfer: indicates active DMA transfer
+ * @dma_complete: DMA completion notifier
  */
 struct tegra_i2c_dev {
 	struct device *dev;
@@ -216,6 +235,7 @@ struct tegra_i2c_dev {
 	struct clk *fast_clk;
 	struct reset_control *rst;
 	void __iomem *base;
+	phys_addr_t base_phys;
 	int cont_id;
 	int irq;
 	bool irq_disabled;
@@ -229,6 +249,13 @@ struct tegra_i2c_dev {
 	u16 clk_divisor_non_hs_mode;
 	bool is_multimaster_mode;
 	spinlock_t xfer_lock;
+	struct dma_chan *tx_dma_chan;
+	struct dma_chan *rx_dma_chan;
+	dma_addr_t dma_phys;
+	u32 *dma_buf;
+	unsigned int dma_buf_size;
+	bool is_curr_dma_xfer;
+	struct completion dma_complete;
 };
 
 static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
@@ -297,6 +324,109 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
 	i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
 }
 
+static void tegra_i2c_dma_complete(void *args)
+{
+	struct tegra_i2c_dev *i2c_dev = args;
+
+	complete(&i2c_dev->dma_complete);
+}
+
+static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len)
+{
+	struct dma_async_tx_descriptor *dma_desc;
+	enum dma_transfer_direction dir;
+	struct dma_chan *chan;
+
+	dev_dbg(i2c_dev->dev, "starting DMA for length: %zu\n", len);
+	reinit_completion(&i2c_dev->dma_complete);
+	dir = i2c_dev->msg_read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+	chan = i2c_dev->msg_read ? i2c_dev->rx_dma_chan : i2c_dev->tx_dma_chan;
+	dma_desc = dmaengine_prep_slave_single(chan, i2c_dev->dma_phys,
+					       len, dir, DMA_PREP_INTERRUPT |
+					       DMA_CTRL_ACK);
+	if (!dma_desc) {
+		dev_err(i2c_dev->dev, "failed to get DMA descriptor\n");
+		return -EINVAL;
+	}
+
+	dma_desc->callback = tegra_i2c_dma_complete;
+	dma_desc->callback_param = i2c_dev;
+	dmaengine_submit(dma_desc);
+	dma_async_issue_pending(chan);
+	return 0;
+}
+
+static void tegra_i2c_release_dma(struct tegra_i2c_dev *i2c_dev)
+{
+	if (i2c_dev->dma_buf) {
+		dma_free_coherent(i2c_dev->dev, i2c_dev->dma_buf_size,
+				  i2c_dev->dma_buf, i2c_dev->dma_phys);
+		i2c_dev->dma_buf = NULL;
+	}
+
+	if (i2c_dev->tx_dma_chan) {
+		dma_release_channel(i2c_dev->tx_dma_chan);
+		i2c_dev->tx_dma_chan = NULL;
+	}
+
+	if (i2c_dev->rx_dma_chan) {
+		dma_release_channel(i2c_dev->rx_dma_chan);
+		i2c_dev->rx_dma_chan = NULL;
+	}
+}
+
+static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
+{
+	struct dma_chan *chan;
+	u32 *dma_buf;
+	dma_addr_t dma_phys;
+	int err;
+
+	if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA) ||
+	    !i2c_dev->hw->has_apb_dma) {
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	chan = dma_request_slave_channel_reason(i2c_dev->dev, "rx");
+	if (IS_ERR(chan)) {
+		err = PTR_ERR(chan);
+		goto err_out;
+	}
+
+	i2c_dev->rx_dma_chan = chan;
+
+	chan = dma_request_slave_channel_reason(i2c_dev->dev, "tx");
+	if (IS_ERR(chan)) {
+		err = PTR_ERR(chan);
+		goto err_out;
+	}
+
+	i2c_dev->tx_dma_chan = chan;
+
+	dma_buf = dma_alloc_coherent(i2c_dev->dev, i2c_dev->dma_buf_size,
+				     &dma_phys, GFP_KERNEL | __GFP_NOWARN);
+	if (!dma_buf) {
+		dev_err(i2c_dev->dev, "failed to allocate the DMA buffer\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	i2c_dev->dma_buf = dma_buf;
+	i2c_dev->dma_phys = dma_phys;
+	return 0;
+
+err_out:
+	tegra_i2c_release_dma(i2c_dev);
+	if (err != -EPROBE_DEFER) {
+		dev_err(i2c_dev->dev, "cannot use DMA: %d\n", err);
+		dev_err(i2c_dev->dev, "fallbacking to PIO\n");
+		return 0;
+	}
+
+	return err;
+}
+
 static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
 {
 	unsigned long timeout = jiffies + HZ;
@@ -574,16 +704,6 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 		i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
 	}
 
-	if (i2c_dev->hw->has_mst_fifo) {
-		val = I2C_MST_FIFO_CONTROL_TX_TRIG(8) |
-		      I2C_MST_FIFO_CONTROL_RX_TRIG(1);
-		i2c_writel(i2c_dev, val, I2C_MST_FIFO_CONTROL);
-	} else {
-		val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
-			0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
-		i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
-	}
-
 	err = tegra_i2c_flush_fifos(i2c_dev);
 	if (err)
 		goto err;
@@ -663,25 +783,37 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
 	if (i2c_dev->hw->supports_bus_clear && (status & I2C_INT_BUS_CLR_DONE))
 		goto err;
 
-	if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) {
-		if (i2c_dev->msg_buf_remaining)
-			tegra_i2c_empty_rx_fifo(i2c_dev);
-		else
-			BUG();
-	}
+	if (!i2c_dev->is_curr_dma_xfer) {
+		if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) {
+			if (i2c_dev->msg_buf_remaining)
+				tegra_i2c_empty_rx_fifo(i2c_dev);
+			else
+				BUG();
+		}
 
-	if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) {
-		if (i2c_dev->msg_buf_remaining)
-			tegra_i2c_fill_tx_fifo(i2c_dev);
-		else
-			tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
+		if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) {
+			if (i2c_dev->msg_buf_remaining)
+				tegra_i2c_fill_tx_fifo(i2c_dev);
+			else
+				tegra_i2c_mask_irq(i2c_dev,
+						   I2C_INT_TX_FIFO_DATA_REQ);
+		}
 	}
 
 	i2c_writel(i2c_dev, status, I2C_INT_STATUS);
 	if (i2c_dev->is_dvc)
 		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
 
+	/*
+	 * During message read XFER_COMPLETE interrupt is triggered prior to
+	 * DMA completion and during message write XFER_COMPLETE interrupt is
+	 * triggered after DMA completion.
+	 * PACKETS_XFER_COMPLETE indicates completion of all bytes of transfer.
+	 * so forcing msg_buf_remaining to 0 in DMA mode.
+	 */
 	if (status & I2C_INT_PACKET_XFER_COMPLETE) {
+		if (i2c_dev->is_curr_dma_xfer)
+			i2c_dev->msg_buf_remaining = 0;
 		BUG_ON(i2c_dev->msg_buf_remaining);
 		complete(&i2c_dev->msg_complete);
 	}
@@ -697,12 +829,91 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
 	if (i2c_dev->is_dvc)
 		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
 
+	if (i2c_dev->is_curr_dma_xfer) {
+		if (i2c_dev->msg_read)
+			dmaengine_terminate_async(i2c_dev->rx_dma_chan);
+		else
+			dmaengine_terminate_async(i2c_dev->tx_dma_chan);
+
+		complete(&i2c_dev->dma_complete);
+	}
+
 	complete(&i2c_dev->msg_complete);
 done:
 	spin_unlock(&i2c_dev->xfer_lock);
 	return IRQ_HANDLED;
 }
 
+static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
+				       size_t len)
+{
+	u32 val, reg;
+	u8 dma_burst;
+	struct dma_slave_config slv_config = {0};
+	struct dma_chan *chan;
+	int ret;
+	unsigned long reg_offset;
+
+	if (i2c_dev->hw->has_mst_fifo)
+		reg = I2C_MST_FIFO_CONTROL;
+	else
+		reg = I2C_FIFO_CONTROL;
+
+	if (i2c_dev->is_curr_dma_xfer) {
+		if (len & 0xF)
+			dma_burst = 1;
+		else if (len & 0x10)
+			dma_burst = 4;
+		else
+			dma_burst = 8;
+
+		if (i2c_dev->msg_read) {
+			chan = i2c_dev->rx_dma_chan;
+			reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_RX_FIFO);
+			slv_config.src_addr = i2c_dev->base_phys + reg_offset;
+			slv_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+			slv_config.src_maxburst = dma_burst;
+
+			if (i2c_dev->hw->has_mst_fifo)
+				val = I2C_MST_FIFO_CONTROL_RX_TRIG(dma_burst);
+			else
+				val = I2C_FIFO_CONTROL_RX_TRIG(dma_burst);
+		} else {
+			chan = i2c_dev->tx_dma_chan;
+			reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_TX_FIFO);
+			slv_config.dst_addr = i2c_dev->base_phys + reg_offset;
+			slv_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+			slv_config.dst_maxburst = dma_burst;
+
+			if (i2c_dev->hw->has_mst_fifo)
+				val = I2C_MST_FIFO_CONTROL_TX_TRIG(dma_burst);
+			else
+				val = I2C_FIFO_CONTROL_TX_TRIG(dma_burst);
+		}
+
+		slv_config.device_fc = true;
+		ret = dmaengine_slave_config(chan, &slv_config);
+		if (ret < 0) {
+			dev_err(i2c_dev->dev, "DMA slave config failed: %d\n",
+				ret);
+			dev_err(i2c_dev->dev, "fallbacking to PIO\n");
+			tegra_i2c_release_dma(i2c_dev);
+			i2c_dev->is_curr_dma_xfer = false;
+		} else {
+			goto out;
+		}
+	}
+
+	if (i2c_dev->hw->has_mst_fifo)
+		val = I2C_MST_FIFO_CONTROL_TX_TRIG(8) |
+		      I2C_MST_FIFO_CONTROL_RX_TRIG(1);
+	else
+		val = I2C_FIFO_CONTROL_TX_TRIG(8) |
+		      I2C_FIFO_CONTROL_RX_TRIG(1);
+out:
+	i2c_writel(i2c_dev, val, reg);
+}
+
 static int tegra_i2c_issue_bus_clear(struct tegra_i2c_dev *i2c_dev)
 {
 	int err;
@@ -747,6 +958,10 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 	u32 int_mask;
 	unsigned long time_left;
 	unsigned long flags;
+	size_t xfer_size;
+	u32 *buffer = NULL;
+	int err = 0;
+	bool dma;
 
 	tegra_i2c_flush_fifos(i2c_dev);
 
@@ -756,19 +971,57 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 	i2c_dev->msg_read = (msg->flags & I2C_M_RD);
 	reinit_completion(&i2c_dev->msg_complete);
 
+	if (i2c_dev->msg_read)
+		xfer_size = msg->len;
+	else
+		xfer_size = msg->len + I2C_PACKET_HEADER_SIZE;
+
+	xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD);
+	i2c_dev->is_curr_dma_xfer = (xfer_size > I2C_PIO_MODE_MAX_LEN) &&
+				    i2c_dev->dma_buf;
+	tegra_i2c_config_fifo_trig(i2c_dev, xfer_size);
+	dma = i2c_dev->is_curr_dma_xfer;
 	spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
 
 	int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
 	tegra_i2c_unmask_irq(i2c_dev, int_mask);
+	if (dma) {
+		if (i2c_dev->msg_read) {
+			dma_sync_single_for_device(i2c_dev->dev,
+						   i2c_dev->dma_phys,
+						   xfer_size,
+						   DMA_FROM_DEVICE);
+			err = tegra_i2c_dma_submit(i2c_dev, xfer_size);
+			if (err < 0) {
+				dev_err(i2c_dev->dev,
+					"starting RX DMA failed, err %d\n",
+					err);
+				goto unlock;
+			}
+
+		} else {
+			dma_sync_single_for_cpu(i2c_dev->dev,
+						i2c_dev->dma_phys,
+						xfer_size,
+						DMA_TO_DEVICE);
+			buffer = i2c_dev->dma_buf;
+		}
+	}
 
 	packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
 			PACKET_HEADER0_PROTOCOL_I2C |
 			(i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) |
 			(1 << PACKET_HEADER0_PACKET_ID_SHIFT);
-	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+	if (dma && !i2c_dev->msg_read)
+		*buffer++ = packet_header;
+	else
+		i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
 
 	packet_header = msg->len - 1;
-	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+	if (dma && !i2c_dev->msg_read)
+		*buffer++ = packet_header;
+	else
+		i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
 
 	packet_header = I2C_HEADER_IE_ENABLE;
 	if (end_state == MSG_END_CONTINUE)
@@ -785,27 +1038,81 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 		packet_header |= I2C_HEADER_CONT_ON_NAK;
 	if (msg->flags & I2C_M_RD)
 		packet_header |= I2C_HEADER_READ;
-	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
-
-	if (!(msg->flags & I2C_M_RD))
-		tegra_i2c_fill_tx_fifo(i2c_dev);
+	if (dma && !i2c_dev->msg_read)
+		*buffer++ = packet_header;
+	else
+		i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+	if (!i2c_dev->msg_read) {
+		if (dma) {
+			memcpy(buffer, msg->buf, msg->len);
+			dma_sync_single_for_device(i2c_dev->dev,
+						   i2c_dev->dma_phys,
+						   xfer_size,
+						   DMA_TO_DEVICE);
+			err = tegra_i2c_dma_submit(i2c_dev, xfer_size);
+			if (err < 0) {
+				dev_err(i2c_dev->dev,
+					"starting TX DMA failed, err %d\n",
+					err);
+				goto unlock;
+			}
+		} else {
+			tegra_i2c_fill_tx_fifo(i2c_dev);
+		}
+	}
 
 	if (i2c_dev->hw->has_per_pkt_xfer_complete_irq)
 		int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
-	if (msg->flags & I2C_M_RD)
-		int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
-	else if (i2c_dev->msg_buf_remaining)
-		int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
+
+	if (!dma) {
+		if (msg->flags & I2C_M_RD)
+			int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
+		else if (i2c_dev->msg_buf_remaining)
+			int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
+	}
 
 	tegra_i2c_unmask_irq(i2c_dev, int_mask);
-	spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
 	dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
 		i2c_readl(i2c_dev, I2C_INT_MASK));
 
+unlock:
+	spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
+
+	if (dma) {
+		if (err)
+			return err;
+
+		time_left = wait_for_completion_timeout(
+						&i2c_dev->dma_complete,
+						TEGRA_I2C_TIMEOUT);
+		if (time_left == 0) {
+			dev_err(i2c_dev->dev, "DMA transfer timeout\n");
+			dmaengine_terminate_sync(i2c_dev->msg_read ?
+						 i2c_dev->rx_dma_chan :
+						 i2c_dev->tx_dma_chan);
+			tegra_i2c_init(i2c_dev);
+			return -ETIMEDOUT;
+		}
+
+		if (i2c_dev->msg_read && i2c_dev->msg_err == I2C_ERR_NONE) {
+			dma_sync_single_for_cpu(i2c_dev->dev,
+						i2c_dev->dma_phys,
+						xfer_size,
+						DMA_FROM_DEVICE);
+			memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf,
+			       msg->len);
+		}
+
+		if (i2c_dev->msg_err != I2C_ERR_NONE)
+			dmaengine_synchronize(i2c_dev->msg_read ?
+					      i2c_dev->rx_dma_chan :
+					      i2c_dev->tx_dma_chan);
+	}
+
 	time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
 						TEGRA_I2C_TIMEOUT);
 	tegra_i2c_mask_irq(i2c_dev, int_mask);
-
 	if (time_left == 0) {
 		dev_err(i2c_dev->dev, "i2c transfer timed out\n");
 
@@ -817,6 +1124,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 		time_left, completion_done(&i2c_dev->msg_complete),
 		i2c_dev->msg_err);
 
+	i2c_dev->is_curr_dma_xfer = false;
 	if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
 		return 0;
 
@@ -925,6 +1233,7 @@ 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,
 };
 
 static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
@@ -940,6 +1249,7 @@ 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,
 };
 
 static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
@@ -955,6 +1265,7 @@ 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,
 };
 
 static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
@@ -970,6 +1281,7 @@ 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,
 };
 
 static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
@@ -985,6 +1297,23 @@ 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,
+};
+
+static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
+	.has_continue_xfer_support = true,
+	.has_per_pkt_xfer_complete_irq = true,
+	.has_single_clk_source = true,
+	.clk_divisor_hs_mode = 1,
+	.clk_divisor_std_fast_mode = 0x19,
+	.clk_divisor_fast_plus_mode = 0x10,
+	.has_config_load_reg = true,
+	.has_multi_master_mode = true,
+	.has_slcg_override_reg = true,
+	.has_mst_fifo = true,
+	.quirks = &tegra_i2c_quirks,
+	.supports_bus_clear = true,
+	.has_apb_dma = false,
 };
 
 static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
@@ -1000,11 +1329,13 @@ 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,
 };
 
 /* Match table for of_platform binding */
 static const struct of_device_id tegra_i2c_of_match[] = {
 	{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
+	{ .compatible = "nvidia,tegra186-i2c", .data = &tegra186_i2c_hw, },
 	{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
 	{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
 	{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
@@ -1022,11 +1353,13 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	struct clk *div_clk;
 	struct clk *fast_clk;
 	void __iomem *base;
+	phys_addr_t base_phys;
 	int irq;
 	int ret = 0;
 	int clk_multiplier = I2C_CLK_MULTIPLIER_STD_FAST_MODE;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base_phys = res->start;
 	base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(base))
 		return PTR_ERR(base);
@@ -1049,6 +1382,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	i2c_dev->base = base;
+	i2c_dev->base_phys = base_phys;
 	i2c_dev->div_clk = div_clk;
 	i2c_dev->adapter.algo = &tegra_i2c_algo;
 	i2c_dev->adapter.retries = 1;
@@ -1068,7 +1402,9 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
 						  "nvidia,tegra20-i2c-dvc");
 	i2c_dev->adapter.quirks = i2c_dev->hw->quirks;
+	i2c_dev->dma_buf_size = i2c_dev->adapter.quirks->max_read_len;
 	init_completion(&i2c_dev->msg_complete);
+	init_completion(&i2c_dev->dma_complete);
 	spin_lock_init(&i2c_dev->xfer_lock);
 
 	if (!i2c_dev->hw->has_single_clk_source) {
@@ -1129,6 +1465,10 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 		}
 	}
 
+	ret = tegra_i2c_init_dma(i2c_dev);
+	if (ret < 0)
+		goto disable_div_clk;
+
 	ret = tegra_i2c_init(i2c_dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to initialize i2c controller\n");
@@ -1160,6 +1500,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 disable_div_clk:
 	if (i2c_dev->is_multimaster_mode)
 		clk_disable(i2c_dev->div_clk);
+	tegra_i2c_release_dma(i2c_dev);
 
 disable_rpm:
 	pm_runtime_disable(&pdev->dev);
@@ -1193,6 +1534,7 @@ static int tegra_i2c_remove(struct platform_device *pdev)
 	if (!i2c_dev->hw->has_single_clk_source)
 		clk_unprepare(i2c_dev->fast_clk);
 
+	tegra_i2c_release_dma(i2c_dev);
 	return 0;
 }
 
@@ -1216,18 +1558,7 @@ static struct platform_driver tegra_i2c_driver = {
 	},
 };
 
-static int __init tegra_i2c_init_driver(void)
-{
-	return platform_driver_register(&tegra_i2c_driver);
-}
-
-static void __exit tegra_i2c_exit_driver(void)
-{
-	platform_driver_unregister(&tegra_i2c_driver);
-}
-
-subsys_initcall(tegra_i2c_init_driver);
-module_exit(tegra_i2c_exit_driver);
+module_platform_driver(tegra_i2c_driver);
 
 MODULE_DESCRIPTION("nVidia Tegra2 I2C Bus Controller driver");
 MODULE_AUTHOR("Colin Cross");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH V15 5/6] i2c: tegra: update transfer timeout
  2019-02-07 21:47 [PATCH V15 1/6] i2c: tegra: sort all the include headers alphabetically Sowjanya Komatineni
                   ` (2 preceding siblings ...)
  2019-02-07 21:47 ` [PATCH V15 4/6] i2c: tegra: Add DMA support Sowjanya Komatineni
@ 2019-02-07 21:47 ` Sowjanya Komatineni
  2019-02-07 21:47 ` [PATCH V15 6/6] i2c: tegra: add i2c interface timing support Sowjanya Komatineni
  4 siblings, 0 replies; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-07 21:47 UTC (permalink / raw)
  To: thierry.reding, jonathanh, mkarthik, smohammed, talho
  Cc: digetx, linux-tegra, linux-kernel, linux-i2c, Sowjanya Komatineni

Tegra194 allows max of 64K bytes and Tegra186 and prior allows
max of 4K bytes of transfer per packet.

one sec timeout is not enough for transfers more than 10K bytes
at STD bus rate.

This patch updates I2C transfer timeout based on the transfer size
and I2C bus rate to allow enough time during max transfer size at
lower bus speed.

Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 [V11/V12/V13/V14/V15] : Same as V10
 [V10] : Reduced the timeout for bus clear operation
	Added adapter timeout to cover worst case transfer rate (max transfer
	size at STD speed) incase if ARB LOST happens during middle/end of 
	the transaction.
 [V9] : Rebased to 5.0-rc4
	Minor updates for readability of xfer time
 [V8] : Added comment with explaination of xfer time calculation
 [V5/V6/V7] : Same as V4
 [V4] : V4 series includes bus clear support and this patch is updated with
	fixed timeout of 1sec for bus clear operation.
 [V3] : Same as V2
 [V2] : Added this patch in V2 series to allow enough time for data transfer
	to happen.
	This patch has dependency with DMA patch as TEGRA_I2C_TIMEOUT define
	takes argument with this patch.


 drivers/i2c/busses/i2c-tegra.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 96553d4543e0..044e4967f1ba 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -24,7 +24,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
 
-#define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000))
 #define BYTES_PER_FIFO_WORD 4
 
 #define I2C_CNFG				0x000
@@ -935,7 +934,7 @@ static int tegra_i2c_issue_bus_clear(struct tegra_i2c_dev *i2c_dev)
 		tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
 
 		time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
-							TEGRA_I2C_TIMEOUT);
+							msecs_to_jiffies(50));
 		if (time_left == 0) {
 			dev_err(i2c_dev->dev, "timed out for bus clear\n");
 			return -ETIMEDOUT;
@@ -962,6 +961,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 	u32 *buffer = NULL;
 	int err = 0;
 	bool dma;
+	u16 xfer_time = 100;
 
 	tegra_i2c_flush_fifos(i2c_dev);
 
@@ -981,6 +981,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 				    i2c_dev->dma_buf;
 	tegra_i2c_config_fifo_trig(i2c_dev, xfer_size);
 	dma = i2c_dev->is_curr_dma_xfer;
+	/*
+	 * Transfer time in mSec = Total bits / transfer rate
+	 * Total bits = 9 bits per byte (including ACK bit) + Start & stop bits
+	 */
+	xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
+					i2c_dev->bus_clk_rate);
 	spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
 
 	int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
@@ -1085,7 +1091,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
 		time_left = wait_for_completion_timeout(
 						&i2c_dev->dma_complete,
-						TEGRA_I2C_TIMEOUT);
+						msecs_to_jiffies(xfer_time));
 		if (time_left == 0) {
 			dev_err(i2c_dev->dev, "DMA transfer timeout\n");
 			dmaengine_terminate_sync(i2c_dev->msg_read ?
@@ -1111,7 +1117,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 	}
 
 	time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
-						TEGRA_I2C_TIMEOUT);
+						msecs_to_jiffies(xfer_time));
 	tegra_i2c_mask_irq(i2c_dev, int_mask);
 	if (time_left == 0) {
 		dev_err(i2c_dev->dev, "i2c transfer timed out\n");
@@ -1386,6 +1392,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	i2c_dev->div_clk = div_clk;
 	i2c_dev->adapter.algo = &tegra_i2c_algo;
 	i2c_dev->adapter.retries = 1;
+	i2c_dev->adapter.timeout = 6 * HZ;
 	i2c_dev->irq = irq;
 	i2c_dev->cont_id = pdev->id;
 	i2c_dev->dev = &pdev->dev;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH V15 6/6] i2c: tegra: add i2c interface timing support
  2019-02-07 21:47 [PATCH V15 1/6] i2c: tegra: sort all the include headers alphabetically Sowjanya Komatineni
                   ` (3 preceding siblings ...)
  2019-02-07 21:47 ` [PATCH V15 5/6] i2c: tegra: update transfer timeout Sowjanya Komatineni
@ 2019-02-07 21:47 ` Sowjanya Komatineni
  2019-02-08 12:53   ` Dmitry Osipenko
  4 siblings, 1 reply; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-07 21:47 UTC (permalink / raw)
  To: thierry.reding, jonathanh, mkarthik, smohammed, talho
  Cc: digetx, linux-tegra, linux-kernel, linux-i2c, Sowjanya Komatineni

This patch adds I2C interface timing registers support for
proper bus rate configuration along with meeting the I2C spec
setup and hold times based on the tuning performed on Tegra210,
Tegra186 and Tegra194 platforms.

I2C_INTERFACE_TIMING_0 register contains TLOW and THIGH field
and Tegra I2C controller design uses them as a part of internal
clock divisor.

I2C_INTERFACE_TIMING_1 register contains the setup and hold times
for start and stop conditions.

Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
---
 [V15]		: Moved Tegra186 hw feature structure to DMA patch of this series.
 [V14]		: INTERFACE_TIMING registers doesnt exist on Tegra114 and prior.
		  Added flag to hw feature to identify this and program only on supported
		  tegra chips.
 [V13]		: Same as V12
 [V12] 		: Fixed strict coding style check issues
 [V9/V10/V11]	: Same as V8
 [V8] 		: Updated to handle timing implementation within tegra_i2c_init directly
 [V7] 		: Minor updates to timing implementation
 [V5/V6] 	: Added this Interface timing patch in V5 of the patch series.


 drivers/i2c/busses/i2c-tegra.c | 185 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 155 insertions(+), 30 deletions(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 044e4967f1ba..7104213d813b 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -126,6 +126,15 @@
 #define I2C_MST_FIFO_STATUS_TX_MASK		0xff0000
 #define I2C_MST_FIFO_STATUS_TX_SHIFT		16
 
+#define I2C_INTERFACE_TIMING_0			0x94
+#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
+#define I2C_HS_MODE				3500000
+
 /* Packet header size in bytes */
 #define I2C_PACKET_HEADER_SIZE			12
 
@@ -160,7 +169,10 @@ enum msg_end_type {
  * @has_config_load_reg: Has the config load register to load the new
  *		configuration.
  * @clk_divisor_hs_mode: Clock divisor in HS mode.
- * @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is
+ * @clk_divisor_std_mode: Clock divisor in standard mode. It is
+ *		applicable if there is no fast clock source i.e. single clock
+ *		source.
+ * @clk_divisor_fast_mode: Clock divisor in fast mode. It is
  *		applicable if there is no fast clock source i.e. single clock
  *		source.
  * @clk_divisor_fast_plus_mode: Clock divisor in fast mode plus. It is
@@ -178,6 +190,18 @@ enum msg_end_type {
  * @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.
+ * @thigh_fast_fastplus_mode: High period of the clock in fast/fast-plus modes.
+ * @setup_hold_time_std_mode: Setup and hold time for start and stop conditions
+ *		in standard mode.
+ * @setup_hold_time_fast_fast_plus_mode: Setup and hold time for start and stop
+ *		conditions in fast/fast-plus modes.
+ * @setup_hold_time_hs_mode: Setup and hold time for start and stop conditions
+ *		in HS mode.
+ * @has_interface_timing_reg: Has interface timing register to program the tuned
+ *		timing settings.
  */
 struct tegra_i2c_hw_feature {
 	bool has_continue_xfer_support;
@@ -185,7 +209,8 @@ struct tegra_i2c_hw_feature {
 	bool has_single_clk_source;
 	bool has_config_load_reg;
 	int clk_divisor_hs_mode;
-	int clk_divisor_std_fast_mode;
+	int clk_divisor_std_mode;
+	int clk_divisor_fast_mode;
 	u16 clk_divisor_fast_plus_mode;
 	bool has_multi_master_mode;
 	bool has_slcg_override_reg;
@@ -193,6 +218,14 @@ struct tegra_i2c_hw_feature {
 	const struct i2c_adapter_quirks *quirks;
 	bool supports_bus_clear;
 	bool has_apb_dma;
+	u8 tlow_std_mode;
+	u8 thigh_std_mode;
+	u8 tlow_fast_fastplus_mode;
+	u8 thigh_fast_fastplus_mode;
+	u32 setup_hold_time_std_mode;
+	u32 setup_hold_time_fast_fast_plus_mode;
+	u32 setup_hold_time_hs_mode;
+	bool has_interface_timing_reg;
 };
 
 /**
@@ -660,11 +693,13 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
 	return 0;
 }
 
-static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
+static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
 {
 	u32 val;
 	int err;
-	u32 clk_divisor;
+	u32 clk_divisor, clk_multiplier;
+	u32 tsu_thd = 0;
+	u8 tlow, thigh;
 
 	err = pm_runtime_get_sync(i2c_dev->dev);
 	if (err < 0) {
@@ -694,6 +729,37 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 					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) {
+		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;
+	} else {
+		tlow = i2c_dev->hw->tlow_std_mode;
+		thigh = i2c_dev->hw->thigh_std_mode;
+		tsu_thd = i2c_dev->hw->setup_hold_time_std_mode;
+	}
+
+	if (i2c_dev->hw->has_interface_timing_reg && val) {
+		val = (thigh << I2C_THIGH_SHIFT) | tlow;
+		i2c_writel(i2c_dev, val, I2C_INTERFACE_TIMING_0);
+	}
+
+	if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
+		i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
+
+	if (!clk_reinit) {
+		clk_multiplier = (tlow + thigh + 2);
+		clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1);
+		err = clk_set_rate(i2c_dev->div_clk,
+				   i2c_dev->bus_clk_rate * clk_multiplier);
+		if (err) {
+			dev_err(i2c_dev->dev,
+				"failed changing clock rate: %d\n", err);
+			goto err;
+		}
+	}
+
 	if (!i2c_dev->is_dvc) {
 		u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
 
@@ -1097,7 +1163,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 			dmaengine_terminate_sync(i2c_dev->msg_read ?
 						 i2c_dev->rx_dma_chan :
 						 i2c_dev->tx_dma_chan);
-			tegra_i2c_init(i2c_dev);
+			tegra_i2c_init(i2c_dev, true);
 			return -ETIMEDOUT;
 		}
 
@@ -1122,7 +1188,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 	if (time_left == 0) {
 		dev_err(i2c_dev->dev, "i2c transfer timed out\n");
 
-		tegra_i2c_init(i2c_dev);
+		tegra_i2c_init(i2c_dev, true);
 		return -ETIMEDOUT;
 	}
 
@@ -1134,7 +1200,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 	if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
 		return 0;
 
-	tegra_i2c_init(i2c_dev);
+	tegra_i2c_init(i2c_dev, true);
 	/* start recovery upon arbitration loss in single master mode */
 	if (i2c_dev->msg_err == I2C_ERR_ARBITRATION_LOST) {
 		if (!i2c_dev->is_multimaster_mode)
@@ -1231,7 +1297,8 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
 	.has_per_pkt_xfer_complete_irq = false,
 	.has_single_clk_source = false,
 	.clk_divisor_hs_mode = 3,
-	.clk_divisor_std_fast_mode = 0,
+	.clk_divisor_std_mode = 0,
+	.clk_divisor_fast_mode = 0,
 	.clk_divisor_fast_plus_mode = 0,
 	.has_config_load_reg = false,
 	.has_multi_master_mode = false,
@@ -1240,6 +1307,14 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
 	.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,
+	.thigh_fast_fastplus_mode = 0x2,
+	.setup_hold_time_std_mode = 0x0,
+	.setup_hold_time_fast_fast_plus_mode = 0x0,
+	.setup_hold_time_hs_mode = 0x0,
+	.has_interface_timing_reg = false,
 };
 
 static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
@@ -1247,7 +1322,8 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
 	.has_per_pkt_xfer_complete_irq = false,
 	.has_single_clk_source = false,
 	.clk_divisor_hs_mode = 3,
-	.clk_divisor_std_fast_mode = 0,
+	.clk_divisor_std_mode = 0,
+	.clk_divisor_fast_mode = 0,
 	.clk_divisor_fast_plus_mode = 0,
 	.has_config_load_reg = false,
 	.has_multi_master_mode = false,
@@ -1256,6 +1332,14 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
 	.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,
+	.thigh_fast_fastplus_mode = 0x2,
+	.setup_hold_time_std_mode = 0x0,
+	.setup_hold_time_fast_fast_plus_mode = 0x0,
+	.setup_hold_time_hs_mode = 0x0,
+	.has_interface_timing_reg = false,
 };
 
 static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
@@ -1263,7 +1347,8 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
 	.has_per_pkt_xfer_complete_irq = true,
 	.has_single_clk_source = true,
 	.clk_divisor_hs_mode = 1,
-	.clk_divisor_std_fast_mode = 0x19,
+	.clk_divisor_std_mode = 0x19,
+	.clk_divisor_fast_mode = 0x19,
 	.clk_divisor_fast_plus_mode = 0x10,
 	.has_config_load_reg = false,
 	.has_multi_master_mode = false,
@@ -1272,6 +1357,14 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
 	.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,
+	.thigh_fast_fastplus_mode = 0x2,
+	.setup_hold_time_std_mode = 0x0,
+	.setup_hold_time_fast_fast_plus_mode = 0x0,
+	.setup_hold_time_hs_mode = 0x0,
+	.has_interface_timing_reg = false,
 };
 
 static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
@@ -1279,7 +1372,8 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
 	.has_per_pkt_xfer_complete_irq = true,
 	.has_single_clk_source = true,
 	.clk_divisor_hs_mode = 1,
-	.clk_divisor_std_fast_mode = 0x19,
+	.clk_divisor_std_mode = 0x19,
+	.clk_divisor_fast_mode = 0x19,
 	.clk_divisor_fast_plus_mode = 0x10,
 	.has_config_load_reg = true,
 	.has_multi_master_mode = false,
@@ -1288,6 +1382,14 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
 	.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,
+	.thigh_fast_fastplus_mode = 0x2,
+	.setup_hold_time_std_mode = 0x0,
+	.setup_hold_time_fast_fast_plus_mode = 0x0,
+	.setup_hold_time_hs_mode = 0x0,
+	.has_interface_timing_reg = true,
 };
 
 static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
@@ -1295,7 +1397,8 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
 	.has_per_pkt_xfer_complete_irq = true,
 	.has_single_clk_source = true,
 	.clk_divisor_hs_mode = 1,
-	.clk_divisor_std_fast_mode = 0x19,
+	.clk_divisor_std_mode = 0x19,
+	.clk_divisor_fast_mode = 0x19,
 	.clk_divisor_fast_plus_mode = 0x10,
 	.has_config_load_reg = true,
 	.has_multi_master_mode = true,
@@ -1304,6 +1407,14 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
 	.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,
+	.thigh_fast_fastplus_mode = 0x2,
+	.setup_hold_time_std_mode = 0,
+	.setup_hold_time_fast_fast_plus_mode = 0,
+	.setup_hold_time_hs_mode = 0,
+	.has_interface_timing_reg = true,
 };
 
 static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
@@ -1311,7 +1422,8 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
 	.has_per_pkt_xfer_complete_irq = true,
 	.has_single_clk_source = true,
 	.clk_divisor_hs_mode = 1,
-	.clk_divisor_std_fast_mode = 0x19,
+	.clk_divisor_std_mode = 0x16,
+	.clk_divisor_fast_mode = 0x19,
 	.clk_divisor_fast_plus_mode = 0x10,
 	.has_config_load_reg = true,
 	.has_multi_master_mode = true,
@@ -1320,6 +1432,14 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
 	.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,
+	.thigh_fast_fastplus_mode = 0x2,
+	.setup_hold_time_std_mode = 0,
+	.setup_hold_time_fast_fast_plus_mode = 0,
+	.setup_hold_time_hs_mode = 0,
+	.has_interface_timing_reg = true,
 };
 
 static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
@@ -1327,8 +1447,9 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
 	.has_per_pkt_xfer_complete_irq = true,
 	.has_single_clk_source = true,
 	.clk_divisor_hs_mode = 1,
-	.clk_divisor_std_fast_mode = 0x19,
-	.clk_divisor_fast_plus_mode = 0x10,
+	.clk_divisor_std_mode = 0x4f,
+	.clk_divisor_fast_mode = 0x3c,
+	.clk_divisor_fast_plus_mode = 0x16,
 	.has_config_load_reg = true,
 	.has_multi_master_mode = true,
 	.has_slcg_override_reg = true,
@@ -1336,6 +1457,14 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
 	.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,
+	.thigh_fast_fastplus_mode = 0x2,
+	.setup_hold_time_std_mode = 0x08080808,
+	.setup_hold_time_fast_fast_plus_mode = 0x02020202,
+	.setup_hold_time_hs_mode = 0x090909,
+	.has_interface_timing_reg = true,
 };
 
 /* Match table for of_platform binding */
@@ -1362,7 +1491,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	phys_addr_t base_phys;
 	int irq;
 	int ret = 0;
-	int clk_multiplier = I2C_CLK_MULTIPLIER_STD_FAST_MODE;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	base_phys = res->start;
@@ -1433,20 +1561,17 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 		}
 	}
 
-	i2c_dev->clk_divisor_non_hs_mode =
-			i2c_dev->hw->clk_divisor_std_fast_mode;
-	if (i2c_dev->hw->clk_divisor_fast_plus_mode &&
-		(i2c_dev->bus_clk_rate == 1000000))
+	if (i2c_dev->bus_clk_rate > I2C_FAST_MODE &&
+	    i2c_dev->bus_clk_rate <= I2C_FAST_PLUS_MODE)
 		i2c_dev->clk_divisor_non_hs_mode =
-			i2c_dev->hw->clk_divisor_fast_plus_mode;
-
-	clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1);
-	ret = clk_set_rate(i2c_dev->div_clk,
-			   i2c_dev->bus_clk_rate * clk_multiplier);
-	if (ret) {
-		dev_err(i2c_dev->dev, "Clock rate change failed %d\n", ret);
-		goto unprepare_fast_clk;
-	}
+				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)
+		i2c_dev->clk_divisor_non_hs_mode =
+				i2c_dev->hw->clk_divisor_fast_mode;
+	else
+		i2c_dev->clk_divisor_non_hs_mode =
+				i2c_dev->hw->clk_divisor_std_mode;
 
 	ret = clk_prepare(i2c_dev->div_clk);
 	if (ret < 0) {
@@ -1476,7 +1601,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto disable_div_clk;
 
-	ret = tegra_i2c_init(i2c_dev);
+	ret = tegra_i2c_init(i2c_dev, false);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to initialize i2c controller\n");
 		goto disable_div_clk;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 3/6] i2c: tegra: fix maximum transfer size
  2019-02-07 21:47 ` [PATCH V15 3/6] i2c: tegra: fix maximum transfer size Sowjanya Komatineni
@ 2019-02-07 22:09   ` Dmitry Osipenko
  2019-02-07 22:25     ` Dmitry Osipenko
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry Osipenko @ 2019-02-07 22:09 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mkarthik,
	smohammed, talho
  Cc: linux-tegra, linux-kernel, linux-i2c

08.02.2019 0:47, Sowjanya Komatineni пишет:
> Tegra194 supports maximum 64K bytes transfer per packet.
> Tegra186 and prior supports maximum 4K bytes transfer per packet.
> This includes 12 bytes of packet header.
> 
> This patch fixes max write length to account for packet header size
> for transfers.

The commit message isn't accurate. We are not actually fixing anything here, this patch is just a preparation for adding DMA support that require the packet-header size to be excluded from the overall TX size-quirk because the packet-header is the part of the DMA transfer.

Given how small this change is, it's probably not really worth to factor out it into a separate patch, let's just squash it to to the DMA-patch.

> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---
>  [V15]	: This is new patch in this series.
> 
>  drivers/i2c/busses/i2c-tegra.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 3758c7a2c781..ab474cc86e0a 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -125,6 +125,9 @@
>  #define I2C_MST_FIFO_STATUS_TX_MASK		0xff0000
>  #define I2C_MST_FIFO_STATUS_TX_SHIFT		16
>  
> +/* Packet header size in bytes */
> +#define I2C_PACKET_HEADER_SIZE			12
> +
>  /*
>   * msg_end_type: The bus control which need to be send at end of transfer.
>   * @MSG_END_STOP: Send stop pulse at end of transfer.
> @@ -900,11 +903,13 @@ static const struct i2c_algorithm tegra_i2c_algo = {
>  static const struct i2c_adapter_quirks tegra_i2c_quirks = {
>  	.flags = I2C_AQ_NO_ZERO_LEN,
>  	.max_read_len = 4096,
> -	.max_write_len = 4096,
> +	.max_write_len = 4096 - I2C_PACKET_HEADER_SIZE,
>  };
>  
>  static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
>  	.flags = I2C_AQ_NO_ZERO_LEN,
> +	.max_read_len = 65535,
> +	.max_write_len = 65535 - I2C_PACKET_HEADER_SIZE,
>  };

This is wrong, 65535 = 64 * 1024 - 1.

Let's just use size-constants provided by kernel:

static const struct i2c_adapter_quirks tegra_i2c_quirks = {
	.flags = I2C_AQ_NO_ZERO_LEN,
	.max_read_len = SZ_4K,
	.max_write_len = SZ_4K - I2C_PACKET_HEADER_SIZE,
};

static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
	.flags = I2C_AQ_NO_ZERO_LEN,
	.max_read_len = SZ_64K,
	.max_write_len = SZ_64K - I2C_PACKET_HEADER_SIZE,
};


I'll take a look at other patches later today, no need to send out new version right now.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 3/6] i2c: tegra: fix maximum transfer size
  2019-02-07 22:09   ` Dmitry Osipenko
@ 2019-02-07 22:25     ` Dmitry Osipenko
  2019-02-08 12:46       ` Dmitry Osipenko
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry Osipenko @ 2019-02-07 22:25 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mkarthik,
	smohammed, talho
  Cc: linux-tegra, linux-kernel, linux-i2c

> 08.02.2019 1:16, Sowjanya Komatineni пишет:> 
>>> This is wrong, 65535 = 64 * 1024 - 1.
>>>
>>> Let's just use size-constants provided by kernel:
>>>
>>> static const struct i2c_adapter_quirks tegra_i2c_quirks = {
>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>> 	.max_read_len = SZ_4K,
>>> 	.max_write_len = SZ_4K - I2C_PACKET_HEADER_SIZE, };
>>>
>>> static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>> 	.max_read_len = SZ_64K,
>>> 	.max_write_len = SZ_64K - I2C_PACKET_HEADER_SIZE, };
>>>
>>>
>>> I'll take a look at other patches later today, no need to send out new version right now.
>>>
>>>
>> 
>> SIZE_64K is 0x00010000 (65536)
>> 
>> msg len is u16 and max that can be set to msg.len is 65535

Ah, okay. Then it looks about right, maybe it's time to change u16 to u32 in the I2C core.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 3/6] i2c: tegra: fix maximum transfer size
  2019-02-07 22:25     ` Dmitry Osipenko
@ 2019-02-08 12:46       ` Dmitry Osipenko
  2019-02-08 14:12         ` Peter Rosin
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry Osipenko @ 2019-02-08 12:46 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mkarthik,
	smohammed, talho
  Cc: linux-tegra, linux-kernel, linux-i2c

08.02.2019 1:25, Dmitry Osipenko пишет:
>> 08.02.2019 1:16, Sowjanya Komatineni пишет:> 
>>>> This is wrong, 65535 = 64 * 1024 - 1.
>>>>
>>>> Let's just use size-constants provided by kernel:
>>>>
>>>> static const struct i2c_adapter_quirks tegra_i2c_quirks = {
>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>>> 	.max_read_len = SZ_4K,
>>>> 	.max_write_len = SZ_4K - I2C_PACKET_HEADER_SIZE, };
>>>>
>>>> static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>>> 	.max_read_len = SZ_64K,
>>>> 	.max_write_len = SZ_64K - I2C_PACKET_HEADER_SIZE, };
>>>>
>>>>
>>>> I'll take a look at other patches later today, no need to send out new version right now.
>>>>
>>>>
>>>
>>> SIZE_64K is 0x00010000 (65536)
>>>
>>> msg len is u16 and max that can be set to msg.len is 65535
> 
> Ah, okay. Then it looks about right, maybe it's time to change u16 to u32 in the I2C core.
> 

Here is my suggestion:

1) Use SZ_4K / SZ_64K that I suggested above.

2) Squash this patch into the DMA-patch.

3) Add another patch (before the DMA-patch) that changes max_read_len/max_write_len types to u32 in the include/linux/i2c.h

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 4/6] i2c: tegra: Add DMA support
  2019-02-07 21:47 ` [PATCH V15 4/6] i2c: tegra: Add DMA support Sowjanya Komatineni
@ 2019-02-08 12:47   ` Dmitry Osipenko
  2019-02-08 15:49     ` Sowjanya Komatineni
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry Osipenko @ 2019-02-08 12:47 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mkarthik,
	smohammed, talho
  Cc: linux-tegra, linux-kernel, linux-i2c

08.02.2019 0:47, Sowjanya Komatineni пишет:
> This patch adds DMA support for Tegra I2C.
> 
> Tegra I2C TX and RX FIFO depth is 8 words. PIO mode is used for
> transfer size of the max FIFO depth and DMA mode is used for
> transfer size higher than max FIFO depth to save CPU overhead.
> 
> PIO mode needs full intervention of CPU to fill or empty FIFO's
> and also need to service multiple data requests interrupt for the
> same transaction. This adds delay between data bytes of the same
> transfer when CPU is fully loaded and some slave devices has
> internal timeout for no bus activity and stops transaction to
> avoid bus hang. DMA mode is helpful in such cases.
> 
> DMA mode is also helpful for Large transfers during downloading or
> uploading FW over I2C to some external devices.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---


[snip]

>  	time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
>  						TEGRA_I2C_TIMEOUT);
>  	tegra_i2c_mask_irq(i2c_dev, int_mask);
> -

Let's keep this newline in place.

[snip]

> +	ret = tegra_i2c_init_dma(i2c_dev);
> +	if (ret < 0)
> +		goto disable_div_clk;
> +
>  	ret = tegra_i2c_init(i2c_dev);
>  	if (ret) {
>  		dev_err(&pdev->dev, "Failed to initialize i2c controller\n");
> @@ -1160,6 +1500,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
>  disable_div_clk:
>  	if (i2c_dev->is_multimaster_mode)
>  		clk_disable(i2c_dev->div_clk);
> +	tegra_i2c_release_dma(i2c_dev);

Please use "release_dma:" variant that I suggested in the comment to v14 because:

1) It's just a good (and common-style in kernel) tone to unwind errors handling in the opposite order, it makes code more straight forward and helps to avoid silly mistakes.

2) It keeps the current code consistent in regards to probe error-handling.

>  
>  disable_rpm:
>  	pm_runtime_disable(&pdev->dev);


[snip]

Please also address my comment to the "fix maximum transfer size" patch. And please add Wolfram Sang to the CC list.

Looks like v16 should be the final, so with everything being addressed:

Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Tested-by: Dmitry Osipenko <digetx@gmail.com>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 6/6] i2c: tegra: add i2c interface timing support
  2019-02-07 21:47 ` [PATCH V15 6/6] i2c: tegra: add i2c interface timing support Sowjanya Komatineni
@ 2019-02-08 12:53   ` Dmitry Osipenko
  2019-02-08 13:00     ` Dmitry Osipenko
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry Osipenko @ 2019-02-08 12:53 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mkarthik,
	smohammed, talho
  Cc: linux-tegra, linux-kernel, linux-i2c

08.02.2019 0:47, Sowjanya Komatineni пишет:
> This patch adds I2C interface timing registers support for
> proper bus rate configuration along with meeting the I2C spec
> setup and hold times based on the tuning performed on Tegra210,
> Tegra186 and Tegra194 platforms.
> 
> I2C_INTERFACE_TIMING_0 register contains TLOW and THIGH field
> and Tegra I2C controller design uses them as a part of internal
> clock divisor.
> 
> I2C_INTERFACE_TIMING_1 register contains the setup and hold times
> for start and stop conditions.
> 
> Acked-by: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
> ---

[snip]

>  
> +	if (i2c_dev->bus_clk_rate > I2C_STANDARD_MODE &&
> +	    i2c_dev->bus_clk_rate <= I2C_FAST_PLUS_MODE) {
> +		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;
> +	} else {
> +		tlow = i2c_dev->hw->tlow_std_mode;
> +		thigh = i2c_dev->hw->thigh_std_mode;
> +		tsu_thd = i2c_dev->hw->setup_hold_time_std_mode;
> +	}
> +
> +	if (i2c_dev->hw->has_interface_timing_reg && val) {

Shouldn't it be "&& tlow"?

> +		val = (thigh << I2C_THIGH_SHIFT) | tlow;
> +		i2c_writel(i2c_dev, val, I2C_INTERFACE_TIMING_0);
> +	}
> +
> +	if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
> +		i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);

Do we really need those "&& tlow" and "&& tsu_thd" at all? It looks to me that checking for "has_interface_timing_reg" should be enough.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 6/6] i2c: tegra: add i2c interface timing support
  2019-02-08 12:53   ` Dmitry Osipenko
@ 2019-02-08 13:00     ` Dmitry Osipenko
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry Osipenko @ 2019-02-08 13:00 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, jonathanh, mkarthik,
	smohammed, talho
  Cc: linux-tegra, linux-kernel, linux-i2c

08.02.2019 15:53, Dmitry Osipenko пишет:
> 08.02.2019 0:47, Sowjanya Komatineni пишет:
>> This patch adds I2C interface timing registers support for
>> proper bus rate configuration along with meeting the I2C spec
>> setup and hold times based on the tuning performed on Tegra210,
>> Tegra186 and Tegra194 platforms.
>>
>> I2C_INTERFACE_TIMING_0 register contains TLOW and THIGH field
>> and Tegra I2C controller design uses them as a part of internal
>> clock divisor.
>>
>> I2C_INTERFACE_TIMING_1 register contains the setup and hold times
>> for start and stop conditions.
>>
>> Acked-by: Thierry Reding <treding@nvidia.com>
>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
>> ---
> 
> [snip]
> 
>>  
>> +	if (i2c_dev->bus_clk_rate > I2C_STANDARD_MODE &&
>> +	    i2c_dev->bus_clk_rate <= I2C_FAST_PLUS_MODE) {
>> +		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;
>> +	} else {
>> +		tlow = i2c_dev->hw->tlow_std_mode;
>> +		thigh = i2c_dev->hw->thigh_std_mode;
>> +		tsu_thd = i2c_dev->hw->setup_hold_time_std_mode;
>> +	}
>> +
>> +	if (i2c_dev->hw->has_interface_timing_reg && val) {
> 
> Shouldn't it be "&& tlow"?

Ah, there is "thigh" in use here.. so it all just doesn't make sense since "&& val" is always true. 

> 
>> +		val = (thigh << I2C_THIGH_SHIFT) | tlow;
>> +		i2c_writel(i2c_dev, val, I2C_INTERFACE_TIMING_0);
>> +	}
>> +
>> +	if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
>> +		i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
> 
> Do we really need those "&& tlow" and "&& tsu_thd" at all? It looks to me that checking for "has_interface_timing_reg" should be enough.
> 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 3/6] i2c: tegra: fix maximum transfer size
  2019-02-08 12:46       ` Dmitry Osipenko
@ 2019-02-08 14:12         ` Peter Rosin
  2019-02-08 14:32           ` Dmitry Osipenko
  0 siblings, 1 reply; 20+ messages in thread
From: Peter Rosin @ 2019-02-08 14:12 UTC (permalink / raw)
  To: Dmitry Osipenko, Sowjanya Komatineni, thierry.reding, jonathanh,
	mkarthik, smohammed, talho
  Cc: linux-tegra, linux-kernel, linux-i2c

On 2019-02-08 13:46, Dmitry Osipenko wrote:
> 08.02.2019 1:25, Dmitry Osipenko пишет:
>>> 08.02.2019 1:16, Sowjanya Komatineni пишет:> 
>>>>> This is wrong, 65535 = 64 * 1024 - 1.
>>>>>
>>>>> Let's just use size-constants provided by kernel:
>>>>>
>>>>> static const struct i2c_adapter_quirks tegra_i2c_quirks = {
>>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>>>> 	.max_read_len = SZ_4K,
>>>>> 	.max_write_len = SZ_4K - I2C_PACKET_HEADER_SIZE, };
>>>>>
>>>>> static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
>>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>>>> 	.max_read_len = SZ_64K,
>>>>> 	.max_write_len = SZ_64K - I2C_PACKET_HEADER_SIZE, };
>>>>>
>>>>>
>>>>> I'll take a look at other patches later today, no need to send out new version right now.
>>>>>
>>>>>
>>>>
>>>> SIZE_64K is 0x00010000 (65536)
>>>>
>>>> msg len is u16 and max that can be set to msg.len is 65535
>>
>> Ah, okay. Then it looks about right, maybe it's time to change u16 to u32 in the I2C core.
>>
> 
> Here is my suggestion:
> 
> 1) Use SZ_4K / SZ_64K that I suggested above.
> 
> 2) Squash this patch into the DMA-patch.
> 
> 3) Add another patch (before the DMA-patch) that changes max_read_len/max_write_len types to u32 in the include/linux/i2c.h

That is a bit naive and will not fly since the I2C core has a max message
size of 65535. Which is exposed to user space...

Given the above, saying .max_read_len = 65535 a NOP (and is in fact omitted
in places where it would be needed if the type is changed). I suggest that
it is omitted here as well. But SZ_64K - I2C_PACKET_HEADER_SIZE is still
needed of course. At least if I2C_PACKET_HEADER_SIZE is guaranteed to be
non-zero?

Cheers,
Peter

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 3/6] i2c: tegra: fix maximum transfer size
  2019-02-08 14:12         ` Peter Rosin
@ 2019-02-08 14:32           ` Dmitry Osipenko
  2019-02-08 15:25             ` Sowjanya Komatineni
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry Osipenko @ 2019-02-08 14:32 UTC (permalink / raw)
  To: Peter Rosin, Sowjanya Komatineni, thierry.reding, jonathanh,
	mkarthik, smohammed, talho
  Cc: linux-tegra, linux-kernel, linux-i2c

08.02.2019 17:12, Peter Rosin пишет:
> On 2019-02-08 13:46, Dmitry Osipenko wrote:
>> 08.02.2019 1:25, Dmitry Osipenko пишет:
>>>> 08.02.2019 1:16, Sowjanya Komatineni пишет:> 
>>>>>> This is wrong, 65535 = 64 * 1024 - 1.
>>>>>>
>>>>>> Let's just use size-constants provided by kernel:
>>>>>>
>>>>>> static const struct i2c_adapter_quirks tegra_i2c_quirks = {
>>>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>>>>> 	.max_read_len = SZ_4K,
>>>>>> 	.max_write_len = SZ_4K - I2C_PACKET_HEADER_SIZE, };
>>>>>>
>>>>>> static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
>>>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>>>>> 	.max_read_len = SZ_64K,
>>>>>> 	.max_write_len = SZ_64K - I2C_PACKET_HEADER_SIZE, };
>>>>>>
>>>>>>
>>>>>> I'll take a look at other patches later today, no need to send out new version right now.
>>>>>>
>>>>>>
>>>>>
>>>>> SIZE_64K is 0x00010000 (65536)
>>>>>
>>>>> msg len is u16 and max that can be set to msg.len is 65535
>>>
>>> Ah, okay. Then it looks about right, maybe it's time to change u16 to u32 in the I2C core.
>>>
>>
>> Here is my suggestion:
>>
>> 1) Use SZ_4K / SZ_64K that I suggested above.
>>
>> 2) Squash this patch into the DMA-patch.
>>
>> 3) Add another patch (before the DMA-patch) that changes max_read_len/max_write_len types to u32 in the include/linux/i2c.h
> 
> That is a bit naive and will not fly since the I2C core has a max message
> size of 65535. Which is exposed to user space...
> 
> Given the above, saying .max_read_len = 65535 a NOP (and is in fact omitted
> in places where it would be needed if the type is changed). I suggest that
> it is omitted here as well. But SZ_64K - I2C_PACKET_HEADER_SIZE is still
> needed of course. At least if I2C_PACKET_HEADER_SIZE is guaranteed to be
> non-zero?

Ah, I missed that message len is also u16 and then we indeed could just drop the "max_read_len" for T194. Thank you Peter.

Sowjanya, given the above, it probably better to define dma_buf max-size in the tegra_i2c_hw_feature.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH V15 3/6] i2c: tegra: fix maximum transfer size
  2019-02-08 14:32           ` Dmitry Osipenko
@ 2019-02-08 15:25             ` Sowjanya Komatineni
  2019-02-08 15:44               ` Dmitry Osipenko
  0 siblings, 1 reply; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-08 15:25 UTC (permalink / raw)
  To: Dmitry Osipenko, Peter Rosin, thierry.reding, Jonathan Hunter,
	Mantravadi Karthik, Shardar Mohammed, Timo Alho
  Cc: linux-tegra, linux-kernel, linux-i2c

> 08.02.2019 17:12, Peter Rosin пишет:
> > On 2019-02-08 13:46, Dmitry Osipenko wrote:
> >> 08.02.2019 1:25, Dmitry Osipenko пишет:
> >>>> 08.02.2019 1:16, Sowjanya Komatineni пишет:>
> >>>>>> This is wrong, 65535 = 64 * 1024 - 1.
> >>>>>>
> >>>>>> Let's just use size-constants provided by kernel:
> >>>>>>
> >>>>>> static const struct i2c_adapter_quirks tegra_i2c_quirks = {
> >>>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
> >>>>>> 	.max_read_len = SZ_4K,
> >>>>>> 	.max_write_len = SZ_4K - I2C_PACKET_HEADER_SIZE, };
> >>>>>>
> >>>>>> static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
> >>>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
> >>>>>> 	.max_read_len = SZ_64K,
> >>>>>> 	.max_write_len = SZ_64K - I2C_PACKET_HEADER_SIZE, };
> >>>>>>
> >>>>>>
> >>>>>> I'll take a look at other patches later today, no need to send out new version right now.
> >>>>>>
> >>>>>>
> >>>>>
> >>>>> SIZE_64K is 0x00010000 (65536)
> >>>>>
> >>>>> msg len is u16 and max that can be set to msg.len is 65535
> >>>
> >>> Ah, okay. Then it looks about right, maybe it's time to change u16 to u32 in the I2C core.
> >>>
> >>
> >> Here is my suggestion:
> >>
> >> 1) Use SZ_4K / SZ_64K that I suggested above.
> >>
> >> 2) Squash this patch into the DMA-patch.
> >>
> >> 3) Add another patch (before the DMA-patch) that changes 
> >> max_read_len/max_write_len types to u32 in the include/linux/i2c.h
> > 
> > That is a bit naive and will not fly since the I2C core has a max 
> > message size of 65535. Which is exposed to user space...
> > 
> > Given the above, saying .max_read_len = 65535 a NOP (and is in fact 
> > omitted in places where it would be needed if the type is changed). I 
> > suggest that it is omitted here as well. But SZ_64K - 
> > I2C_PACKET_HEADER_SIZE is still needed of course. At least if 
> > I2C_PACKET_HEADER_SIZE is guaranteed to be non-zero?
>
> Ah, I missed that message len is also u16 and then we indeed could just drop the "max_read_len" for T194. Thank you Peter.
>
> Sowjanya, given the above, it probably better to define dma_buf max-size in the tegra_i2c_hw_feature.
>

I2C_PACKET_HEADER_SIZE is always fixed 12. So in that case, we can just add max_write_len 
If no max_read_len, max will be 65535 anyway right

static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
	.flags = I2C_AQ_NO_ZERO_LEN,
	.max_write_len = SZ_64K - I2C_PACKET_HEADER_SIZE, };


sowjanya

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 3/6] i2c: tegra: fix maximum transfer size
  2019-02-08 15:25             ` Sowjanya Komatineni
@ 2019-02-08 15:44               ` Dmitry Osipenko
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry Osipenko @ 2019-02-08 15:44 UTC (permalink / raw)
  To: Sowjanya Komatineni, Peter Rosin, thierry.reding,
	Jonathan Hunter, Mantravadi Karthik, Shardar Mohammed, Timo Alho
  Cc: linux-tegra, linux-kernel, linux-i2c

08.02.2019 18:25, Sowjanya Komatineni пишет:
>> 08.02.2019 17:12, Peter Rosin пишет:
>>> On 2019-02-08 13:46, Dmitry Osipenko wrote:
>>>> 08.02.2019 1:25, Dmitry Osipenko пишет:
>>>>>> 08.02.2019 1:16, Sowjanya Komatineni пишет:>
>>>>>>>> This is wrong, 65535 = 64 * 1024 - 1.
>>>>>>>>
>>>>>>>> Let's just use size-constants provided by kernel:
>>>>>>>>
>>>>>>>> static const struct i2c_adapter_quirks tegra_i2c_quirks = {
>>>>>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>>>>>>> 	.max_read_len = SZ_4K,
>>>>>>>> 	.max_write_len = SZ_4K - I2C_PACKET_HEADER_SIZE, };
>>>>>>>>
>>>>>>>> static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
>>>>>>>> 	.flags = I2C_AQ_NO_ZERO_LEN,
>>>>>>>> 	.max_read_len = SZ_64K,
>>>>>>>> 	.max_write_len = SZ_64K - I2C_PACKET_HEADER_SIZE, };
>>>>>>>>
>>>>>>>>
>>>>>>>> I'll take a look at other patches later today, no need to send out new version right now.
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> SIZE_64K is 0x00010000 (65536)
>>>>>>>
>>>>>>> msg len is u16 and max that can be set to msg.len is 65535
>>>>>
>>>>> Ah, okay. Then it looks about right, maybe it's time to change u16 to u32 in the I2C core.
>>>>>
>>>>
>>>> Here is my suggestion:
>>>>
>>>> 1) Use SZ_4K / SZ_64K that I suggested above.
>>>>
>>>> 2) Squash this patch into the DMA-patch.
>>>>
>>>> 3) Add another patch (before the DMA-patch) that changes 
>>>> max_read_len/max_write_len types to u32 in the include/linux/i2c.h
>>>
>>> That is a bit naive and will not fly since the I2C core has a max 
>>> message size of 65535. Which is exposed to user space...
>>>
>>> Given the above, saying .max_read_len = 65535 a NOP (and is in fact 
>>> omitted in places where it would be needed if the type is changed). I 
>>> suggest that it is omitted here as well. But SZ_64K - 
>>> I2C_PACKET_HEADER_SIZE is still needed of course. At least if 
>>> I2C_PACKET_HEADER_SIZE is guaranteed to be non-zero?
>>
>> Ah, I missed that message len is also u16 and then we indeed could just drop the "max_read_len" for T194. Thank you Peter.
>>
>> Sowjanya, given the above, it probably better to define dma_buf max-size in the tegra_i2c_hw_feature.
>>
> 
> I2C_PACKET_HEADER_SIZE is always fixed 12. So in that case, we can just add max_write_len 
> If no max_read_len, max will be 65535 anyway right
> 
> static const struct i2c_adapter_quirks tegra194_i2c_quirks = {
> 	.flags = I2C_AQ_NO_ZERO_LEN,
> 	.max_write_len = SZ_64K - I2C_PACKET_HEADER_SIZE, };

Yes, adding header size to the max_write_len for the dma_buf size also will be fine.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH V15 4/6] i2c: tegra: Add DMA support
  2019-02-08 12:47   ` Dmitry Osipenko
@ 2019-02-08 15:49     ` Sowjanya Komatineni
  2019-02-08 15:55       ` Sowjanya Komatineni
  0 siblings, 1 reply; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-08 15:49 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, Jonathan Hunter,
	Mantravadi Karthik, Shardar Mohammed, Timo Alho
  Cc: linux-tegra, linux-kernel, linux-i2c

> > +	ret = tegra_i2c_init_dma(i2c_dev);
> > +	if (ret < 0)
> > +		goto disable_div_clk;
> > +
> >  	ret = tegra_i2c_init(i2c_dev);
> >  	if (ret) {
> >  		dev_err(&pdev->dev, "Failed to initialize i2c controller\n"); @@ 
> > -1160,6 +1500,7 @@ static int tegra_i2c_probe(struct platform_device 
> > *pdev)
> >  disable_div_clk:
> >  	if (i2c_dev->is_multimaster_mode)
> >  		clk_disable(i2c_dev->div_clk);
> > +	tegra_i2c_release_dma(i2c_dev);
>
> Please use "release_dma:" variant that I suggested in the comment to v14 because:
>
> 1) It's just a good (and common-style in kernel) tone to unwind errors handling in the opposite order, it makes code more straight forward and helps to avoid silly mistakes.
>
> 2) It keeps the current code consistent in regards to probe error-handling.
>

Can move tegra_i2c_release_dma under the same disable_div_clk label before clk_disable

Order in probe is
	clk_prepare
	i2c_runtime_resume
	clk_enable in case of multimaster mode
	i2c_init_dma

unwinding should be order is
	release_dma
	disable_div_clk
	disable_rpm
	unprepared

Probe failure from tegra_i2c_init_dma, tegra_i2c_init, devm_request_irq, i2c_add_numbered_adapter all of them perform goto disable_div_clk

I can add tegra_i2c_release_dma before performing clock disable under same disable_div_clk so all existing disable_div_clk labels remain same.
Otherwise adding new label release_dma causes all goto disable_div_clk statement also to be changed but its same as adding release_dma under disable_div_clk above the clk_disable.

> >  
> >  disable_rpm:
> >  	pm_runtime_disable(&pdev->dev);
>
>
> [snip]
>
> Please also address my comment to the "fix maximum transfer size" patch. And please add Wolfram Sang to the CC list.
>
> Looks like v16 should be the final, so with everything being addressed:
>
> Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
> Tested-by: Dmitry Osipenko <digetx@gmail.com>



^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH V15 4/6] i2c: tegra: Add DMA support
  2019-02-08 15:49     ` Sowjanya Komatineni
@ 2019-02-08 15:55       ` Sowjanya Komatineni
  2019-02-08 15:58         ` Sowjanya Komatineni
  0 siblings, 1 reply; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-08 15:55 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, Jonathan Hunter,
	Mantravadi Karthik, Shardar Mohammed, Timo Alho
  Cc: linux-tegra, linux-kernel, linux-i2c


> > Please use "release_dma:" variant that I suggested in the comment to v14 because:
> >
> > 1) It's just a good (and common-style in kernel) tone to unwind errors handling in the opposite order, it makes code more straight forward and helps to avoid silly mistakes.
> >
> > 2) It keeps the current code consistent in regards to probe error-handling.
> >
>
> Can move tegra_i2c_release_dma under the same disable_div_clk label before clk_disable
>
> Order in probe is
	clk_prepare
	i2c_runtime_resume
	clk_enable in case of multimaster mode
	i2c_init_dma
>
> unwinding should be order is
	release_dma
	disable_div_clk
	disable_rpm
	unprepared
>
> Probe failure from tegra_i2c_init_dma, tegra_i2c_init, devm_request_irq, i2c_add_numbered_adapter all of them perform goto disable_div_clk
>
> I can add tegra_i2c_release_dma before performing clock disable under same disable_div_clk so all existing disable_div_clk labels remain same.
> Otherwise adding new label release_dma causes all goto disable_div_clk statement also to be changed but its same as adding release_dma under disable_div_clk above the clk_disable.
>

OK, please ignore above. will add release_dma to show explicitly for readability.

> > >  
> > >  disable_rpm:
> > >  	pm_runtime_disable(&pdev->dev);
> >
> >
> > [snip]
> >
> > Please also address my comment to the "fix maximum transfer size" patch. And please add Wolfram Sang to the CC list.
> >
> > Looks like v16 should be the final, so with everything being addressed:
> >
> > Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
> > Tested-by: Dmitry Osipenko <digetx@gmail.com>



^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH V15 4/6] i2c: tegra: Add DMA support
  2019-02-08 15:55       ` Sowjanya Komatineni
@ 2019-02-08 15:58         ` Sowjanya Komatineni
  2019-02-08 16:15           ` Dmitry Osipenko
  0 siblings, 1 reply; 20+ messages in thread
From: Sowjanya Komatineni @ 2019-02-08 15:58 UTC (permalink / raw)
  To: Dmitry Osipenko, thierry.reding, Jonathan Hunter,
	Mantravadi Karthik, Shardar Mohammed, Timo Alho
  Cc: linux-tegra, linux-kernel, linux-i2c



> > Please use "release_dma:" variant that I suggested in the comment to v14 because:
> > >
> > 1) It's just a good (and common-style in kernel) tone to unwind errors handling in the opposite order, it makes code more straight forward and helps to avoid silly mistakes.
> >
> > 2) It keeps the current code consistent in regards to probe error-handling.
> >
>
> Can move tegra_i2c_release_dma under the same disable_div_clk label before clk_disable
>
> Order in probe is
	clk_prepare
	i2c_runtime_resume
	clk_enable in case of multimaster mode
	i2c_init_dma
>
> unwinding should be order is
	release_dma
	disable_div_clk
	disable_rpm
	unprepared
>
> Probe failure from tegra_i2c_init_dma, tegra_i2c_init, devm_request_irq, i2c_add_numbered_adapter all of them perform goto disable_div_clk
>
> I can add tegra_i2c_release_dma before performing clock disable under same disable_div_clk so all existing disable_div_clk labels remain same.
> Otherwise adding new label release_dma causes all goto disable_div_clk statement also to be changed but its same as adding release_dma under disable_div_clk above the clk_disable.
>

OK, please ignore above. will add release_dma to show explicitly for readability.
With release_dma all error handlers performing disable_clk_div need to go thru release dma and disable_clk_div label is not needed.
So having release dma under disable_clk before clk_disable function is also same. 

Please confirm if this is ok to use same disable_div_clk or do you prefer release_dma label removing disable_div_clk


> > >  
> > >  disable_rpm:
> > >  	pm_runtime_disable(&pdev->dev);
> >
> >
> > [snip]
> >
> > Please also address my comment to the "fix maximum transfer size" patch. And please add Wolfram Sang to the CC list.
> >
> > Looks like v16 should be the final, so with everything being addressed:
> >
> > Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
> > Tested-by: Dmitry Osipenko <digetx@gmail.com>



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH V15 4/6] i2c: tegra: Add DMA support
  2019-02-08 15:58         ` Sowjanya Komatineni
@ 2019-02-08 16:15           ` Dmitry Osipenko
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry Osipenko @ 2019-02-08 16:15 UTC (permalink / raw)
  To: Sowjanya Komatineni, thierry.reding, Jonathan Hunter,
	Mantravadi Karthik, Shardar Mohammed, Timo Alho
  Cc: linux-tegra, linux-kernel, linux-i2c

08.02.2019 18:58, Sowjanya Komatineni пишет:
> 
> 
>>> Please use "release_dma:" variant that I suggested in the comment to v14 because:
>>>>
>>> 1) It's just a good (and common-style in kernel) tone to unwind errors handling in the opposite order, it makes code more straight forward and helps to avoid silly mistakes.
>>>
>>> 2) It keeps the current code consistent in regards to probe error-handling.
>>>
>>
>> Can move tegra_i2c_release_dma under the same disable_div_clk label before clk_disable
>>
>> Order in probe is
> 	clk_prepare
> 	i2c_runtime_resume
> 	clk_enable in case of multimaster mode
> 	i2c_init_dma
>>
>> unwinding should be order is
> 	release_dma
> 	disable_div_clk
> 	disable_rpm
> 	unprepared
>>
>> Probe failure from tegra_i2c_init_dma, tegra_i2c_init, devm_request_irq, i2c_add_numbered_adapter all of them perform goto disable_div_clk
>>
>> I can add tegra_i2c_release_dma before performing clock disable under same disable_div_clk so all existing disable_div_clk labels remain same.
>> Otherwise adding new label release_dma causes all goto disable_div_clk statement also to be changed but its same as adding release_dma under disable_div_clk above the clk_disable.
>>
> 
> OK, please ignore above. will add release_dma to show explicitly for readability.
> With release_dma all error handlers performing disable_clk_div need to go thru release dma and disable_clk_div label is not needed.

tegra_i2c_init_dma() releases dma itself in a case of error, hence it should jump to the disable_clk_div.

> So having release dma under disable_clk before clk_disable function is also same. 
> Please confirm if this is ok to use same disable_div_clk or do you prefer release_dma label removing disable_div_clk

In general goto-label naming should reflect the actual jump-action. If goto jumps to dma-releasing, then the action is release-dma and not disable-clk.

Hence the correct variant is:

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 7104213d813b..62e81096fb55 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -1604,14 +1604,14 @@ static int tegra_i2c_probe(struct platform_device *pdev)
        ret = tegra_i2c_init(i2c_dev, false);
        if (ret) {
                dev_err(&pdev->dev, "Failed to initialize i2c controller\n");
-               goto disable_div_clk;
+               goto release_dma;
        }
 
        ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
                        tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
-               goto disable_div_clk;
+               goto release_dma;
        }
 
        i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
@@ -1625,14 +1625,16 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 
        ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
        if (ret)
-               goto disable_div_clk;
+               goto release_dma;
 
        return 0;
 
+release_dma:
+       tegra_i2c_release_dma(i2c_dev);
+
 disable_div_clk:
        if (i2c_dev->is_multimaster_mode)
                clk_disable(i2c_dev->div_clk);
-       tegra_i2c_release_dma(i2c_dev);
 
 disable_rpm:
        pm_runtime_disable(&pdev->dev);

^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2019-02-08 16:15 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-07 21:47 [PATCH V15 1/6] i2c: tegra: sort all the include headers alphabetically Sowjanya Komatineni
2019-02-07 21:47 ` [PATCH V15 2/6] i2c: tegra: add bus clear Master Support Sowjanya Komatineni
2019-02-07 21:47 ` [PATCH V15 3/6] i2c: tegra: fix maximum transfer size Sowjanya Komatineni
2019-02-07 22:09   ` Dmitry Osipenko
2019-02-07 22:25     ` Dmitry Osipenko
2019-02-08 12:46       ` Dmitry Osipenko
2019-02-08 14:12         ` Peter Rosin
2019-02-08 14:32           ` Dmitry Osipenko
2019-02-08 15:25             ` Sowjanya Komatineni
2019-02-08 15:44               ` Dmitry Osipenko
2019-02-07 21:47 ` [PATCH V15 4/6] i2c: tegra: Add DMA support Sowjanya Komatineni
2019-02-08 12:47   ` Dmitry Osipenko
2019-02-08 15:49     ` Sowjanya Komatineni
2019-02-08 15:55       ` Sowjanya Komatineni
2019-02-08 15:58         ` Sowjanya Komatineni
2019-02-08 16:15           ` Dmitry Osipenko
2019-02-07 21:47 ` [PATCH V15 5/6] i2c: tegra: update transfer timeout Sowjanya Komatineni
2019-02-07 21:47 ` [PATCH V15 6/6] i2c: tegra: add i2c interface timing support Sowjanya Komatineni
2019-02-08 12:53   ` Dmitry Osipenko
2019-02-08 13:00     ` Dmitry Osipenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).