struct ipu_soc *ipu;
        struct v4l2_subdev sd;
        struct media_pad pad[CSI_NUM_PADS];
+       struct v4l2_async_notifier notifier;
+
        /* the video device at IDMAC output pad */
        struct imx_media_video_dev *vdev;
        struct imx_media_fim *fim;
        .unregistered = csi_unregistered,
 };
 
-static int imx_csi_parse_endpoint(struct device *dev,
-                                 struct v4l2_fwnode_endpoint *vep,
-                                 struct v4l2_async_subdev *asd)
-{
-       return fwnode_device_is_available(asd->match.fwnode) ? 0 : -ENOTCONN;
-}
-
 static int imx_csi_async_register(struct csi_priv *priv)
 {
-       struct v4l2_async_notifier *notifier;
-       struct fwnode_handle *fwnode;
+       struct v4l2_async_subdev *asd = NULL;
+       struct fwnode_handle *ep;
        unsigned int port;
        int ret;
 
-       notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
-       if (!notifier)
-               return -ENOMEM;
-
-       v4l2_async_notifier_init(notifier);
-
-       fwnode = dev_fwnode(priv->dev);
+       v4l2_async_notifier_init(&priv->notifier);
 
        /* get this CSI's port id */
-       ret = fwnode_property_read_u32(fwnode, "reg", &port);
-       if (ret < 0)
-               goto out_free;
-
-       ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
-               priv->dev->parent, notifier, sizeof(struct v4l2_async_subdev),
-               port, imx_csi_parse_endpoint);
+       ret = fwnode_property_read_u32(dev_fwnode(priv->dev), "reg", &port);
        if (ret < 0)
-               goto out_cleanup;
+               return ret;
 
-       ret = v4l2_async_subdev_notifier_register(&priv->sd, notifier);
-       if (ret < 0)
-               goto out_cleanup;
+       ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev->parent),
+                                            port, 0,
+                                            FWNODE_GRAPH_ENDPOINT_NEXT);
+       if (ep) {
+               asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+               if (!asd) {
+                       fwnode_handle_put(ep);
+                       return -ENOMEM;
+               }
 
-       ret = v4l2_async_register_subdev(&priv->sd);
-       if (ret < 0)
-               goto out_unregister;
+               ret = v4l2_async_notifier_add_fwnode_remote_subdev(
+                       &priv->notifier, ep, asd);
 
-       priv->sd.subdev_notifier = notifier;
+               fwnode_handle_put(ep);
 
-       return 0;
+               if (ret) {
+                       kfree(asd);
+                       /* OK if asd already exists */
+                       if (ret != -EEXIST)
+                               return ret;
+               }
+       }
 
-out_unregister:
-       v4l2_async_notifier_unregister(notifier);
-out_cleanup:
-       v4l2_async_notifier_cleanup(notifier);
-out_free:
-       kfree(notifier);
+       ret = v4l2_async_subdev_notifier_register(&priv->sd,
+                                                 &priv->notifier);
+       if (ret)
+               return ret;
 
-       return ret;
+       return v4l2_async_register_subdev(&priv->sd);
 }
 
 static int imx_csi_probe(struct platform_device *pdev)
 
        ret = imx_csi_async_register(priv);
        if (ret)
-               goto free;
+               goto cleanup;
 
        return 0;
+
+cleanup:
+       v4l2_async_notifier_unregister(&priv->notifier);
+       v4l2_async_notifier_cleanup(&priv->notifier);
 free:
        v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
        mutex_destroy(&priv->lock);
 
        v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
        mutex_destroy(&priv->lock);
+       v4l2_async_notifier_unregister(&priv->notifier);
+       v4l2_async_notifier_cleanup(&priv->notifier);
        v4l2_async_unregister_subdev(sd);
        media_entity_cleanup(&sd->entity);
 
 
 struct csi2_dev {
        struct device          *dev;
        struct v4l2_subdev      sd;
+       struct v4l2_async_notifier notifier;
        struct media_pad       pad[CSI2_NUM_PADS];
        struct clk             *dphy_clk;
        struct clk             *pllref_clk;
        .registered = csi2_registered,
 };
 
-static int csi2_parse_endpoint(struct device *dev,
-                              struct v4l2_fwnode_endpoint *vep,
-                              struct v4l2_async_subdev *asd)
+static int csi2_async_register(struct csi2_dev *csi2)
 {
-       struct v4l2_subdev *sd = dev_get_drvdata(dev);
-       struct csi2_dev *csi2 = sd_to_dev(sd);
+       struct v4l2_fwnode_endpoint vep = {
+               .bus_type = V4L2_MBUS_CSI2_DPHY,
+       };
+       struct v4l2_async_subdev *asd = NULL;
+       struct fwnode_handle *ep;
+       int ret;
 
-       if (!fwnode_device_is_available(asd->match.fwnode)) {
-               v4l2_err(&csi2->sd, "remote is not available\n");
-               return -EINVAL;
-       }
+       v4l2_async_notifier_init(&csi2->notifier);
 
-       if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
-               v4l2_err(&csi2->sd, "invalid bus type, must be MIPI CSI2\n");
-               return -EINVAL;
-       }
+       ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi2->dev), 0, 0,
+                                            FWNODE_GRAPH_ENDPOINT_NEXT);
+       if (!ep)
+               return -ENOTCONN;
+
+       ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+       if (ret)
+               goto err_parse;
 
-       csi2->bus = vep->bus.mipi_csi2;
+       csi2->bus = vep.bus.mipi_csi2;
 
        dev_dbg(csi2->dev, "data lanes: %d\n", csi2->bus.num_data_lanes);
        dev_dbg(csi2->dev, "flags: 0x%08x\n", csi2->bus.flags);
 
-       return 0;
+       asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+       if (!asd) {
+               ret = -ENOMEM;
+               goto err_parse;
+       }
+
+       ret = v4l2_async_notifier_add_fwnode_remote_subdev(
+               &csi2->notifier, ep, asd);
+       if (ret)
+               goto err_parse;
+
+       fwnode_handle_put(ep);
+
+       ret = v4l2_async_subdev_notifier_register(&csi2->sd,
+                                                 &csi2->notifier);
+       if (ret)
+               return ret;
+
+       return v4l2_async_register_subdev(&csi2->sd);
+
+err_parse:
+       fwnode_handle_put(ep);
+       kfree(asd);
+       return ret;
 }
 
 static int csi2_probe(struct platform_device *pdev)
 {
-       unsigned int sink_port = 0;
        struct csi2_dev *csi2;
        struct resource *res;
        int i, ret;
 
        platform_set_drvdata(pdev, &csi2->sd);
 
-       ret = v4l2_async_register_fwnode_subdev(
-               &csi2->sd, sizeof(struct v4l2_async_subdev),
-               &sink_port, 1, csi2_parse_endpoint);
+       ret = csi2_async_register(csi2);
        if (ret)
-               goto dphy_off;
+               goto clean_notifier;
 
        return 0;
 
-dphy_off:
+clean_notifier:
+       v4l2_async_notifier_unregister(&csi2->notifier);
+       v4l2_async_notifier_cleanup(&csi2->notifier);
        clk_disable_unprepare(csi2->dphy_clk);
 pllref_off:
        clk_disable_unprepare(csi2->pllref_clk);
        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
        struct csi2_dev *csi2 = sd_to_dev(sd);
 
+       v4l2_async_notifier_unregister(&csi2->notifier);
+       v4l2_async_notifier_cleanup(&csi2->notifier);
        v4l2_async_unregister_subdev(sd);
        clk_disable_unprepare(csi2->dphy_clk);
        clk_disable_unprepare(csi2->pllref_clk);
 
 struct imx7_csi {
        struct device *dev;
        struct v4l2_subdev sd;
+       struct v4l2_async_notifier notifier;
        struct imx_media_video_dev *vdev;
        struct imx_media_dev *imxmd;
        struct media_pad pad[IMX7_CSI_PADS_NUM];
        .unregistered   = imx7_csi_unregistered,
 };
 
-static int imx7_csi_parse_endpoint(struct device *dev,
-                                  struct v4l2_fwnode_endpoint *vep,
-                                  struct v4l2_async_subdev *asd)
+static int imx7_csi_async_register(struct imx7_csi *csi)
 {
-       return fwnode_device_is_available(asd->match.fwnode) ? 0 : -EINVAL;
+       struct v4l2_async_subdev *asd = NULL;
+       struct fwnode_handle *ep;
+       int ret;
+
+       v4l2_async_notifier_init(&csi->notifier);
+
+       ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
+                                            FWNODE_GRAPH_ENDPOINT_NEXT);
+       if (ep) {
+               asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+               if (!asd) {
+                       fwnode_handle_put(ep);
+                       return -ENOMEM;
+               }
+
+               ret = v4l2_async_notifier_add_fwnode_remote_subdev(
+                       &csi->notifier, ep, asd);
+
+               fwnode_handle_put(ep);
+
+               if (ret) {
+                       kfree(asd);
+                       /* OK if asd already exists */
+                       if (ret != -EEXIST)
+                               return ret;
+               }
+       }
+
+       ret = v4l2_async_subdev_notifier_register(&csi->sd, &csi->notifier);
+       if (ret)
+               return ret;
+
+       return v4l2_async_register_subdev(&csi->sd);
 }
 
 static int imx7_csi_probe(struct platform_device *pdev)
        if (ret < 0)
                goto free;
 
-       ret = v4l2_async_register_fwnode_subdev(&csi->sd,
-                                               sizeof(struct v4l2_async_subdev),
-                                               NULL, 0,
-                                               imx7_csi_parse_endpoint);
+       ret = imx7_csi_async_register(csi);
        if (ret)
-               goto free;
+               goto subdev_notifier_cleanup;
 
        return 0;
 
+subdev_notifier_cleanup:
+       v4l2_async_notifier_unregister(&csi->notifier);
+       v4l2_async_notifier_cleanup(&csi->notifier);
+
 free:
        v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
 
 cleanup:
+       v4l2_async_notifier_unregister(&imxmd->notifier);
        v4l2_async_notifier_cleanup(&imxmd->notifier);
        v4l2_device_unregister(&imxmd->v4l2_dev);
        media_device_unregister(&imxmd->md);
        v4l2_device_unregister(&imxmd->v4l2_dev);
        media_device_cleanup(&imxmd->md);
 
+       v4l2_async_notifier_unregister(&csi->notifier);
+       v4l2_async_notifier_cleanup(&csi->notifier);
        v4l2_async_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
 
 
        struct device *dev;
        struct media_pad pads[CSIS_PADS_NUM];
        struct v4l2_subdev mipi_sd;
+       struct v4l2_async_notifier notifier;
        struct v4l2_subdev *src_sd;
 
        u8 index;
 
 static int mipi_csis_pm_resume(struct device *dev, bool runtime);
 
-static int mipi_csis_parse_endpoint(struct device *dev,
-                                   struct v4l2_fwnode_endpoint *ep,
-                                   struct v4l2_async_subdev *asd)
-{
-       struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
-       struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
-
-       if (ep->bus_type != V4L2_MBUS_CSI2_DPHY) {
-               dev_err(dev, "invalid bus type, must be MIPI CSI2\n");
-               return -EINVAL;
-       }
-
-       state->bus = ep->bus.mipi_csi2;
-
-       dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes);
-       dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags);
-
-       return 0;
-}
-
 static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
                                 struct platform_device *pdev,
                                 const struct v4l2_subdev_ops *ops)
 {
        struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
-       unsigned int sink_port = 0;
-       int ret;
 
        v4l2_subdev_init(mipi_sd, ops);
        mipi_sd->owner = THIS_MODULE;
 
        state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
        state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
-       ret = media_entity_pads_init(&mipi_sd->entity, CSIS_PADS_NUM,
-                                    state->pads);
+       return media_entity_pads_init(&mipi_sd->entity, CSIS_PADS_NUM,
+                                     state->pads);
+}
+
+static int mipi_csis_async_register(struct csi_state *state)
+{
+       struct v4l2_fwnode_endpoint vep = {
+               .bus_type = V4L2_MBUS_CSI2_DPHY,
+       };
+       struct v4l2_async_subdev *asd = NULL;
+       struct fwnode_handle *ep;
+       int ret;
+
+       v4l2_async_notifier_init(&state->notifier);
+
+       ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0,
+                                            FWNODE_GRAPH_ENDPOINT_NEXT);
+       if (!ep)
+               return -ENOTCONN;
+
+       ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+       if (ret)
+               goto err_parse;
+
+       state->bus = vep.bus.mipi_csi2;
+
+       dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes);
+       dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags);
+
+       asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+       if (!asd) {
+               ret = -ENOMEM;
+               goto err_parse;
+       }
+
+       ret = v4l2_async_notifier_add_fwnode_remote_subdev(
+               &state->notifier, ep, asd);
+       if (ret)
+               goto err_parse;
+
+       fwnode_handle_put(ep);
+
+       ret = v4l2_async_subdev_notifier_register(&state->mipi_sd,
+                                                 &state->notifier);
        if (ret)
                return ret;
 
-       ret = v4l2_async_register_fwnode_subdev(mipi_sd,
-                                               sizeof(struct v4l2_async_subdev),
-                                               &sink_port, 1,
-                                               mipi_csis_parse_endpoint);
-       if (ret < 0)
-               dev_err(&pdev->dev, "async fwnode register failed: %d\n", ret);
+       return v4l2_async_register_subdev(&state->mipi_sd);
+
+err_parse:
+       fwnode_handle_put(ep);
+       kfree(asd);
 
        return ret;
 }
        if (ret < 0)
                goto disable_clock;
 
+       ret = mipi_csis_async_register(state);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "async register failed: %d\n", ret);
+               goto cleanup;
+       }
+
        memcpy(state->events, mipi_csis_events, sizeof(state->events));
 
        mipi_csis_debugfs_init(state);
 
 unregister_all:
        mipi_csis_debugfs_exit(state);
+cleanup:
        media_entity_cleanup(&state->mipi_sd.entity);
+       v4l2_async_notifier_unregister(&state->notifier);
+       v4l2_async_notifier_cleanup(&state->notifier);
        v4l2_async_unregister_subdev(&state->mipi_sd);
 disable_clock:
        mipi_csis_clk_disable(state);
        struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
 
        mipi_csis_debugfs_exit(state);
+       v4l2_async_notifier_unregister(&state->notifier);
+       v4l2_async_notifier_cleanup(&state->notifier);
        v4l2_async_unregister_subdev(&state->mipi_sd);
 
        pm_runtime_disable(&pdev->dev);