Merge tag 'media/v5.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[linux-2.6-microblaze.git] / drivers / staging / media / imx / imx-media-of.c
index 09580d8..990e82a 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);
@@ -56,12 +45,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;
 }
 
 /*
@@ -141,15 +161,18 @@ int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
                                  struct v4l2_subdev *csi)
 {
        struct device_node *csi_np = csi->dev->of_node;
-       struct fwnode_handle *fwnode, *csi_ep;
-       struct v4l2_fwnode_link link;
        struct device_node *ep;
-       int ret;
-
-       link.local_node = of_fwnode_handle(csi_np);
-       link.local_port = CSI_SINK_PAD;
 
        for_each_child_of_node(csi_np, ep) {
+               struct fwnode_handle *fwnode, *csi_ep;
+               struct v4l2_fwnode_link link;
+               int ret;
+
+               memset(&link, 0, sizeof(link));
+
+               link.local_node = of_fwnode_handle(csi_np);
+               link.local_port = CSI_SINK_PAD;
+
                csi_ep = of_fwnode_handle(ep);
 
                fwnode = fwnode_graph_get_remote_endpoint(csi_ep);