struct v4l2_fwnode_endpoint vep = {
                        .bus_type = V4L2_MBUS_CSI2_DPHY
                };
-               struct sensor_async_subdev *s_asd = NULL;
+               struct sensor_async_subdev *s_asd;
+               struct v4l2_async_subdev *asd;
                struct fwnode_handle *ep;
 
                ep = fwnode_graph_get_endpoint_by_id(
                if (ret)
                        goto err_parse;
 
-               s_asd = kzalloc(sizeof(*s_asd), GFP_KERNEL);
-               if (!s_asd) {
-                       ret = -ENOMEM;
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                               &cio2->notifier, ep, sizeof(*s_asd));
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        goto err_parse;
                }
 
+               s_asd = container_of(asd, struct sensor_async_subdev, asd);
                s_asd->csi2.port = vep.base.port;
                s_asd->csi2.lanes = vep.bus.mipi_csi2.num_data_lanes;
 
-               ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                       &cio2->notifier, ep, &s_asd->asd);
-               if (ret)
-                       goto err_parse;
-
                fwnode_handle_put(ep);
 
                continue;
 
 err_parse:
                fwnode_handle_put(ep);
-               kfree(s_asd);
                return ret;
        }
 
 
        buscfg->bus.ccp2.crc = 1;
 }
 
-static int isp_alloc_isd(struct isp_async_subdev **isd,
-                        struct isp_bus_cfg **buscfg)
-{
-       struct isp_async_subdev *__isd;
-
-       __isd = kzalloc(sizeof(*__isd), GFP_KERNEL);
-       if (!__isd)
-               return -ENOMEM;
-
-       *isd = __isd;
-       *buscfg = &__isd->bus;
-
-       return 0;
-}
-
 static struct {
        u32 phy;
        u32 csi2_if;
 {
        struct fwnode_handle *ep;
        struct isp_async_subdev *isd = NULL;
-       struct isp_bus_cfg *buscfg;
+       struct v4l2_async_subdev *asd;
        unsigned int i;
 
        ep = fwnode_graph_get_endpoint_by_id(
                ret = v4l2_fwnode_endpoint_parse(ep, &vep);
 
                if (!ret) {
-                       ret = isp_alloc_isd(&isd, &buscfg);
-                       if (ret)
-                               return ret;
-               }
-
-               if (!ret) {
-                       isp_parse_of_parallel_endpoint(isp->dev, &vep, buscfg);
-                       ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                               &isp->notifier, ep, &isd->asd);
+                       asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                               &isp->notifier, ep, sizeof(*isd));
+                       if (!IS_ERR(asd)) {
+                               isd = container_of(asd, struct isp_async_subdev, asd);
+                               isp_parse_of_parallel_endpoint(isp->dev, &vep, &isd->bus);
+                       }
                }
 
                fwnode_handle_put(ep);
-               if (ret)
-                       kfree(isd);
        }
 
        for (i = 0; i < ARRAY_SIZE(isp_bus_interfaces); i++) {
                dev_dbg(isp->dev, "parsing serial interface %u, node %pOF\n", i,
                        to_of_node(ep));
 
-               ret = isp_alloc_isd(&isd, &buscfg);
-               if (ret)
-                       return ret;
-
                ret = v4l2_fwnode_endpoint_parse(ep, &vep);
-               if (!ret) {
-                       buscfg->interface = isp_bus_interfaces[i].csi2_if;
-                       isp_parse_of_csi2_endpoint(isp->dev, &vep, buscfg);
-               } else if (ret == -ENXIO) {
+               if (ret == -ENXIO) {
                        vep = (struct v4l2_fwnode_endpoint)
                                { .bus_type = V4L2_MBUS_CSI1 };
                        ret = v4l2_fwnode_endpoint_parse(ep, &vep);
                                        { .bus_type = V4L2_MBUS_CCP2 };
                                ret = v4l2_fwnode_endpoint_parse(ep, &vep);
                        }
-                       if (!ret) {
-                               buscfg->interface =
-                                       isp_bus_interfaces[i].csi1_if;
-                               isp_parse_of_csi1_endpoint(isp->dev, &vep,
-                                                          buscfg);
-                       }
                }
 
-               if (!ret)
-                       ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                               &isp->notifier, ep, &isd->asd);
+               if (!ret) {
+                       asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                               &isp->notifier, ep, sizeof(*isd));
+
+                       if (!IS_ERR(asd)) {
+                               isd = container_of(asd, struct isp_async_subdev, asd);
+
+                               switch (vep.bus_type) {
+                               case V4L2_MBUS_CSI2_DPHY:
+                                       isd->bus.interface =
+                                               isp_bus_interfaces[i].csi2_if;
+                                       isp_parse_of_csi2_endpoint(isp->dev, &vep, &isd->bus);
+                                       break;
+                               case V4L2_MBUS_CSI1:
+                               case V4L2_MBUS_CCP2:
+                                       isd->bus.interface =
+                                               isp_bus_interfaces[i].csi1_if;
+                                       isp_parse_of_csi1_endpoint(isp->dev, &vep,
+                                                                  &isd->bus);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               }
 
                fwnode_handle_put(ep);
-               if (ret)
-                       kfree(isd);
        }
 
        return 0;
 
                        .bus_type = V4L2_MBUS_CSI2_DPHY
                };
                struct rkisp1_sensor_async *rk_asd = NULL;
+               struct v4l2_async_subdev *asd;
                struct fwnode_handle *ep;
 
                ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev),
                if (ret)
                        goto err_parse;
 
-               rk_asd = kzalloc(sizeof(*rk_asd), GFP_KERNEL);
-               if (!rk_asd) {
-                       ret = -ENOMEM;
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(ntf, ep,
+                                                       sizeof(*rk_asd));
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        goto err_parse;
                }
 
+               rk_asd = container_of(asd, struct rkisp1_sensor_async, asd);
                rk_asd->mbus_type = vep.bus_type;
                rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
                rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
 
-               ret = v4l2_async_notifier_add_fwnode_remote_subdev(ntf, ep,
-                                                                  &rk_asd->asd);
-               if (ret)
-                       goto err_parse;
-
                dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n",
                        vep.base.id, rk_asd->lanes);
 
                continue;
 err_parse:
                fwnode_handle_put(ep);
-               kfree(rk_asd);
                v4l2_async_notifier_cleanup(ntf);
                return ret;
        }
 
        struct v4l2_fwnode_endpoint vep = {
                .bus_type = V4L2_MBUS_PARALLEL,
        };
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *ep;
        int ret;
 
 
        csi->bus = vep.bus.parallel;
 
-       ret = v4l2_async_notifier_add_fwnode_remote_subdev(&csi->notifier,
-                                                          ep, &csi->asd);
-       if (ret)
+       asd = v4l2_async_notifier_add_fwnode_remote_subdev(&csi->notifier,
+                                                          ep, sizeof(*asd));
+       if (IS_ERR(asd)) {
+               ret = PTR_ERR(asd);
                goto out;
+       }
 
        csi->notifier.ops = &sun4i_csi_notify_ops;
 
 
        struct v4l2_mbus_framefmt       subdev_fmt;
 
        /* V4L2 Async variables */
-       struct v4l2_async_subdev        asd;
        struct v4l2_async_notifier      notifier;
        struct v4l2_subdev              *src_subdev;
        int                             src_pad;
 
                if (!ep)
                        continue;
 
-               asd = kzalloc(sizeof(*asd), GFP_KERNEL);
-               if (!asd) {
-                       fwnode_handle_put(ep);
-                       return -ENOMEM;
-               }
-
-               ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-                       &vmux->notifier, ep, asd);
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                       &vmux->notifier, ep, sizeof(*asd));
 
                fwnode_handle_put(ep);
 
-               if (ret) {
-                       kfree(asd);
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        /* OK if asd already exists */
                        if (ret != -EEXIST)
                                return ret;
 
 }
 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_subdev);
 
-int
+struct v4l2_async_subdev *
 v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif,
                                             struct fwnode_handle *endpoint,
-                                            struct v4l2_async_subdev *asd)
+                                            unsigned int asd_struct_size)
 {
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *remote;
-       int ret;
 
        remote = fwnode_graph_get_remote_port_parent(endpoint);
        if (!remote)
-               return -ENOTCONN;
+               return ERR_PTR(-ENOTCONN);
 
-       asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
-       asd->match.fwnode = remote;
-
-       ret = v4l2_async_notifier_add_subdev(notif, asd);
-       if (ret)
-               fwnode_handle_put(remote);
-
-       return ret;
+       asd = v4l2_async_notifier_add_fwnode_subdev(notif, remote,
+                                                   asd_struct_size);
+       /*
+        * Calling v4l2_async_notifier_add_fwnode_subdev grabs a refcount,
+        * so drop the one we got in fwnode_graph_get_remote_port_parent.
+        */
+       fwnode_handle_put(remote);
+       return asd;
 }
 EXPORT_SYMBOL_GPL(v4l2_async_notifier_add_fwnode_remote_subdev);
 
 
                                             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_notifier_add_fwnode_remote_subdev(
-                       &priv->notifier, ep, asd);
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                       &priv->notifier, ep, sizeof(*asd));
 
                fwnode_handle_put(ep);
 
-               if (ret) {
-                       kfree(asd);
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        /* OK if asd already exists */
                        if (ret != -EEXIST)
                                return ret;
 
        struct v4l2_fwnode_endpoint vep = {
                .bus_type = V4L2_MBUS_CSI2_DPHY,
        };
-       struct v4l2_async_subdev *asd = NULL;
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *ep;
        int ret;
 
        dev_dbg(csi2->dev, "data lanes: %d\n", vep.bus.mipi_csi2.num_data_lanes);
        dev_dbg(csi2->dev, "flags: 0x%08x\n", vep.bus.mipi_csi2.flags);
 
-       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;
-
+       asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+               &csi2->notifier, ep, sizeof(*asd));
        fwnode_handle_put(ep);
 
+       if (IS_ERR(asd))
+               return PTR_ERR(asd);
+
        csi2->notifier.ops = &csi2_notify_ops;
 
        ret = v4l2_async_subdev_notifier_register(&csi2->sd,
 
 err_parse:
        fwnode_handle_put(ep);
-       kfree(asd);
        return ret;
 }
 
 
 
 static int imx7_csi_async_register(struct imx7_csi *csi)
 {
-       struct v4l2_async_subdev *asd = NULL;
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *ep;
        int ret;
 
        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);
+               asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+                       &csi->notifier, ep, sizeof(*asd));
 
                fwnode_handle_put(ep);
 
-               if (ret) {
-                       kfree(asd);
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
                        /* OK if asd already exists */
                        if (ret != -EEXIST)
                                return ret;
 
        struct v4l2_fwnode_endpoint vep = {
                .bus_type = V4L2_MBUS_CSI2_DPHY,
        };
-       struct v4l2_async_subdev *asd = NULL;
+       struct v4l2_async_subdev *asd;
        struct fwnode_handle *ep;
        int ret;
 
        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;
+       asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+               &state->notifier, ep, sizeof(*asd));
+       if (IS_ERR(asd)) {
+               ret = PTR_ERR(asd);
                goto err_parse;
        }
 
-       ret = v4l2_async_notifier_add_fwnode_remote_subdev(
-               &state->notifier, ep, asd);
-       if (ret)
-               goto err_parse;
-
        fwnode_handle_put(ep);
 
        state->notifier.ops = &mipi_csis_notify_ops;
 
 err_parse:
        fwnode_handle_put(ep);
-       kfree(asd);
 
        return ret;
 }
 
  *
  * @notif: pointer to &struct v4l2_async_notifier
  * @endpoint: local endpoint pointing to the remote sub-device to be matched
- * @asd: Async sub-device struct allocated by the caller. The &struct
- *      v4l2_async_subdev shall be the first member of the driver's async
- *      sub-device struct, i.e. both begin at the same memory address.
+ * @asd_struct_size: size of the driver's async sub-device struct, including
+ *                  sizeof(struct v4l2_async_subdev). The &struct
+ *                  v4l2_async_subdev shall be the first member of
+ *                  the driver's async sub-device struct, i.e. both
+ *                  begin at the same memory address.
  *
  * Gets the remote endpoint of a given local endpoint, set it up for fwnode
  * matching and adds the async sub-device to the notifier's @asd_list. The
  * notifier cleanup time.
  *
  * This is just like @v4l2_async_notifier_add_fwnode_subdev, but with the
- * exception that the fwnode refers to a local endpoint, not the remote one, and
- * the function relies on the caller to allocate the async sub-device struct.
+ * exception that the fwnode refers to a local endpoint, not the remote one.
  */
-int
+struct v4l2_async_subdev *
 v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif,
                                             struct fwnode_handle *endpoint,
-                                            struct v4l2_async_subdev *asd);
+                                            unsigned int asd_struct_size);
 
 /**
  * v4l2_async_notifier_add_i2c_subdev - Allocate and add an i2c async