* [PATCH v2 0/2] Minor changes for i2c-imx driver
@ 2026-04-24 12:36 Daniel Scally
2026-04-24 12:36 ` [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost Daniel Scally
2026-04-24 12:36 ` [PATCH v2 2/2] i2c: imx: Retry failed transfers 3 times Daniel Scally
0 siblings, 2 replies; 6+ messages in thread
From: Daniel Scally @ 2026-04-24 12:36 UTC (permalink / raw)
To: Oleksij Rempel, Pengutronix Kernel Team, Andi Shyti, Frank Li,
Sascha Hauer, Fabio Estevam, Gao Pan, Fugang Duan, Wolfram Sang
Cc: linux-i2c, imx, linux-arm-kernel, Daniel Scally
Hello all
These small changes helped resolve issues we experienced using the
i2c-imx driver on a multi-master bus. The device was losing
arbitration which triggered the driver to attempt to recover the bus
rather than retry the transfer. The set stops the bus recovery
attempts on lost arbitration and instructs the driver to retry
transfers 3 times, which seems sufficient for our setup.
I had intended to make a larger change that added a new devicetree
property for i2c-controller.yaml that held the number of retries an
adapter should use, and then parse that to set adap->retries. I found
a relatively old discussion on the list though in which a similar
idea was discussed and rejected so I dropped that, but I thought I'd
mention it in case things had changed.
Thanks
Dan
Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
---
Changes in v2:
- Updated the commit message in v1, and added a Fixes tag.
- Link to v1: https://lore.kernel.org/r/20260311-i2c-imx-fixes-v1-0-e625034d8202@ideasonboard.com
---
Daniel Scally (2):
i2c: imx: Don't recover bus when arbitration lost
i2c: imx: Retry failed transfers 3 times
drivers/i2c/busses/i2c-imx.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
---
base-commit: 4a181746639404023abfcb28eb6f6c66974be5a7
change-id: 20260311-i2c-imx-fixes-3e23164a8a8f
Best regards,
--
Daniel Scally <dan.scally@ideasonboard.com>
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost 2026-04-24 12:36 [PATCH v2 0/2] Minor changes for i2c-imx driver Daniel Scally @ 2026-04-24 12:36 ` Daniel Scally 2026-05-19 8:42 ` Dan Scally 2026-04-24 12:36 ` [PATCH v2 2/2] i2c: imx: Retry failed transfers 3 times Daniel Scally 1 sibling, 1 reply; 6+ messages in thread From: Daniel Scally @ 2026-04-24 12:36 UTC (permalink / raw) To: Oleksij Rempel, Pengutronix Kernel Team, Andi Shyti, Frank Li, Sascha Hauer, Fabio Estevam, Gao Pan, Fugang Duan, Wolfram Sang Cc: linux-i2c, imx, linux-arm-kernel, Daniel Scally In i2c_imx_xfer_common(), the driver attempts bus recovery whenever i2c_imx_start() fails. One of the failure modes for i2c_imx_start() is an arbitration-lost signal which results when a second I2C master on the bus tries to control the bus simultaneously, which is a normal and expected behaviour. Bus recovery is not the right response for this case. Add a check for the -EAGAIN return code to avoid running the bus recovery. Fixes: 1c4b6c3bcf30d ("i2c: imx: implement bus recovery") Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> --- drivers/i2c/busses/i2c-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index a208fefd3c3b35672a00eda8448f24859aaa793a..b68a0f7105682006bbcfee52891c9a9c2d8c009e 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1552,7 +1552,7 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, /* Start I2C transfer */ result = i2c_imx_start(i2c_imx, atomic); - if (result) { + if (result && result != -EAGAIN) { /* * Bus recovery uses gpiod_get_value_cansleep() which is not * allowed within atomic context. -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost 2026-04-24 12:36 ` [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost Daniel Scally @ 2026-05-19 8:42 ` Dan Scally 2026-05-19 10:29 ` Carlos Song (OSS) 0 siblings, 1 reply; 6+ messages in thread From: Dan Scally @ 2026-05-19 8:42 UTC (permalink / raw) To: Oleksij Rempel, Pengutronix Kernel Team Cc: linux-i2c, imx, linux-arm-kernel, Andi Shyti, Frank Li, Sascha Hauer, Fabio Estevam, Gao Pan, Fugang Duan, Wolfram Sang Hello Oleksij / all On 24/04/2026 13:36, Daniel Scally wrote: > In i2c_imx_xfer_common(), the driver attempts bus recovery whenever > i2c_imx_start() fails. One of the failure modes for i2c_imx_start() > is an arbitration-lost signal which results when a second I2C master > on the bus tries to control the bus simultaneously, which is a normal > and expected behaviour. > > Bus recovery is not the right response for this case. Add a check for > the -EAGAIN return code to avoid running the bus recovery. > > Fixes: 1c4b6c3bcf30d ("i2c: imx: implement bus recovery") > Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> > --- I raised this patch after we had issues with one of the i2c controllers on imx8mp. In that case, the bus had multiple masters that were causing the SoC's i2c controller to lose arbitration. The result was that the framework attempted to run i2c_generic_scl_recovery() and regularly hit the "SCL is stuck low, exit recovery" message [1] because the bus was busy rather than stuck. I'm now experiencing a different issue with the imx8mp in which a different controller - which isn't on a multiple-masters bus - starts transacting fine early in boot, but then seems to get stuck - any attempt to start a transaction by either a driver or i2ctransfer results in the IAL bit in I2C_I2SR being set and so the driver reports that it's lost arbitration [2]. In this case, the bus recovery is needed to fix the problem, and so this commit hurts things rather than helps them. This problem isn't consistent - I get it on maybe 10% of boots. I'm trying to find a way to handle the two problems together. I can move the retries into the i2x-imx driver like below, and that works so far: diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index a208fefd3c3b3..cee333236646a 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1551,7 +1551,20 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, int use_dma = 0; /* Start I2C transfer */ - result = i2c_imx_start(i2c_imx, atomic); + for (unsigned int try = 0; try <= 3; try++) { + result = i2c_imx_start(i2c_imx, atomic); + if (result == -EAGAIN) { + i2c_imx_stop(i2c_imx, atomic); + + if (i2c_imx->slave) + i2c_imx_slave_init(i2c_imx); + + continue; + } + + break; + } + if (result) { /* * Bus recovery uses gpiod_get_value_cansleep() which is not That way it retries 3 times if i2c_bus_busy() reports -EAGAIN from lost arbitration, but then gives up and runs the bus recovery if none of the retries works. I do wonder why the i2c controller is setting the IAL bit though given there's no other master on the bus. If I use a logic analyser to track traffic on the bus I can't see anything anomalous, so I thought I'd check whether anyone has experienced something similar before. [1] https://elixir.bootlin.com/linux/v7.0.1/source/drivers/i2c/i2c-core-base.c#L254 [2] https://elixir.bootlin.com/linux/v7.0.1/source/drivers/i2c/busses/i2c-imx.c#L548 > drivers/i2c/busses/i2c-imx.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c > index a208fefd3c3b35672a00eda8448f24859aaa793a..b68a0f7105682006bbcfee52891c9a9c2d8c009e 100644 > --- a/drivers/i2c/busses/i2c-imx.c > +++ b/drivers/i2c/busses/i2c-imx.c > @@ -1552,7 +1552,7 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, > > /* Start I2C transfer */ > result = i2c_imx_start(i2c_imx, atomic); > - if (result) { > + if (result && result != -EAGAIN) { > /* > * Bus recovery uses gpiod_get_value_cansleep() which is not > * allowed within atomic context. > ^ permalink raw reply related [flat|nested] 6+ messages in thread
* RE: [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost 2026-05-19 8:42 ` Dan Scally @ 2026-05-19 10:29 ` Carlos Song (OSS) 2026-05-19 18:32 ` Dan Scally 0 siblings, 1 reply; 6+ messages in thread From: Carlos Song (OSS) @ 2026-05-19 10:29 UTC (permalink / raw) To: Dan Scally Cc: linux-i2c@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, Andi Shyti, Frank Li, Sascha Hauer, Fabio Estevam, Gao Pan, Fugang Duan, Wolfram Sang, Oleksij Rempel, Pengutronix Kernel Team > -----Original Message----- > From: Dan Scally <dan.scally@ideasonboard.com> > Sent: Tuesday, May 19, 2026 4:42 PM > To: Oleksij Rempel <o.rempel@pengutronix.de>; Pengutronix Kernel Team > <kernel@pengutronix.de> > Cc: linux-i2c@vger.kernel.org; imx@lists.linux.dev; > linux-arm-kernel@lists.infradead.org; Andi Shyti <andi.shyti@kernel.org>; Frank > Li <frank.li@nxp.com>; Sascha Hauer <s.hauer@pengutronix.de>; Fabio > Estevam <festevam@gmail.com>; Gao Pan <b54642@freescale.com>; Fugang > Duan <B38611@freescale.com>; Wolfram Sang <wsa@kernel.org> > Subject: Re: [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost > > [You don't often get email from dan.scally@ideasonboard.com. Learn why this is > important at https://aka.ms/LearnAboutSenderIdentification ] > > Hello Oleksij / all > > On 24/04/2026 13:36, Daniel Scally wrote: > > In i2c_imx_xfer_common(), the driver attempts bus recovery whenever > > i2c_imx_start() fails. One of the failure modes for i2c_imx_start() is > > an arbitration-lost signal which results when a second I2C master on > > the bus tries to control the bus simultaneously, which is a normal and > > expected behaviour. > > > > Bus recovery is not the right response for this case. Add a check for > > the -EAGAIN return code to avoid running the bus recovery. > > > > Fixes: 1c4b6c3bcf30d ("i2c: imx: implement bus recovery") > > Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> > > --- > > I raised this patch after we had issues with one of the i2c controllers on imx8mp. > In that case, the bus had multiple masters that were causing the SoC's i2c > controller to lose arbitration. The result was that the framework attempted to > run i2c_generic_scl_recovery() and regularly hit the "SCL is stuck low, exit > recovery" message [1] because the bus was busy rather than stuck. > > I'm now experiencing a different issue with the imx8mp in which a different > controller - which isn't on a multiple-masters bus - starts transacting fine early in > boot, but then seems to get stuck - any attempt to start a transaction by either > a driver or i2ctransfer results in the IAL bit in I2C_I2SR being set and so the > driver reports that it's lost arbitration [2]. In this case, the bus recovery is > needed to fix the problem, and so this commit hurts things rather than helps > them. This problem isn't consistent - I get it on maybe 10% of boots. > Hi Dan, This is the RM shows: Arbitration lost. Set by hardware in the following circumstances (IAL must be cleared by software by writing a "0" to it at the start of the interrupt service routine): * I2Cn_SDA input samples low when the master drives high during an address or data-transmit cycle. * I2Cn_SDA input samples low when the master drives high during the acknowledge bit of a datareceive cycle. For the above two cases, the bit is set at the falling edge of the ninth I2Cn_SCL clock during the ACK cycle. * A Start cycle is attempted when the bus is busy. * A Repeated Start cycle is requested in Slave mode. * A Stop condition is detected when the master did not request it. NOTE: Software cannot set the bit. 0 No arbitration lost. 1 Arbitration is lost. From my understanding: The IAL (Arbitration Lost) bit is set not only when true arbitration is lost, but also in several other conditions: - SDA is sampled low when the master drives it high (during address/data or ACK phase) - A START is attempted while the bus is busy - A STOP condition is detected unexpectedly - A repeated START occurs in slave mode So in practice, IAL can be asserted not only by real arbitration loss, but also when the controller detects abnormal bus conditions. Since your system is single-master, this is unlikely to be a true arbitration scenario. Instead, it is more likely caused by signal integrity or timing-related issues, such as: - weak pull-up / slow rising edges - noise or glitches on SDA - timing violations from the slave device - others As a workaround, you can enable the 'single-master' property to disable arbitration checks in single-master systems, for example: &i2c1 { clock-frequency = <400000>; pinctrl-names = "default", "gpio"; pinctrl-0 = <&pinctrl_i2c1>; pinctrl-1 = <&pinctrl_i2c1_gpio>; scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; single-master; status = "okay"; }; Hope it will help some. Carlos ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost 2026-05-19 10:29 ` Carlos Song (OSS) @ 2026-05-19 18:32 ` Dan Scally 0 siblings, 0 replies; 6+ messages in thread From: Dan Scally @ 2026-05-19 18:32 UTC (permalink / raw) To: Carlos Song (OSS) Cc: linux-i2c@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, Andi Shyti, Frank Li, Sascha Hauer, Fabio Estevam, Gao Pan, Fugang Duan, Wolfram Sang, Oleksij Rempel, Pengutronix Kernel Team Hi Carlos On 19/05/2026 11:29, Carlos Song (OSS) wrote: > > >> -----Original Message----- >> From: Dan Scally <dan.scally@ideasonboard.com> >> Sent: Tuesday, May 19, 2026 4:42 PM >> To: Oleksij Rempel <o.rempel@pengutronix.de>; Pengutronix Kernel Team >> <kernel@pengutronix.de> >> Cc: linux-i2c@vger.kernel.org; imx@lists.linux.dev; >> linux-arm-kernel@lists.infradead.org; Andi Shyti <andi.shyti@kernel.org>; Frank >> Li <frank.li@nxp.com>; Sascha Hauer <s.hauer@pengutronix.de>; Fabio >> Estevam <festevam@gmail.com>; Gao Pan <b54642@freescale.com>; Fugang >> Duan <B38611@freescale.com>; Wolfram Sang <wsa@kernel.org> >> Subject: Re: [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost >> >> [You don't often get email from dan.scally@ideasonboard.com. Learn why this is >> important at https://aka.ms/LearnAboutSenderIdentification ] >> >> Hello Oleksij / all >> >> On 24/04/2026 13:36, Daniel Scally wrote: >>> In i2c_imx_xfer_common(), the driver attempts bus recovery whenever >>> i2c_imx_start() fails. One of the failure modes for i2c_imx_start() is >>> an arbitration-lost signal which results when a second I2C master on >>> the bus tries to control the bus simultaneously, which is a normal and >>> expected behaviour. >>> >>> Bus recovery is not the right response for this case. Add a check for >>> the -EAGAIN return code to avoid running the bus recovery. >>> >>> Fixes: 1c4b6c3bcf30d ("i2c: imx: implement bus recovery") >>> Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> >>> --- >> >> I raised this patch after we had issues with one of the i2c controllers on imx8mp. >> In that case, the bus had multiple masters that were causing the SoC's i2c >> controller to lose arbitration. The result was that the framework attempted to >> run i2c_generic_scl_recovery() and regularly hit the "SCL is stuck low, exit >> recovery" message [1] because the bus was busy rather than stuck. >> >> I'm now experiencing a different issue with the imx8mp in which a different >> controller - which isn't on a multiple-masters bus - starts transacting fine early in >> boot, but then seems to get stuck - any attempt to start a transaction by either >> a driver or i2ctransfer results in the IAL bit in I2C_I2SR being set and so the >> driver reports that it's lost arbitration [2]. In this case, the bus recovery is >> needed to fix the problem, and so this commit hurts things rather than helps >> them. This problem isn't consistent - I get it on maybe 10% of boots. >> > Hi Dan, > > This is the RM shows: > > Arbitration lost. Set by hardware in the following circumstances (IAL must be cleared by software by > writing a "0" to it at the start of the interrupt service routine): > * I2Cn_SDA input samples low when the master drives high during an address or data-transmit cycle. > * I2Cn_SDA input samples low when the master drives high during the acknowledge bit of a datareceive > cycle. > For the above two cases, the bit is set at the falling edge of the ninth I2Cn_SCL clock during the ACK > cycle. > * A Start cycle is attempted when the bus is busy. > * A Repeated Start cycle is requested in Slave mode. > * A Stop condition is detected when the master did not request it. > NOTE: Software cannot set the bit. > 0 No arbitration lost. > 1 Arbitration is lost. > > From my understanding: > The IAL (Arbitration Lost) bit is set not only when true arbitration is lost, but also in several other conditions: > > - SDA is sampled low when the master drives it high (during address/data or ACK phase) > - A START is attempted while the bus is busy > - A STOP condition is detected unexpectedly > - A repeated START occurs in slave mode > > So in practice, IAL can be asserted not only by real arbitration loss, but also when the controller detects abnormal bus conditions. > > Since your system is single-master, this is unlikely to be a true arbitration scenario. Instead, it is more likely caused by signal integrity or timing-related issues, such as: > - weak pull-up / slow rising edges > - noise or glitches on SDA > - timing violations from the slave device > - others > > As a workaround, you can enable the 'single-master' property to disable arbitration checks in single-master systems, for example: > > &i2c1 { > clock-frequency = <400000>; > pinctrl-names = "default", "gpio"; > pinctrl-0 = <&pinctrl_i2c1>; > pinctrl-1 = <&pinctrl_i2c1_gpio>; > scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; > sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; > single-master; > status = "okay"; > }; Thanks! I'm away from the hardware at the moment but I'll give it a try next week and see if that fixes the issue. Dan > > Hope it will help some. > > Carlos ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] i2c: imx: Retry failed transfers 3 times 2026-04-24 12:36 [PATCH v2 0/2] Minor changes for i2c-imx driver Daniel Scally 2026-04-24 12:36 ` [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost Daniel Scally @ 2026-04-24 12:36 ` Daniel Scally 1 sibling, 0 replies; 6+ messages in thread From: Daniel Scally @ 2026-04-24 12:36 UTC (permalink / raw) To: Oleksij Rempel, Pengutronix Kernel Team, Andi Shyti, Frank Li, Sascha Hauer, Fabio Estevam, Gao Pan, Fugang Duan, Wolfram Sang Cc: linux-i2c, imx, linux-arm-kernel, Daniel Scally Set the retries member of the i2c_adapter to 3, which will cause the i2c-core code to retry transfers that lose arbitration 3 times before giving up. Reviewed-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> --- drivers/i2c/busses/i2c-imx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index b68a0f7105682006bbcfee52891c9a9c2d8c009e..e70e64cc633ff1e13dc61920c0c7960fb6a02622 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1749,6 +1749,7 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx->adapter.dev.parent = &pdev->dev; i2c_imx->adapter.nr = pdev->id; i2c_imx->adapter.dev.of_node = pdev->dev.of_node; + i2c_imx->adapter.retries = 3; i2c_imx->base = base; ACPI_COMPANION_SET(&i2c_imx->adapter.dev, ACPI_COMPANION(&pdev->dev)); -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-05-19 18:32 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-24 12:36 [PATCH v2 0/2] Minor changes for i2c-imx driver Daniel Scally 2026-04-24 12:36 ` [PATCH v2 1/2] i2c: imx: Don't recover bus when arbitration lost Daniel Scally 2026-05-19 8:42 ` Dan Scally 2026-05-19 10:29 ` Carlos Song (OSS) 2026-05-19 18:32 ` Dan Scally 2026-04-24 12:36 ` [PATCH v2 2/2] i2c: imx: Retry failed transfers 3 times Daniel Scally
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox