struct cio2_device *cio2 = container_of(notifier, struct cio2_device,
                                                notifier);
        struct sensor_async_subdev *s_asd;
+       struct v4l2_async_subdev *asd;
        struct cio2_queue *q;
-       unsigned int i, pad;
+       unsigned int pad;
        int ret;
 
-       for (i = 0; i < notifier->num_subdevs; i++) {
-               s_asd = container_of(cio2->notifier.subdevs[i],
-                                    struct sensor_async_subdev, asd);
+       list_for_each_entry(asd, &cio2->notifier.asd_list, asd_list) {
+               s_asd = container_of(asd, struct sensor_async_subdev, asd);
                q = &cio2->queue[s_asd->csi2.port];
 
                for (pad = 0; pad < q->sensor->entity.num_pads; pad++)
                if (ret) {
                        dev_err(&cio2->pci_dev->dev,
                                "failed to create link for %s\n",
-                               cio2->queue[i].sensor->name);
+                               q->sensor->name);
                        return ret;
                }
        }
 {
        int ret;
 
+       v4l2_async_notifier_init(&cio2->notifier);
+
        ret = v4l2_async_notifier_parse_fwnode_endpoints(
                &cio2->pci_dev->dev, &cio2->notifier,
                sizeof(struct sensor_async_subdev),
 
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
 
-static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
-                                      unsigned int max_subdevs)
-{
-       struct v4l2_async_subdev **subdevs;
-
-       if (max_subdevs <= notifier->max_subdevs)
-               return 0;
-
-       subdevs = kvmalloc_array(
-               max_subdevs, sizeof(*notifier->subdevs),
-               GFP_KERNEL | __GFP_ZERO);
-       if (!subdevs)
-               return -ENOMEM;
-
-       if (notifier->subdevs) {
-               memcpy(subdevs, notifier->subdevs,
-                      sizeof(*subdevs) * notifier->num_subdevs);
-
-               kvfree(notifier->subdevs);
-       }
-
-       notifier->subdevs = subdevs;
-       notifier->max_subdevs = max_subdevs;
-
-       return 0;
-}
-
 static int v4l2_async_notifier_fwnode_parse_endpoint(
        struct device *dev, struct v4l2_async_notifier *notifier,
        struct fwnode_handle *endpoint, unsigned int asd_struct_size,
        if (ret < 0)
                goto out_err;
 
-       notifier->subdevs[notifier->num_subdevs] = asd;
-       notifier->num_subdevs++;
+       ret = v4l2_async_notifier_add_subdev(notifier, asd);
+       if (ret < 0) {
+               /* not an error if asd already exists */
+               if (ret == -EEXIST)
+                       ret = 0;
+               goto out_err;
+       }
 
        return 0;
 
                            struct v4l2_async_subdev *asd))
 {
        struct fwnode_handle *fwnode;
-       unsigned int max_subdevs = notifier->max_subdevs;
-       int ret;
+       int ret = 0;
 
        if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
                return -EINVAL;
 
-       for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
-                                    dev_fwnode(dev), fwnode)); ) {
-               struct fwnode_handle *dev_fwnode;
-               bool is_available;
-
-               dev_fwnode = fwnode_graph_get_port_parent(fwnode);
-               is_available = fwnode_device_is_available(dev_fwnode);
-               fwnode_handle_put(dev_fwnode);
-               if (!is_available)
-                       continue;
-
-               if (has_port) {
-                       struct fwnode_endpoint ep;
-
-                       ret = fwnode_graph_parse_endpoint(fwnode, &ep);
-                       if (ret) {
-                               fwnode_handle_put(fwnode);
-                               return ret;
-                       }
-
-                       if (ep.port != port)
-                               continue;
-               }
-               max_subdevs++;
-       }
-
-       /* No subdevs to add? Return here. */
-       if (max_subdevs == notifier->max_subdevs)
-               return 0;
-
-       ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
-       if (ret)
-               return ret;
-
        for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
                                     dev_fwnode(dev), fwnode)); ) {
                struct fwnode_handle *dev_fwnode;
                                continue;
                }
 
-               if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
-                       ret = -EINVAL;
-                       break;
-               }
-
                ret = v4l2_async_notifier_fwnode_parse_endpoint(
                        dev, notifier, fwnode, asd_struct_size, parse_endpoint);
                if (ret < 0)
        if (ret != -ENOENT && ret != -ENODATA)
                return ret;
 
-       ret = v4l2_async_notifier_realloc(notifier,
-                                         notifier->num_subdevs + index);
-       if (ret)
-               return ret;
-
        for (index = 0; !fwnode_property_get_reference_args(
                     dev_fwnode(dev), prop, NULL, 0, index, &args);
             index++) {
                struct v4l2_async_subdev *asd;
 
-               if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
-                       ret = -EINVAL;
-                       goto error;
-               }
+               asd = v4l2_async_notifier_add_fwnode_subdev(
+                       notifier, args.fwnode, sizeof(*asd));
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
+                       /* not an error if asd already exists */
+                       if (ret == -EEXIST) {
+                               fwnode_handle_put(args.fwnode);
+                               continue;
+                       }
 
-               asd = kzalloc(sizeof(*asd), GFP_KERNEL);
-               if (!asd) {
-                       ret = -ENOMEM;
                        goto error;
                }
-
-               notifier->subdevs[notifier->num_subdevs] = asd;
-               asd->match.fwnode = args.fwnode;
-               asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
-               notifier->num_subdevs++;
        }
 
        return 0;
                index++;
        } while (1);
 
-       ret = v4l2_async_notifier_realloc(notifier,
-                                         notifier->num_subdevs + index);
-       if (ret)
-               return -ENOMEM;
-
        for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
                                         dev_fwnode(dev), prop, index, props,
                                         nprops))); index++) {
                struct v4l2_async_subdev *asd;
 
-               if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
-                       ret = -EINVAL;
-                       goto error;
-               }
+               asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
+                                                           sizeof(*asd));
+               if (IS_ERR(asd)) {
+                       ret = PTR_ERR(asd);
+                       /* not an error if asd already exists */
+                       if (ret == -EEXIST) {
+                               fwnode_handle_put(fwnode);
+                               continue;
+                       }
 
-               asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
-               if (!asd) {
-                       ret = -ENOMEM;
                        goto error;
                }
-
-               notifier->subdevs[notifier->num_subdevs] = asd;
-               asd->match.fwnode = fwnode;
-               asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
-               notifier->num_subdevs++;
        }
 
        return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
        if (!notifier)
                return -ENOMEM;
 
+       v4l2_async_notifier_init(notifier);
+
        ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
                                                             notifier);
        if (ret < 0)
 
  *                 endpoint. Optional.
  *
  * Parse the fwnode endpoints of the @dev device and populate the async sub-
- * devices array of the notifier. The @parse_endpoint callback function is
+ * devices list in the notifier. The @parse_endpoint callback function is
  * called for each endpoint with the corresponding async sub-device pointer to
  * let the caller initialize the driver-specific part of the async sub-device
  * structure.
  * This function may not be called on a registered notifier and may be called on
  * a notifier only once.
  *
- * Do not change the notifier's subdevs array, take references to the subdevs
- * array itself or change the notifier's num_subdevs field. This is because this
- * function allocates and reallocates the subdevs array based on parsing
- * endpoints.
+ * Do not allocate the notifier's subdevs array, or change the notifier's
+ * num_subdevs field. This is because this function uses
+ * @v4l2_async_notifier_add_subdev to populate the notifier's asd_list,
+ * which is in-place-of the subdevs array which must remain unallocated
+ * and unused.
  *
  * The &struct v4l2_fwnode_endpoint passed to the callback function
  * @parse_endpoint is released once the function is finished. If there is a need
  * devices). In this case the driver must know which ports to parse.
  *
  * Parse the fwnode endpoints of the @dev device on a given @port and populate
- * the async sub-devices array of the notifier. The @parse_endpoint callback
+ * the async sub-devices list of the notifier. The @parse_endpoint callback
  * function is called for each endpoint with the corresponding async sub-device
  * pointer to let the caller initialize the driver-specific part of the async
  * sub-device structure.
  * This function may not be called on a registered notifier and may be called on
  * a notifier only once per port.
  *
- * Do not change the notifier's subdevs array, take references to the subdevs
- * array itself or change the notifier's num_subdevs field. This is because this
- * function allocates and reallocates the subdevs array based on parsing
- * endpoints.
+ * Do not allocate the notifier's subdevs array, or change the notifier's
+ * num_subdevs field. This is because this function uses
+ * @v4l2_async_notifier_add_subdev to populate the notifier's asd_list,
+ * which is in-place-of the subdevs array which must remain unallocated
+ * and unused.
  *
  * The &struct v4l2_fwnode_endpoint passed to the callback function
  * @parse_endpoint is released once the function is finished. If there is a need