Thread (7 messages) 7 messages, 3 authors, 2026-01-16

Re: [PATCH v1 0/2] i2c: add support for forced SDA recovery

From: 李杰 <hidden>
Date: 2026-01-15 13:13:11
Also in: linux-gpio, linux-i2c, lkml

Dear Linus,

Thank you for your feedback and the insightful suggestion regarding
GPIO_OPEN_DRAIN.

I have analyzed the current implementation of gpiod_get_direction() in
the kernel, and I believe that relying solely on standard GPIO flags
cannot resolve the "deadlock" on this specific hardware.

The issue lies in how gpiod_get_direction() interacts with certain
open-drain controllers. As seen in the source code:

Even if FLAG_OPEN_DRAIN is set, the function falls back to
gc->get_direction() if the FLAG_IS_OUT bit hasn't been established
yet. Crucially, some ASICs do not even implement a readable direction
bit in hardware.

In many true open-drain hardware implementations, a line driven "high"
(high-impedance) is physically reported as an Input by the hardware
register.

Consequently, gc->get_direction() returns 1 (Input), and the following
assign_bit(FLAG_IS_OUT, &desc->flags, !ret) explicitly clears the
output flag in the kernel's descriptor.

This creates a logic loop in i2c_init_recovery():

The I2C core queries the direction via gpiod_get_direction().

The function returns 1 because the line is currently high/floating or
the hardware lacks direction reporting.

The I2C core then assumes the pin is "Input-only" and skips the
assignment of bri->set_sda.

Bus recovery becomes impossible even though the hardware is fully
capable of driving the line low.

Regarding the suggestion to use GPIOD_OUT_HIGH_OPEN_DRAIN in the I2C
core: I am concerned that forcing the line to "Output" globally in the
core might be too aggressive for all platforms. My proposed
force-set-sda property provides a safe, explicit way for a specific
board to say: "I know this pin reports as Input, but it is safe to
treat it as an Output for recovery."

I believe this explicit opt-in mechanism is more robust than relying
on an automatic detection that is fundamentally tied to the
instantaneous state of a high-impedance line.

What do you think about this perspective?

Best regards,
Jie Li


On Thu, Jan 15, 2026 at 10:27 AM Linus Walleij [off-list ref] wrote:
Hi Jie,

thanks for your patch!

On Wed, Jan 14, 2026 at 3:13 PM Jie Li [off-list ref] wrote:
quoted
This series addresses a limitation in the I2C bus recovery mechanism when
dealing with certain open-drain GPIO configurations where the direction
cannot be automatically detected.
I'm sorry but I don't understand the premise. How can we even get here?

So the mechanism is about I2C that is using a regular I2C block, and
the pins get re-muxed to GPIO to drive recovery using the I2C
core GPIO-mode recovery mechanism with bridge->sda_gpiod
which is retrieved in the core from "sda" which in DT is
sda-gpios = <....>; (calong with similarly named SCL) for
GPIO-mode recovery.

So if that is set in an input mode, such as during devm_gpiod_get()
reading the initial direction of the line,
so gpiod_get_direction(bri->sda_gpiod) == 1.
this patch set will go and write output values to the line
*anyway* because "it works".

This is how I understand the patch set.

In which scenario do you have a device tree where you can add
"force-set-sda" to a DT node, but you *can't* just fix up the
SCL/SDA flags like this:

#include <dt-bindings/gpio/gpio.h>

sda-gpios = <&gpio0 5 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
scl-gpios = <&gpio0 6 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;

?

We should possibly also enforce it from the I2C recovery core,
for SDA we are currently doing:

gpiod = devm_gpiod_get(dev, "sda", GPIOD_IN);

what happens if you patch i2c-core-base.c to simply do:

gpiod = devm_gpiod_get(dev, "sda", GPIOD_OUT_HIGH_OPEN_DRAIN);

(Based on SDA resting polarity being high.)
I'm more uncertain about that one because I don't know exactly
how hardware behaves in response to this, but can you test this
first if you have to hack around in the core?

Yours,
Linus Walleij
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help