devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Benoît Monin" <benoit.monin@bootlin.com>
To: Andi Shyti <andi.shyti@kernel.org>, Rob Herring <robh@kernel.org>,
	 Krzysztof Kozlowski <krzk+dt@kernel.org>,
	 Conor Dooley <conor+dt@kernel.org>,
	 Jarkko Nikula <jarkko.nikula@linux.intel.com>,
	 Mika Westerberg <mika.westerberg@linux.intel.com>,
	 Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	 Jan Dabros <jsd@semihalf.com>,
	 Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
	 Clark Williams <clrkwllms@kernel.org>,
	Steven Rostedt <rostedt@goodmis.org>
Cc: "Thomas Petazzoni" <thomas.petazzoni@bootlin.com>,
	"Gregory CLEMENT" <gregory.clement@bootlin.com>,
	"Théo Lebrun" <theo.lebrun@bootlin.com>,
	"Tawfik Bayouk" <tawfik.bayouk@mobileye.com>,
	"Vladimir Kondratiev" <vladimir.kondratiev@mobileye.com>,
	"Dmitry Guzman" <dmitry.guzman@mobileye.com>,
	linux-i2c@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-rt-devel@lists.linux.dev,
	"Benoît Monin" <benoit.monin@bootlin.com>
Subject: [PATCH 2/3] i2c: designware: Enable transfer with different target addresses
Date: Fri, 17 Oct 2025 16:59:33 +0200	[thread overview]
Message-ID: <20251017-i2c-dw-v1-2-7b85b71c7a87@bootlin.com> (raw)
In-Reply-To: <20251017-i2c-dw-v1-0-7b85b71c7a87@bootlin.com>

When i2c_dw_xfer() is called with more than one message, it sets the
target address according to the first message. If any of the following
messages have a different target address, the transfer finishes with
an error.

Instead, if the next message has a different target address, wait until
all previous messages are sent and the STOP condition is detected. This
will complete the current part of the transfer. The next part is then
handled by looping in i2c_dw_xfer(), calling i2c_dw_xfer_init() and
i2c_dw_wait_transfer() until all messages of the transfer have been
processed, or an error is detected.

The RESTART bit is now set after the first message of each part of the
transfer, instead of just after the very first message of the whole
transfer.

For each address change, i2c_dw_xfer_init() is called, which takes care
of disabling the adapter before changing the target address register,
then re-enabling it. Given that we cannot know the value of the
I2C_DYNAMIC_TAR_UPDATE parameter, this is the only sure way to change
the target address.

Based on the work of Dmitry Guzman <dmitry.guzman@mobileye.com>

Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
 drivers/i2c/busses/i2c-designware-master.c | 58 ++++++++++++++++--------------
 1 file changed, 31 insertions(+), 27 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index c7a72c28786c2..f9a180b145da8 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -436,6 +436,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 	u8 *buf = dev->tx_buf;
 	bool need_restart = false;
 	unsigned int flr;
+	int first_idx = dev->msg_write_idx;
 
 	intr_mask = DW_IC_INTR_MASTER_MASK;
 
@@ -446,11 +447,11 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 		 * If target address has changed, we need to
 		 * reprogram the target address in the I2C
 		 * adapter when we are done with this transfer.
+		 * This can be done after STOP_DET IRQ flag is raised.
+		 * So, disable "TX FIFO empty" interrupt.
 		 */
 		if (msgs[dev->msg_write_idx].addr != addr) {
-			dev_err(dev->dev,
-				"%s: invalid target address\n", __func__);
-			dev->msg_err = -EINVAL;
+			intr_mask &= ~DW_IC_INTR_TX_EMPTY;
 			break;
 		}
 
@@ -465,7 +466,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 			 * set restart bit between messages.
 			 */
 			if ((dev->master_cfg & DW_IC_CON_RESTART_EN) &&
-					(dev->msg_write_idx > 0))
+					(dev->msg_write_idx > first_idx))
 				need_restart = true;
 		}
 
@@ -822,7 +823,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 		break;
 	}
 
-	reinit_completion(&dev->cmd_complete);
 	dev->msgs = msgs;
 	dev->msgs_num = num;
 	dev->cmd_err = 0;
@@ -841,18 +841,33 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	if (ret < 0)
 		goto done;
 
-	/* Start the transfers */
-	i2c_dw_xfer_init(dev);
+	do {
+		reinit_completion(&dev->cmd_complete);
 
-	/* Wait for tx to complete */
-	ret = i2c_dw_wait_transfer(dev);
-	if (ret) {
-		dev_err(dev->dev, "controller timed out\n");
-		/* i2c_dw_init_master() implicitly disables the adapter */
-		i2c_recover_bus(&dev->adapter);
-		i2c_dw_init_master(dev);
-		goto done;
-	}
+		/* Start the transfers */
+		i2c_dw_xfer_init(dev);
+
+		/* Wait for tx to complete */
+		ret = i2c_dw_wait_transfer(dev);
+		if (ret) {
+			dev_err(dev->dev, "controller timed out\n");
+			/* i2c_dw_init_master() implicitly disables the adapter */
+			i2c_recover_bus(&dev->adapter);
+			i2c_dw_init_master(dev);
+			goto done;
+		}
+
+		if (dev->msg_err) {
+			ret = dev->msg_err;
+			goto done;
+		}
+
+		/* We have an error */
+		if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
+			ret = i2c_dw_handle_tx_abort(dev);
+			goto done;
+		}
+	} while (dev->msg_write_idx < num);
 
 	/*
 	 * This happens rarely (~1:500) and is hard to reproduce. Debug trace
@@ -874,23 +889,12 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	 */
 	__i2c_dw_disable_nowait(dev);
 
-	if (dev->msg_err) {
-		ret = dev->msg_err;
-		goto done;
-	}
-
 	/* No error */
 	if (likely(!dev->cmd_err && !dev->status)) {
 		ret = num;
 		goto done;
 	}
 
-	/* We have an error */
-	if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
-		ret = i2c_dw_handle_tx_abort(dev);
-		goto done;
-	}
-
 	if (dev->status)
 		dev_err(dev->dev,
 			"transfer terminated early - interrupt latency too high?\n");

-- 
2.51.0


  parent reply	other threads:[~2025-10-17 15:02 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-17 14:59 [PATCH 0/3] i2c: designware: Improve support of multi-messages transfer Benoît Monin
2025-10-17 14:59 ` [PATCH 1/3] dt-bindings: i2c: dw: Add Mobileye I2C controllers Benoît Monin
2025-10-18 15:55   ` Krzysztof Kozlowski
2025-10-17 14:59 ` Benoît Monin [this message]
2025-10-20  9:38   ` [PATCH 2/3] i2c: designware: Enable transfer with different target addresses Hans Verkuil
2025-10-20 15:00     ` Benoît Monin
2025-10-20 19:52       ` Wolfram Sang
2025-10-22  8:36         ` Benoît Monin
2025-10-22  8:58           ` Wolfram Sang
2025-10-17 14:59 ` [PATCH 3/3] i2c: designware: Support of controller with IC_EMPTYFIFO_HOLD_MASTER disabled Benoît Monin
2025-10-18 15:55   ` Krzysztof Kozlowski
2025-10-18 19:57   ` Andy Shevchenko
2025-10-21 15:40   ` Mika Westerberg
2025-10-18 19:49 ` [PATCH 0/3] i2c: designware: Improve support of multi-messages transfer Andy Shevchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251017-i2c-dw-v1-2-7b85b71c7a87@bootlin.com \
    --to=benoit.monin@bootlin.com \
    --cc=andi.shyti@kernel.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=bigeasy@linutronix.de \
    --cc=clrkwllms@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dmitry.guzman@mobileye.com \
    --cc=gregory.clement@bootlin.com \
    --cc=jarkko.nikula@linux.intel.com \
    --cc=jsd@semihalf.com \
    --cc=krzk+dt@kernel.org \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-devel@lists.linux.dev \
    --cc=mika.westerberg@linux.intel.com \
    --cc=robh@kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=tawfik.bayouk@mobileye.com \
    --cc=theo.lebrun@bootlin.com \
    --cc=thomas.petazzoni@bootlin.com \
    --cc=vladimir.kondratiev@mobileye.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).