From: Wolfram Sang <wsa+renesas@sang-engineering.com>
To: Stanley Chong <ale.sarick@gmail.com>
Cc: Andi Shyti <andi.shyti@kernel.org>, linux-i2c@vger.kernel.org
Subject: Re: [RFC PATCH] i2c: algo-bit: return -EBUSY if the bus is not idle after STOP
Date: Wed, 4 Nov 2026 23:29:35 +0200 [thread overview]
Message-ID: <auujutmzEYNySrGV@shikoro> (raw)
In-Reply-To: <20261027130315.390-1-ale.sarick@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 4668 bytes --]
Hi Stanley,
thanks for the patch, the thorough explanations, and your care to
prevent regressions!
> When a device on the bus holds SDA low, bit_xfer() can still report
> success. i2c_stop() releases SDA, but it never checks that SDA and SCL
> really went high. The caller gets a positive message count and a
> buffer full of zeros.
>
> I found this on a Raspberry Pi 3B with i2c-gpio. An Arduino Uno pulls
> SDA low on command. With SDA held low, all 12 test transfers returned
> success. One of them is a write to address 0x70, where no device
> exists.
>
> This patch reads SDA and SCL after the STOP condition. If either line
> is still low, the bus is not free, and bit_xfer() returns -EBUSY.
> If the adapter has no getsda() or getscl(), that line is not checked.
Basically correct, but the check should not be applied after a STOP but
before a START. Remember that I2C is (theoretically) a multi-master bus.
If not both lines are high, it could be that another controller is
transmitting. This is why it should be checked before starting a
message. We retry in the hope that the other controller is done by then,
so the bus can be used by ourself again.
> I chose -EBUSY because the I2C core already uses it for a line that is
> stuck low. i2c_generic_bus_free() returns -EBUSY when SDA is low, and
> i2c_generic_scl_recovery() returns -EBUSY when SCL is stuck low.
> i2c-aspeed also returns -EBUSY for its SDA and SCL low timeouts.
We have defined error value for most cases. Not all driver adhere it to
it 100%, but we are striving for that because it is so much easier for
the upper layers. Check:
Documentation/i2c/fault-codes.rst
So, in your case, if the check is moved to the beginning, -EAGAIN would
be the proper error code. (And -EBUSY probably needs an update saying
that it is also the response of a failed recovery)
> The check runs in the bailout path, before post_xfer(). At this point
> the lines are still in the mode that pre_xfer() set up. So the check
> reads the lines the same way the ACK reads do during the transfer.
>
> With the patch, all 12 transfers return -EBUSY in 0.2 to 0.4 ms.
> Normal transfers do not change. When SCL is held low, the error code
> changes from -ENXIO to -EBUSY. See the questions below.
>
> Signed-off-by: Stanley Chong <ale.sarick@gmail.com>
> ---
> This is an RFC because the patch changes the error code in some cases.
> I would like to know if this direction is acceptable before I go
> further.
>
> Questions
> 1. SCL stuck low: -ENXIO becomes -EBUSY.
> drm_do_probe_ddc_edid() stops retrying when it gets -ENXIO. With
> this patch, a DDC bus with SCL stuck low is tried 5 times instead
> of once. radeon and amdgpu use a timeout of usecs_to_jiffies(2200).
> That is at least one jiffy: 4 ms at HZ=250, 10 ms at HZ=100. I have
> not measured this on a real DDC bus.
-ENXIO means no device is responding (so no retries). This is plain
wrong. -EAGAIN will be much better because the bus might be
(theoretically) free somewhen. This is actually an improvement.
> 2. Some DDC buses read low when they are idle.
> In bugzilla 200045 (the 2018 revert of "i2c: algo-bit: init the
> bus to a known state"), radeon buses 0x92, 0x93 and 0x14 read SCL=0
> even after pre_xfer() was called (comment 14). Today such a bus
> fails at the address phase with -ENXIO. With this patch it returns
> -EBUSY, so DRM retries it as in question 1. Is that acceptable, or
> should the check be opt-in per adapter?
This is actually improved to the expected behaviour. If SCL is stuck
low, it will fail as well, just a tad later.
> 3. Rise time.
> The check reads the lines adap->udelay after releasing SDA (5 us for
> i2c-gpio at 100 kHz). The I2C spec allows at most 1 us rise time in
> Standard-mode, so a compliant bus is high by then. A bus with weak
> pull-ups is out of spec, but it may work today. With this patch it
> could start getting -EBUSY. Is that acceptable, or should the check
> wait longer?
I think the problem is gone when you move the check before START because
we did not modify a signal yet.
> 4. Recovery.
> Neither algo-bit nor i2c-gpio sets up bus recovery, and the core
> only retries on -EAGAIN. So -EBUSY goes straight back to the
> caller. Should bit_xfer() try i2c_recover_bus() first when
> bus_recovery_info is set?
When to do recovery is a question of its own. I would leave it out for
now and tackle your issue seperately first.
Does this all make sense to you?
Thanks again and happy hacking,
Wolfram
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
prev parent reply other threads:[~2026-11-04 21:29 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 13:02 [RFC PATCH] i2c: algo-bit: return -EBUSY if the bus is not idle after STOP Stanley Chong
2026-11-04 21:29 ` Wolfram Sang [this message]
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=auujutmzEYNySrGV@shikoro \
--to=wsa+renesas@sang-engineering.com \
--cc=ale.sarick@gmail.com \
--cc=andi.shyti@kernel.org \
--cc=linux-i2c@vger.kernel.org \
/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