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