lt9611_sleep_setup() writes 0x8023 = 0x01, which overrides the ADDR
strap and moves the chip to I2C address 0x3b, and then configures the
ADDR pin as an output (0x8157/0x8149). On boards where the pin is
strapped low (address 0x39, e.g. Thundercomm RUBIK Pi 3) the chip
becomes unreachable as soon as the bridge is disabled: all further
register accesses NACK and on resume the bridge fails with "power on
failed", leaving HDMI dead until reboot.

Skip the address override and ADDR pin setup when the device sits at
the low-strap address.

While touching this driver, also fix the misleading error messages in
atomic disable path.

Fixes: 23278bf54afe ("drm/bridge: Introduce LT9611 DSI to HDMI bridge")
Signed-off-by: Marek Szyprowski <[email protected]>
---
The issue was analyzed and the patch was prepared with LLM assistance.
The fix was tested on the real Thundercomm RubikPi3 board - the HDMI
display now comes back after system suspend/resume cycle.

Best regards
Marek Szyprowski, PhD
Samsung R&D Institute Poland
---
 drivers/gpu/drm/bridge/lontium-lt9611.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c 
b/drivers/gpu/drm/bridge/lontium-lt9611.c
index 2d1a28261037..9e4f45d9f6d3 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -35,6 +35,9 @@
 
 #define LT9611_4LANES  0
 
+/* I2C address with the ADDR pin strapped low */
+#define LT9611_ADDR_LOW        0x39
+
 struct lt9611 {
        struct device *dev;
        struct drm_bridge bridge;
@@ -440,10 +443,13 @@ static void lt9611_sleep_setup(struct lt9611 *lt9611)
 {
        const struct reg_sequence sleep_setup[] = {
                { 0x8024, 0x76 },
+       };
+       const struct reg_sequence addr_pin_setup[] = {
                { 0x8023, 0x01 },
                { 0x8157, 0x03 }, /* set addr pin as output */
                { 0x8149, 0x0b },
-
+       };
+       const struct reg_sequence power_down[] = {
                { 0x8102, 0x48 }, /* MIPI Rx power down */
                { 0x8123, 0x80 },
                { 0x8130, 0x00 },
@@ -452,6 +458,18 @@ static void lt9611_sleep_setup(struct lt9611 *lt9611)
 
        regmap_multi_reg_write(lt9611->regmap,
                               sleep_setup, ARRAY_SIZE(sleep_setup));
+
+       /*
+        * The ADDR pin selects the I2C address and addr_pin_setup overrides
+        * it to high (0x8023 bit 0), which moves a chip strapped low over
+        * to 0x3b and makes it unreachable. Skip it in that case.
+        */
+       if (lt9611->client->addr != LT9611_ADDR_LOW)
+               regmap_multi_reg_write(lt9611->regmap, addr_pin_setup,
+                                      ARRAY_SIZE(addr_pin_setup));
+
+       regmap_multi_reg_write(lt9611->regmap,
+                              power_down, ARRAY_SIZE(power_down));
        lt9611->sleep = true;
 }
 
@@ -712,12 +730,12 @@ static void lt9611_bridge_atomic_disable(struct 
drm_bridge *bridge,
        /* Disable HDMI output */
        ret = regmap_write(lt9611->regmap, 0x8130, 0x6a);
        if (ret) {
-               dev_err(lt9611->dev, "video on failed\n");
+               dev_err(lt9611->dev, "video off failed\n");
                return;
        }
 
        if (lt9611_power_off(lt9611)) {
-               dev_err(lt9611->dev, "power on failed\n");
+               dev_err(lt9611->dev, "power off failed\n");
                return;
        }
 }
-- 
2.43.0

Reply via email to