Blob Blame History Raw
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Date: Sun, 11 Feb 2018 15:07:40 +0200
Subject: drm: omapdrm: displays: Get panel source at connect time
Git-commit: 2f8c4a8a9d4b65d296fd5ccd0c5ba7ad5cbcb931
Patch-mainline: v4.17-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

The connector drivers need a handle to the source they are connected to
in order to control the source.

All drivers get that handle at probe time, resulting in probe deferral
when the source hasn't been probed yet. However they don't need the
handle until their connect handler is called.

Move retrieval of the source handle to the connect handler to avoid
probe deferrals.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/omapdrm/displays/panel-dpi.c                |   34 +++-----
 drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c             |   27 +++----
 drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c |   35 +++------
 drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c     |   39 ++++------
 drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c  |   35 +++------
 drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c     |   26 +++---
 drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c     |   46 +++---------
 drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c     |   29 +++----
 8 files changed, 119 insertions(+), 152 deletions(-)

--- a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c
@@ -38,16 +38,25 @@ struct panel_drv_data {
 static int panel_dpi_connect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *in;
 	int r;
 
 	if (omapdss_device_is_connected(dssdev))
 		return 0;
 
+	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
+	if (IS_ERR(in)) {
+		dev_err(dssdev->dev, "failed to find video source\n");
+		return PTR_ERR(in);
+	}
+
 	r = in->ops.dpi->connect(in, dssdev);
-	if (r)
+	if (r) {
+		omap_dss_put_device(in);
 		return r;
+	}
 
+	ddata->in = in;
 	return 0;
 }
 
@@ -60,6 +69,9 @@ static void panel_dpi_disconnect(struct
 		return;
 
 	in->ops.dpi->disconnect(in, dssdev);
+
+	omap_dss_put_device(in);
+	ddata->in = NULL;
 }
 
 static int panel_dpi_enable(struct omap_dss_device *dssdev)
@@ -157,7 +169,6 @@ static int panel_dpi_probe_of(struct pla
 {
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct device_node *node = pdev->dev.of_node;
-	struct omap_dss_device *in;
 	int r;
 	struct display_timing timing;
 	struct gpio_desc *gpio;
@@ -195,14 +206,6 @@ static int panel_dpi_probe_of(struct pla
 
 	videomode_from_timing(&timing, &ddata->vm);
 
-	in = omapdss_of_find_source_for_first_ep(node);
-	if (IS_ERR(in)) {
-		dev_err(&pdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	ddata->in = in;
-
 	return 0;
 }
 
@@ -232,29 +235,22 @@ static int panel_dpi_probe(struct platfo
 	r = omapdss_register_display(dssdev);
 	if (r) {
 		dev_err(&pdev->dev, "Failed to register panel\n");
-		goto err_reg;
+		return r;
 	}
 
 	return 0;
-
-err_reg:
-	omap_dss_put_device(ddata->in);
-	return r;
 }
 
 static int __exit panel_dpi_remove(struct platform_device *pdev)
 {
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
-	struct omap_dss_device *in = ddata->in;
 
 	omapdss_unregister_display(dssdev);
 
 	panel_dpi_disable(dssdev);
 	panel_dpi_disconnect(dssdev);
 
-	omap_dss_put_device(in);
-
 	return 0;
 }
 
--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
@@ -759,17 +759,23 @@ static int dsicm_panel_reset(struct pane
 static int dsicm_connect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
 	struct device *dev = &ddata->pdev->dev;
+	struct omap_dss_device *in;
 	int r;
 
 	if (omapdss_device_is_connected(dssdev))
 		return 0;
 
+	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
+	if (IS_ERR(in)) {
+		dev_err(dssdev->dev, "failed to find video source\n");
+		return PTR_ERR(in);
+	}
+
 	r = in->ops.dsi->connect(in, dssdev);
 	if (r) {
 		dev_err(dev, "Failed to connect to video source\n");
-		return r;
+		goto err_connect;
 	}
 
 	r = in->ops.dsi->request_vc(ddata->in, &ddata->channel);
@@ -784,12 +790,15 @@ static int dsicm_connect(struct omap_dss
 		goto err_vc_id;
 	}
 
+	ddata->in = in;
 	return 0;
 
 err_vc_id:
 	in->ops.dsi->release_vc(ddata->in, ddata->channel);
 err_req_vc:
 	in->ops.dsi->disconnect(in, dssdev);
+err_connect:
+	omap_dss_put_device(in);
 	return r;
 }
 
@@ -803,6 +812,9 @@ static void dsicm_disconnect(struct omap
 
 	in->ops.dsi->release_vc(in, ddata->channel);
 	in->ops.dsi->disconnect(in, dssdev);
+
+	omap_dss_put_device(in);
+	ddata->in = NULL;
 }
 
 static int dsicm_enable(struct omap_dss_device *dssdev)
@@ -1223,7 +1235,6 @@ static int dsicm_probe_of(struct platfor
 	struct device_node *node = pdev->dev.of_node;
 	struct device_node *backlight;
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
-	struct omap_dss_device *in;
 	struct display_timing timing;
 	int err;
 
@@ -1259,12 +1270,6 @@ static int dsicm_probe_of(struct platfor
 	ddata->height_mm = 0;
 	of_property_read_u32(node, "height-mm", &ddata->height_mm);
 
-	in = omapdss_of_find_source_for_first_ep(node);
-	if (IS_ERR(in)) {
-		dev_err(&pdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
 	ddata->vpnl = devm_regulator_get_optional(&pdev->dev, "vpnl");
 	if (IS_ERR(ddata->vpnl)) {
 		err = PTR_ERR(ddata->vpnl);
@@ -1281,8 +1286,6 @@ static int dsicm_probe_of(struct platfor
 		ddata->vddi = NULL;
 	}
 
-	ddata->in = in;
-
 	backlight = of_parse_phandle(node, "backlight", 0);
 	if (backlight) {
 		ddata->extbldev = of_find_backlight_by_node(backlight);
@@ -1421,8 +1424,6 @@ static int __exit dsicm_remove(struct pl
 	if (ddata->extbldev)
 		put_device(&ddata->extbldev->dev);
 
-	omap_dss_put_device(ddata->in);
-
 	dsicm_cancel_ulps_work(ddata);
 	destroy_workqueue(ddata->workqueue);
 
--- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c
@@ -119,18 +119,27 @@ static void init_lb035q02_panel(struct s
 static int lb035q02_connect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *in;
 	int r;
 
 	if (omapdss_device_is_connected(dssdev))
 		return 0;
 
+	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
+	if (IS_ERR(in)) {
+		dev_err(dssdev->dev, "failed to find video source\n");
+		return PTR_ERR(in);
+	}
+
 	r = in->ops.dpi->connect(in, dssdev);
-	if (r)
+	if (r) {
+		omap_dss_put_device(in);
 		return r;
+	}
 
 	init_lb035q02_panel(ddata->spi);
 
+	ddata->in = in;
 	return 0;
 }
 
@@ -143,6 +152,9 @@ static void lb035q02_disconnect(struct o
 		return;
 
 	in->ops.dpi->disconnect(in, dssdev);
+
+	omap_dss_put_device(in);
+	ddata->in = NULL;
 }
 
 static int lb035q02_enable(struct omap_dss_device *dssdev)
@@ -230,9 +242,7 @@ static struct omap_dss_driver lb035q02_o
 
 static int lb035q02_probe_of(struct spi_device *spi)
 {
-	struct device_node *node = spi->dev.of_node;
 	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
-	struct omap_dss_device *in;
 	struct gpio_desc *gpio;
 
 	gpio = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW);
@@ -243,14 +253,6 @@ static int lb035q02_probe_of(struct spi_
 
 	ddata->enable_gpio = gpio;
 
-	in = omapdss_of_find_source_for_first_ep(node);
-	if (IS_ERR(in)) {
-		dev_err(&spi->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	ddata->in = in;
-
 	return 0;
 }
 
@@ -284,29 +286,22 @@ static int lb035q02_panel_spi_probe(stru
 	r = omapdss_register_display(dssdev);
 	if (r) {
 		dev_err(&spi->dev, "Failed to register panel\n");
-		goto err_reg;
+		return r;
 	}
 
 	return 0;
-
-err_reg:
-	omap_dss_put_device(ddata->in);
-	return r;
 }
 
 static int lb035q02_panel_spi_remove(struct spi_device *spi)
 {
 	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
-	struct omap_dss_device *in = ddata->in;
 
 	omapdss_unregister_display(dssdev);
 
 	lb035q02_disable(dssdev);
 	lb035q02_disconnect(dssdev);
 
-	omap_dss_put_device(in);
-
 	return 0;
 }
 
--- a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c
@@ -115,16 +115,25 @@ static int init_nec_8048_wvga_lcd(struct
 static int nec_8048_connect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *in;
 	int r;
 
 	if (omapdss_device_is_connected(dssdev))
 		return 0;
 
+	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
+	if (IS_ERR(in)) {
+		dev_err(dssdev->dev, "failed to find video source\n");
+		return PTR_ERR(in);
+	}
+
 	r = in->ops.dpi->connect(in, dssdev);
-	if (r)
+	if (r) {
+		omap_dss_put_device(in);
 		return r;
+	}
 
+	ddata->in = in;
 	return 0;
 }
 
@@ -137,6 +146,9 @@ static void nec_8048_disconnect(struct o
 		return;
 
 	in->ops.dpi->disconnect(in, dssdev);
+
+	omap_dss_put_device(in);
+	ddata->in = NULL;
 }
 
 static int nec_8048_enable(struct omap_dss_device *dssdev)
@@ -226,7 +238,6 @@ static int nec_8048_probe_of(struct spi_
 {
 	struct device_node *node = spi->dev.of_node;
 	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
-	struct omap_dss_device *in;
 	int gpio;
 
 	gpio = of_get_named_gpio(node, "reset-gpios", 0);
@@ -239,14 +250,6 @@ static int nec_8048_probe_of(struct spi_
 	/* XXX the panel spec doesn't mention any QVGA pin?? */
 	ddata->qvga_gpio = -ENOENT;
 
-	in = omapdss_of_find_source_for_first_ep(node);
-	if (IS_ERR(in)) {
-		dev_err(&spi->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	ddata->in = in;
-
 	return 0;
 }
 
@@ -285,14 +288,14 @@ static int nec_8048_probe(struct spi_dev
 		r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio,
 				GPIOF_OUT_INIT_HIGH, "lcd QVGA");
 		if (r)
-			goto err_gpio;
+			return r;
 	}
 
 	if (gpio_is_valid(ddata->res_gpio)) {
 		r = devm_gpio_request_one(&spi->dev, ddata->res_gpio,
 				GPIOF_OUT_INIT_LOW, "lcd RES");
 		if (r)
-			goto err_gpio;
+			return r;
 	}
 
 	ddata->vm = nec_8048_panel_vm;
@@ -307,22 +310,16 @@ static int nec_8048_probe(struct spi_dev
 	r = omapdss_register_display(dssdev);
 	if (r) {
 		dev_err(&spi->dev, "Failed to register panel\n");
-		goto err_reg;
+		return r;
 	}
 
 	return 0;
-
-err_reg:
-err_gpio:
-	omap_dss_put_device(ddata->in);
-	return r;
 }
 
 static int nec_8048_remove(struct spi_device *spi)
 {
 	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
-	struct omap_dss_device *in = ddata->in;
 
 	dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 
@@ -331,8 +328,6 @@ static int nec_8048_remove(struct spi_de
 	nec_8048_disable(dssdev);
 	nec_8048_disconnect(dssdev);
 
-	omap_dss_put_device(in);
-
 	return 0;
 }
 
--- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c
@@ -61,16 +61,25 @@ static const struct videomode sharp_ls_v
 static int sharp_ls_connect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *in;
 	int r;
 
 	if (omapdss_device_is_connected(dssdev))
 		return 0;
 
+	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
+	if (IS_ERR(in)) {
+		dev_err(dssdev->dev, "failed to find video source\n");
+		return PTR_ERR(in);
+	}
+
 	r = in->ops.dpi->connect(in, dssdev);
-	if (r)
+	if (r) {
+		omap_dss_put_device(in);
 		return r;
+	}
 
+	ddata->in = in;
 	return 0;
 }
 
@@ -83,6 +92,9 @@ static void sharp_ls_disconnect(struct o
 		return;
 
 	in->ops.dpi->disconnect(in, dssdev);
+
+	omap_dss_put_device(in);
+	ddata->in = NULL;
 }
 
 static int sharp_ls_enable(struct omap_dss_device *dssdev)
@@ -210,8 +222,6 @@ static  int sharp_ls_get_gpio_of(struct
 static int sharp_ls_probe_of(struct platform_device *pdev)
 {
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
-	struct device_node *node = pdev->dev.of_node;
-	struct omap_dss_device *in;
 	int r;
 
 	ddata->vcc = devm_regulator_get(&pdev->dev, "envdd");
@@ -245,14 +255,6 @@ static int sharp_ls_probe_of(struct plat
 	if (r)
 		return r;
 
-	in = omapdss_of_find_source_for_first_ep(node);
-	if (IS_ERR(in)) {
-		dev_err(&pdev->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	ddata->in = in;
-
 	return 0;
 }
 
@@ -284,29 +286,22 @@ static int sharp_ls_probe(struct platfor
 	r = omapdss_register_display(dssdev);
 	if (r) {
 		dev_err(&pdev->dev, "Failed to register panel\n");
-		goto err_reg;
+		return r;
 	}
 
 	return 0;
-
-err_reg:
-	omap_dss_put_device(ddata->in);
-	return r;
 }
 
 static int __exit sharp_ls_remove(struct platform_device *pdev)
 {
 	struct panel_drv_data *ddata = platform_get_drvdata(pdev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
-	struct omap_dss_device *in = ddata->in;
 
 	omapdss_unregister_display(dssdev);
 
 	sharp_ls_disable(dssdev);
 	sharp_ls_disconnect(dssdev);
 
-	omap_dss_put_device(in);
-
 	return 0;
 }
 
--- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
@@ -510,16 +510,25 @@ static const struct attribute_group blde
 static int acx565akm_connect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *in;
 	int r;
 
 	if (omapdss_device_is_connected(dssdev))
 		return 0;
 
+	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
+	if (IS_ERR(in)) {
+		dev_err(dssdev->dev, "failed to find video source\n");
+		return PTR_ERR(in);
+	}
+
 	r = in->ops.sdi->connect(in, dssdev);
-	if (r)
+	if (r) {
+		omap_dss_put_device(in);
 		return r;
+	}
 
+	ddata->in = in;
 	return 0;
 }
 
@@ -532,6 +541,9 @@ static void acx565akm_disconnect(struct
 		return;
 
 	in->ops.sdi->disconnect(in, dssdev);
+
+	omap_dss_put_device(in);
+	ddata->in = NULL;
 }
 
 static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
@@ -700,12 +712,6 @@ static int acx565akm_probe_of(struct spi
 
 	ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
 
-	ddata->in = omapdss_of_find_source_for_first_ep(np);
-	if (IS_ERR(ddata->in)) {
-		dev_err(&spi->dev, "failed to find video source\n");
-		return PTR_ERR(ddata->in);
-	}
-
 	return 0;
 }
 
@@ -823,7 +829,6 @@ err_sysfs:
 err_reg_bl:
 err_detect:
 err_gpio:
-	omap_dss_put_device(ddata->in);
 	return r;
 }
 
@@ -831,7 +836,6 @@ static int acx565akm_remove(struct spi_d
 {
 	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
-	struct omap_dss_device *in = ddata->in;
 
 	dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 
@@ -843,8 +847,6 @@ static int acx565akm_remove(struct spi_d
 	acx565akm_disable(dssdev);
 	acx565akm_disconnect(dssdev);
 
-	omap_dss_put_device(in);
-
 	return 0;
 }
 
--- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c
@@ -169,16 +169,25 @@ enum jbt_register {
 static int td028ttec1_panel_connect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *in;
 	int r;
 
 	if (omapdss_device_is_connected(dssdev))
 		return 0;
 
+	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
+	if (IS_ERR(in)) {
+		dev_err(dssdev->dev, "failed to find video source\n");
+		return PTR_ERR(in);
+	}
+
 	r = in->ops.dpi->connect(in, dssdev);
-	if (r)
+	if (r) {
+		omap_dss_put_device(in);
 		return r;
+	}
 
+	ddata->in = in;
 	return 0;
 }
 
@@ -191,6 +200,9 @@ static void td028ttec1_panel_disconnect(
 		return;
 
 	in->ops.dpi->disconnect(in, dssdev);
+
+	omap_dss_put_device(in);
+	ddata->in = NULL;
 }
 
 static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
@@ -362,23 +374,6 @@ static struct omap_dss_driver td028ttec1
 	.check_timings	= td028ttec1_panel_check_timings,
 };
 
-static int td028ttec1_probe_of(struct spi_device *spi)
-{
-	struct device_node *node = spi->dev.of_node;
-	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
-	struct omap_dss_device *in;
-
-	in = omapdss_of_find_source_for_first_ep(node);
-	if (IS_ERR(in)) {
-		dev_err(&spi->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	ddata->in = in;
-
-	return 0;
-}
-
 static int td028ttec1_panel_probe(struct spi_device *spi)
 {
 	struct panel_drv_data *ddata;
@@ -404,10 +399,6 @@ static int td028ttec1_panel_probe(struct
 
 	ddata->spi_dev = spi;
 
-	r = td028ttec1_probe_of(spi);
-	if (r)
-		return r;
-
 	ddata->vm = td028ttec1_panel_vm;
 
 	dssdev = &ddata->dssdev;
@@ -420,21 +411,16 @@ static int td028ttec1_panel_probe(struct
 	r = omapdss_register_display(dssdev);
 	if (r) {
 		dev_err(&spi->dev, "Failed to register panel\n");
-		goto err_reg;
+		return r;
 	}
 
 	return 0;
-
-err_reg:
-	omap_dss_put_device(ddata->in);
-	return r;
 }
 
 static int td028ttec1_panel_remove(struct spi_device *spi)
 {
 	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
-	struct omap_dss_device *in = ddata->in;
 
 	dev_dbg(&ddata->spi_dev->dev, "%s\n", __func__);
 
@@ -443,8 +429,6 @@ static int td028ttec1_panel_remove(struc
 	td028ttec1_panel_disable(dssdev);
 	td028ttec1_panel_disconnect(dssdev);
 
-	omap_dss_put_device(in);
-
 	return 0;
 }
 
--- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c
@@ -340,16 +340,25 @@ static void tpo_td043_power_off(struct p
 static int tpo_td043_connect(struct omap_dss_device *dssdev)
 {
 	struct panel_drv_data *ddata = to_panel_data(dssdev);
-	struct omap_dss_device *in = ddata->in;
+	struct omap_dss_device *in;
 	int r;
 
 	if (omapdss_device_is_connected(dssdev))
 		return 0;
 
+	in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
+	if (IS_ERR(in)) {
+		dev_err(dssdev->dev, "failed to find video source\n");
+		return PTR_ERR(in);
+	}
+
 	r = in->ops.dpi->connect(in, dssdev);
-	if (r)
+	if (r) {
+		omap_dss_put_device(in);
 		return r;
+	}
 
+	ddata->in = in;
 	return 0;
 }
 
@@ -362,6 +371,9 @@ static void tpo_td043_disconnect(struct
 		return;
 
 	in->ops.dpi->disconnect(in, dssdev);
+
+	omap_dss_put_device(in);
+	ddata->in = NULL;
 }
 
 static int tpo_td043_enable(struct omap_dss_device *dssdev)
@@ -463,7 +475,6 @@ static int tpo_td043_probe_of(struct spi
 {
 	struct device_node *node = spi->dev.of_node;
 	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
-	struct omap_dss_device *in;
 	int gpio;
 
 	gpio = of_get_named_gpio(node, "reset-gpios", 0);
@@ -473,14 +484,6 @@ static int tpo_td043_probe_of(struct spi
 	}
 	ddata->nreset_gpio = gpio;
 
-	in = omapdss_of_find_source_for_first_ep(node);
-	if (IS_ERR(in)) {
-		dev_err(&spi->dev, "failed to find video source\n");
-		return PTR_ERR(in);
-	}
-
-	ddata->in = in;
-
 	return 0;
 }
 
@@ -561,7 +564,6 @@ err_reg:
 err_sysfs:
 err_gpio_req:
 err_regulator:
-	omap_dss_put_device(ddata->in);
 	return r;
 }
 
@@ -569,7 +571,6 @@ static int tpo_td043_remove(struct spi_d
 {
 	struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 	struct omap_dss_device *dssdev = &ddata->dssdev;
-	struct omap_dss_device *in = ddata->in;
 
 	dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 
@@ -578,8 +579,6 @@ static int tpo_td043_remove(struct spi_d
 	tpo_td043_disable(dssdev);
 	tpo_td043_disconnect(dssdev);
 
-	omap_dss_put_device(in);
-
 	sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
 
 	return 0;