if (of_property_read_bool(np, "analogix,audio-enable"))
                pdata->audio_en = 1;
 
+       return 0;
+}
+
+static int anx7625_parse_dt_panel(struct device *dev,
+                                 struct anx7625_platform_data *pdata)
+{
+       struct device_node *np = dev->of_node;
+
        pdata->panel_bridge = devm_drm_of_get_bridge(dev, np, 1, 0);
        if (IS_ERR(pdata->panel_bridge)) {
                if (PTR_ERR(pdata->panel_bridge) == -ENODEV) {
        return 0;
 }
 
-static int anx7625_attach_dsi(struct anx7625_data *ctx)
+static int anx7625_setup_dsi_device(struct anx7625_data *ctx)
 {
        struct mipi_dsi_device *dsi;
        struct device *dev = &ctx->client->dev;
                .channel = 0,
                .node = NULL,
        };
-       int ret;
-
-       DRM_DEV_DEBUG_DRIVER(dev, "attach dsi\n");
 
        host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node);
        if (!host) {
                MIPI_DSI_MODE_VIDEO_HSE |
                MIPI_DSI_HS_PKT_END_ALIGNED;
 
-       ret = devm_mipi_dsi_attach(dev, dsi);
+       ctx->dsi = dsi;
+
+       return 0;
+}
+
+static int anx7625_attach_dsi(struct anx7625_data *ctx)
+{
+       struct device *dev = &ctx->client->dev;
+       int ret;
+
+       DRM_DEV_DEBUG_DRIVER(dev, "attach dsi\n");
+
+       ret = devm_mipi_dsi_attach(dev, ctx->dsi);
        if (ret) {
                DRM_DEV_ERROR(dev, "fail to attach dsi to host.\n");
                return ret;
        }
 
-       ctx->dsi = dsi;
-
        DRM_DEV_DEBUG_DRIVER(dev, "attach dsi succeeded.\n");
 
        return 0;
        pm_runtime_disable(data);
 }
 
+static int anx7625_link_bridge(struct drm_dp_aux *aux)
+{
+       struct anx7625_data *platform = container_of(aux, struct anx7625_data, aux);
+       struct device *dev = aux->dev;
+       int ret;
+
+       ret = anx7625_parse_dt_panel(dev, &platform->pdata);
+       if (ret) {
+               DRM_DEV_ERROR(dev, "fail to parse DT for panel : %d\n", ret);
+               return ret;
+       }
+
+       platform->bridge.funcs = &anx7625_bridge_funcs;
+       platform->bridge.of_node = dev->of_node;
+       if (!anx7625_of_panel_on_aux_bus(dev))
+               platform->bridge.ops |= DRM_BRIDGE_OP_EDID;
+       if (!platform->pdata.panel_bridge)
+               platform->bridge.ops |= DRM_BRIDGE_OP_HPD |
+                                       DRM_BRIDGE_OP_DETECT;
+       platform->bridge.type = platform->pdata.panel_bridge ?
+                                   DRM_MODE_CONNECTOR_eDP :
+                                   DRM_MODE_CONNECTOR_DisplayPort;
+
+       drm_bridge_add(&platform->bridge);
+
+       if (!platform->pdata.is_dpi) {
+               ret = anx7625_attach_dsi(platform);
+               if (ret)
+                       drm_bridge_remove(&platform->bridge);
+       }
+
+       return ret;
+}
+
 static int anx7625_i2c_probe(struct i2c_client *client)
 {
        struct anx7625_data *platform;
        platform->aux.wait_hpd_asserted = anx7625_wait_hpd_asserted;
        drm_dp_aux_init(&platform->aux);
 
+       ret = anx7625_parse_dt(dev, pdata);
+       if (ret) {
+               if (ret != -EPROBE_DEFER)
+                       DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret);
+               goto free_wq;
+       }
+
+       if (!platform->pdata.is_dpi) {
+               ret = anx7625_setup_dsi_device(platform);
+               if (ret < 0)
+                       goto free_wq;
+       }
+
+       /*
+        * Registering the i2c devices will retrigger deferred probe, so it
+        * needs to be done after calls that might return EPROBE_DEFER,
+        * otherwise we can get an infinite loop.
+        */
        if (anx7625_register_i2c_dummy_clients(platform, client) != 0) {
                ret = -ENOMEM;
                DRM_DEV_ERROR(dev, "fail to reserve I2C bus.\n");
        if (ret)
                goto free_wq;
 
-       devm_of_dp_aux_populate_ep_devices(&platform->aux);
-
-       ret = anx7625_parse_dt(dev, pdata);
+       /*
+        * Populating the aux bus will retrigger deferred probe, so it needs to
+        * be done after calls that might return EPROBE_DEFER, otherwise we can
+        * get an infinite loop.
+        */
+       ret = devm_of_dp_aux_populate_bus(&platform->aux, anx7625_link_bridge);
        if (ret) {
-               if (ret != -EPROBE_DEFER)
-                       DRM_DEV_ERROR(dev, "fail to parse DT : %d\n", ret);
-               goto free_wq;
+               if (ret != -ENODEV) {
+                       DRM_DEV_ERROR(dev, "failed to populate aux bus : %d\n", ret);
+                       goto free_wq;
+               }
+
+               ret = anx7625_link_bridge(&platform->aux);
+               if (ret)
+                       goto free_wq;
        }
 
        if (!platform->pdata.low_power_mode) {
        if (platform->pdata.intp_irq)
                queue_work(platform->workqueue, &platform->work);
 
-       platform->bridge.funcs = &anx7625_bridge_funcs;
-       platform->bridge.of_node = client->dev.of_node;
-       if (!anx7625_of_panel_on_aux_bus(&client->dev))
-               platform->bridge.ops |= DRM_BRIDGE_OP_EDID;
-       if (!platform->pdata.panel_bridge)
-               platform->bridge.ops |= DRM_BRIDGE_OP_HPD |
-                                       DRM_BRIDGE_OP_DETECT;
-       platform->bridge.type = platform->pdata.panel_bridge ?
-                                   DRM_MODE_CONNECTOR_eDP :
-                                   DRM_MODE_CONNECTOR_DisplayPort;
-
-       drm_bridge_add(&platform->bridge);
-
-       if (!platform->pdata.is_dpi) {
-               ret = anx7625_attach_dsi(platform);
-               if (ret) {
-                       DRM_DEV_ERROR(dev, "Fail to attach to dsi : %d\n", ret);
-                       goto unregister_bridge;
-               }
-       }
-
        if (platform->pdata.audio_en)
                anx7625_register_audio(dev, platform);
 
 
        return 0;
 
-unregister_bridge:
-       drm_bridge_remove(&platform->bridge);
-
-       if (!platform->pdata.low_power_mode)
-               pm_runtime_put_sync_suspend(&client->dev);
-
 free_wq:
        if (platform->workqueue)
                destroy_workqueue(platform->workqueue);