Merge tag 'media/v4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[sfrench/cifs-2.6.git] / drivers / staging / media / imx / imx-media-dev.c
index b0be80f05767869b9947a64dabd657ea18a129c4..026b9cbe581d49e7bcef260ae875eb63f5eb2915 100644 (file)
 
 static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
 {
-       return container_of(n, struct imx_media_dev, subdev_notifier);
+       return container_of(n, struct imx_media_dev, notifier);
 }
 
 /*
- * Find an asd by fwnode or device name. This is called during
- * driver load to form the async subdev list and bind them.
- */
-static struct v4l2_async_subdev *
-find_async_subdev(struct imx_media_dev *imxmd,
-                 struct fwnode_handle *fwnode,
-                 const char *devname)
-{
-       struct imx_media_async_subdev *imxasd;
-       struct v4l2_async_subdev *asd;
-
-       list_for_each_entry(imxasd, &imxmd->asd_list, list) {
-               asd = &imxasd->asd;
-               switch (asd->match_type) {
-               case V4L2_ASYNC_MATCH_FWNODE:
-                       if (fwnode && asd->match.fwnode == fwnode)
-                               return asd;
-                       break;
-               case V4L2_ASYNC_MATCH_DEVNAME:
-                       if (devname && !strcmp(asd->match.device_name,
-                                              devname))
-                               return asd;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       return NULL;
-}
-
-
-/*
- * Adds a subdev to the async subdev list. If fwnode is non-NULL, adds
- * the async as a V4L2_ASYNC_MATCH_FWNODE match type, otherwise as
- * a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name of the
- * given platform_device. This is called during driver load when
+ * Adds a subdev to the root notifier's async subdev list. If fwnode is
+ * non-NULL, adds the async as a V4L2_ASYNC_MATCH_FWNODE match type,
+ * otherwise as a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name
+ * of the given platform_device. This is called during driver load when
  * forming the async subdev list.
  */
 int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
@@ -80,47 +47,43 @@ int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
        struct imx_media_async_subdev *imxasd;
        struct v4l2_async_subdev *asd;
        const char *devname = NULL;
-       int ret = 0;
-
-       mutex_lock(&imxmd->mutex);
+       int ret;
 
-       if (pdev)
+       if (fwnode) {
+               asd = v4l2_async_notifier_add_fwnode_subdev(
+                       &imxmd->notifier, fwnode, sizeof(*imxasd));
+       } else {
                devname = dev_name(&pdev->dev);
-
-       /* return -EEXIST if this asd already added */
-       if (find_async_subdev(imxmd, fwnode, devname)) {
-               dev_dbg(imxmd->md.dev, "%s: already added %s\n",
-                       __func__, np ? np->name : devname);
-               ret = -EEXIST;
-               goto out;
+               asd = v4l2_async_notifier_add_devname_subdev(
+                       &imxmd->notifier, devname, sizeof(*imxasd));
        }
 
-       imxasd = devm_kzalloc(imxmd->md.dev, sizeof(*imxasd), GFP_KERNEL);
-       if (!imxasd) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       asd = &imxasd->asd;
-
-       if (fwnode) {
-               asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
-               asd->match.fwnode = fwnode;
-       } else {
-               asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
-               asd->match.device_name = devname;
-               imxasd->pdev = pdev;
+       if (IS_ERR(asd)) {
+               ret = PTR_ERR(asd);
+               if (ret == -EEXIST) {
+                       if (np)
+                               dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n",
+                                       __func__, np);
+                       else
+                               dev_dbg(imxmd->md.dev, "%s: already added %s\n",
+                                       __func__, devname);
+               }
+               return ret;
        }
 
-       list_add_tail(&imxasd->list, &imxmd->asd_list);
+       imxasd = to_imx_media_asd(asd);
 
-       imxmd->subdev_notifier.num_subdevs++;
+       if (devname)
+               imxasd->pdev = pdev;
 
-       dev_dbg(imxmd->md.dev, "%s: added %s, match type %s\n",
-               __func__, np ? np->name : devname, np ? "FWNODE" : "DEVNAME");
+       if (np)
+               dev_dbg(imxmd->md.dev, "%s: added %pOFn, match type FWNODE\n",
+                       __func__, np);
+       else
+               dev_dbg(imxmd->md.dev, "%s: added %s, match type DEVNAME\n",
+                       __func__, devname);
 
-out:
-       mutex_unlock(&imxmd->mutex);
-       return ret;
+       return 0;
 }
 
 /*
@@ -175,7 +138,7 @@ out:
 }
 
 /*
- * create the media links for all subdevs that registered async.
+ * Create the media links for all subdevs that registered.
  * Called after all async subdevs have bound.
  */
 static int imx_media_create_links(struct v4l2_async_notifier *notifier)
@@ -184,14 +147,7 @@ static int imx_media_create_links(struct v4l2_async_notifier *notifier)
        struct v4l2_subdev *sd;
        int ret;
 
-       /*
-        * Only links are created between subdevices that are known
-        * to the async notifier. If there are other non-async subdevices,
-        * they were created internally by some subdevice (smiapp is one
-        * example). In those cases it is expected the subdevice is
-        * responsible for creating those internal links.
-        */
-       list_for_each_entry(sd, &notifier->done, async_list) {
+       list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
                switch (sd->grp_id) {
                case IMX_MEDIA_GRP_ID_VDIC:
                case IMX_MEDIA_GRP_ID_IC_PRP:
@@ -211,7 +167,10 @@ static int imx_media_create_links(struct v4l2_async_notifier *notifier)
                                imx_media_create_csi_of_links(imxmd, sd);
                        break;
                default:
-                       /* this is an external fwnode subdev */
+                       /*
+                        * if this subdev has fwnode links, create media
+                        * links for them.
+                        */
                        imx_media_create_of_links(imxmd, sd);
                        break;
                }
@@ -487,10 +446,8 @@ static int imx_media_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *node = dev->of_node;
-       struct imx_media_async_subdev *imxasd;
-       struct v4l2_async_subdev **subdevs;
        struct imx_media_dev *imxmd;
-       int num_subdevs, i, ret;
+       int ret;
 
        imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
        if (!imxmd)
@@ -498,14 +455,14 @@ static int imx_media_probe(struct platform_device *pdev)
 
        dev_set_drvdata(dev, imxmd);
 
-       strlcpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
+       strscpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
        imxmd->md.ops = &imx_media_md_ops;
        imxmd->md.dev = dev;
 
        mutex_init(&imxmd->mutex);
 
        imxmd->v4l2_dev.mdev = &imxmd->md;
-       strlcpy(imxmd->v4l2_dev.name, "imx-media",
+       strscpy(imxmd->v4l2_dev.name, "imx-media",
                sizeof(imxmd->v4l2_dev.name));
 
        media_device_init(&imxmd->md);
@@ -519,47 +476,34 @@ static int imx_media_probe(struct platform_device *pdev)
 
        dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
 
-       INIT_LIST_HEAD(&imxmd->asd_list);
        INIT_LIST_HEAD(&imxmd->vdev_list);
 
+       v4l2_async_notifier_init(&imxmd->notifier);
+
        ret = imx_media_add_of_subdevs(imxmd, node);
        if (ret) {
                v4l2_err(&imxmd->v4l2_dev,
                         "add_of_subdevs failed with %d\n", ret);
-               goto unreg_dev;
+               goto notifier_cleanup;
        }
 
        ret = imx_media_add_internal_subdevs(imxmd);
        if (ret) {
                v4l2_err(&imxmd->v4l2_dev,
                         "add_internal_subdevs failed with %d\n", ret);
-               goto unreg_dev;
+               goto notifier_cleanup;
        }
 
-       num_subdevs = imxmd->subdev_notifier.num_subdevs;
-
        /* no subdevs? just bail */
-       if (num_subdevs == 0) {
+       if (list_empty(&imxmd->notifier.asd_list)) {
                ret = -ENODEV;
-               goto unreg_dev;
+               goto notifier_cleanup;
        }
 
-       subdevs = devm_kcalloc(imxmd->md.dev, num_subdevs, sizeof(*subdevs),
-                              GFP_KERNEL);
-       if (!subdevs) {
-               ret = -ENOMEM;
-               goto unreg_dev;
-       }
-
-       i = 0;
-       list_for_each_entry(imxasd, &imxmd->asd_list, list)
-               subdevs[i++] = &imxasd->asd;
-
        /* prepare the async subdev notifier and register it */
-       imxmd->subdev_notifier.subdevs = subdevs;
-       imxmd->subdev_notifier.ops = &imx_media_subdev_ops;
+       imxmd->notifier.ops = &imx_media_subdev_ops;
        ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
-                                          &imxmd->subdev_notifier);
+                                          &imxmd->notifier);
        if (ret) {
                v4l2_err(&imxmd->v4l2_dev,
                         "v4l2_async_notifier_register failed with %d\n", ret);
@@ -570,7 +514,8 @@ static int imx_media_probe(struct platform_device *pdev)
 
 del_int:
        imx_media_remove_internal_subdevs(imxmd);
-unreg_dev:
+notifier_cleanup:
+       v4l2_async_notifier_cleanup(&imxmd->notifier);
        v4l2_device_unregister(&imxmd->v4l2_dev);
 cleanup:
        media_device_cleanup(&imxmd->md);
@@ -584,8 +529,9 @@ static int imx_media_remove(struct platform_device *pdev)
 
        v4l2_info(&imxmd->v4l2_dev, "Removing imx-media\n");
 
-       v4l2_async_notifier_unregister(&imxmd->subdev_notifier);
+       v4l2_async_notifier_unregister(&imxmd->notifier);
        imx_media_remove_internal_subdevs(imxmd);
+       v4l2_async_notifier_cleanup(&imxmd->notifier);
        v4l2_device_unregister(&imxmd->v4l2_dev);
        media_device_unregister(&imxmd->md);
        media_device_cleanup(&imxmd->md);