media: imx: Don't register IPU subdevs/links if CSI port missing
authorSteve Longerbeam <slongerbeam@gmail.com>
Wed, 20 Feb 2019 23:53:32 +0000 (18:53 -0500)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Tue, 19 Mar 2019 17:42:52 +0000 (13:42 -0400)
The second IPU internal sub-devices were being registered and links
to them created even when the second IPU is not present. This is wrong
for i.MX6 S/DL and i.MX53 which have only a single IPU.

Fixes: e130291212df5 ("[media] media: Add i.MX media core driver")
Signed-off-by: Steve Longerbeam <slongerbeam@gmail.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Cc: stable@vger.kernel.org
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/staging/media/imx/imx-media-dev.c
drivers/staging/media/imx/imx-media-internal-sd.c
drivers/staging/media/imx/imx-media-of.c
drivers/staging/media/imx/imx-media.h
drivers/staging/media/imx/imx7-media-csi.c

index fc35508d939683d4ffe65737d955330be136e4d9..10a63a4fa90b5c5a9b752302926ba3153221417b 100644 (file)
@@ -477,13 +477,6 @@ static int imx_media_probe(struct platform_device *pdev)
                goto cleanup;
        }
 
-       ret = imx_media_add_ipu_internal_subdevs(imxmd);
-       if (ret) {
-               v4l2_err(&imxmd->v4l2_dev,
-                        "add_ipu_internal_subdevs failed with %d\n", ret);
-               goto cleanup;
-       }
-
        ret = imx_media_dev_notifier_register(imxmd);
        if (ret)
                goto del_int;
index e620f4adb7559733d8442c1d6129f0ee8d1fa782..dc510dcfe16091574c882390f885c16ad602510a 100644 (file)
@@ -298,13 +298,14 @@ static int add_internal_subdev(struct imx_media_dev *imxmd,
 }
 
 /* adds the internal subdevs in one ipu */
-static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id)
+int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd,
+                                      int ipu_id)
 {
        enum isd_enum i;
+       int ret;
 
        for (i = 0; i < num_isd; i++) {
                const struct internal_subdev *isd = &int_subdev[i];
-               int ret;
 
                /*
                 * the CSIs are represented in the device-tree, so those
@@ -322,25 +323,10 @@ static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id)
                }
 
                if (ret)
-                       return ret;
+                       goto remove;
        }
 
        return 0;
-}
-
-int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd)
-{
-       int ret;
-
-       ret = add_ipu_internal_subdevs(imxmd, 0);
-       if (ret)
-               goto remove;
-
-       ret = add_ipu_internal_subdevs(imxmd, 1);
-       if (ret)
-               goto remove;
-
-       return 0;
 
 remove:
        imx_media_remove_ipu_internal_subdevs(imxmd);
index a26bdeb1af34d28fa03f9f3f42c2aaf18521f8f1..12383f4785ad8f0aed4df741cd5ff12cd0a312bf 100644 (file)
 int imx_media_of_add_csi(struct imx_media_dev *imxmd,
                         struct device_node *csi_np)
 {
-       int ret;
-
        if (!of_device_is_available(csi_np)) {
                dev_dbg(imxmd->md.dev, "%s: %pOFn not enabled\n", __func__,
                        csi_np);
-               /* unavailable is not an error */
-               return 0;
+               return -ENODEV;
        }
 
        /* add CSI fwnode to async notifier */
-       ret = imx_media_add_async_subdev(imxmd, of_fwnode_handle(csi_np), NULL);
-       if (ret) {
-               if (ret == -EEXIST) {
-                       /* already added, everything is fine */
-                       return 0;
-               }
-
-               /* other error, can't continue */
-               return ret;
-       }
-
-       return 0;
+       return imx_media_add_async_subdev(imxmd, of_fwnode_handle(csi_np),
+                                         NULL);
 }
 EXPORT_SYMBOL_GPL(imx_media_of_add_csi);
 
 int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
                             struct device_node *np)
 {
+       bool ipu_found[2] = {false, false};
        struct device_node *csi_np;
        int i, ret;
+       u32 ipu_id;
 
        for (i = 0; ; i++) {
                csi_np = of_parse_phandle(np, "ports", i);
@@ -60,12 +49,43 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
                        break;
 
                ret = imx_media_of_add_csi(imxmd, csi_np);
-               of_node_put(csi_np);
-               if (ret)
-                       return ret;
+               if (ret) {
+                       /* unavailable or already added is not an error */
+                       if (ret == -ENODEV || ret == -EEXIST) {
+                               of_node_put(csi_np);
+                               continue;
+                       }
+
+                       /* other error, can't continue */
+                       goto err_out;
+               }
+
+               ret = of_alias_get_id(csi_np->parent, "ipu");
+               if (ret < 0)
+                       goto err_out;
+               if (ret > 1) {
+                       ret = -EINVAL;
+                       goto err_out;
+               }
+
+               ipu_id = ret;
+
+               if (!ipu_found[ipu_id]) {
+                       ret = imx_media_add_ipu_internal_subdevs(imxmd,
+                                                                ipu_id);
+                       if (ret)
+                               goto err_out;
+               }
+
+               ipu_found[ipu_id] = true;
        }
 
        return 0;
+
+err_out:
+       imx_media_remove_ipu_internal_subdevs(imxmd);
+       of_node_put(csi_np);
+       return ret;
 }
 
 /*
index ccbfc4438c856e2a8f05f7a4f7f5abe9fbe1d423..dd603a6b3a7027ec2a3f8d5c1d40512dfc6dbbc5 100644 (file)
@@ -252,7 +252,8 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd);
 void imx_media_fim_free(struct imx_media_fim *fim);
 
 /* imx-media-internal-sd.c */
-int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd);
+int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd,
+                                      int ipu_id);
 int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd,
                                        struct v4l2_subdev *sd);
 void imx_media_remove_ipu_internal_subdevs(struct imx_media_dev *imxmd);
index 3fba7c27c0ecdf38db73dbbeb6e36c05f51ed285..1ba62fcdcae8d6d38add9e49a85ef1b152f2caf7 100644 (file)
@@ -1271,7 +1271,7 @@ static int imx7_csi_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, &csi->sd);
 
        ret = imx_media_of_add_csi(imxmd, node);
-       if (ret < 0)
+       if (ret < 0 && ret != -ENODEV && ret != -EEXIST)
                goto cleanup;
 
        ret = imx_media_dev_notifier_register(imxmd);