Make sure to drop the i2c adapter reference on probe failure (e.g.
probe deferral) and on driver unbind also if a devicetree redundantly
uses the 'ddc-i2c-bus' property to point to the aux ddc bus.

Fixes: cc5a3fc041f0 ("drm/panel: panel-simple: Stash DP AUX bus; allow using it 
for DDC")
Cc: [email protected]      # 5.15
Reported-by: Douglas Anderson <[email protected]>
Link: 
https://lore.kernel.org/r/CAD=FV=vzphzhu+pet2m3l+pqc7mopfzc-f5p0ounl79wnzp...@mail.gmail.com
Signed-off-by: Johan Hovold <[email protected]>
---
 drivers/gpu/drm/panel/panel-edp.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index aa27d6cd932e..ac815729aa83 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -831,6 +831,13 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
        return 0;
 }
 
+static void panel_edp_put_adapter(void *_adap)
+{
+       struct i2c_adapter *adap = _adap;
+
+       put_device(&adap->dev);
+}
+
 static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
                           struct drm_dp_aux *aux)
 {
@@ -878,6 +885,11 @@ static int panel_edp_probe(struct device *dev, const 
struct panel_desc *desc,
 
                if (!panel->ddc)
                        return -EPROBE_DEFER;
+
+               err = devm_add_action_or_reset(dev, panel_edp_put_adapter,
+                                              panel->ddc);
+               if (err)
+                       return err;
        } else if (aux) {
                panel->ddc = &aux->ddc;
        }
@@ -889,7 +901,7 @@ static int panel_edp_probe(struct device *dev, const struct 
panel_desc *desc,
 
        err = drm_panel_of_backlight(&panel->base);
        if (err)
-               goto err_finished_ddc_init;
+               return err;
 
        /*
         * We use runtime PM for prepare / unprepare since those power the panel
@@ -936,9 +948,6 @@ static int panel_edp_probe(struct device *dev, const struct 
panel_desc *desc,
 err_finished_pm_runtime:
        pm_runtime_dont_use_autosuspend(dev);
        pm_runtime_disable(dev);
-err_finished_ddc_init:
-       if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
-               put_device(&panel->ddc->dev);
 
        return err;
 }
@@ -982,8 +991,6 @@ static void panel_edp_remove(struct device *dev)
 
        pm_runtime_dont_use_autosuspend(dev);
        pm_runtime_disable(dev);
-       if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc))
-               put_device(&panel->ddc->dev);
 
        drm_edid_free(panel->drm_edid);
        panel->drm_edid = NULL;
-- 
2.54.0

Reply via email to