diff options
Diffstat (limited to 'drivers/staging/media/imx/imx-media-of.c')
-rw-r--r-- | drivers/staging/media/imx/imx-media-of.c | 73 |
1 files changed, 48 insertions, 25 deletions
diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c index 09580d83c685..990e82aa8e42 100644 --- a/drivers/staging/media/imx/imx-media-of.c +++ b/drivers/staging/media/imx/imx-media-of.c @@ -19,36 +19,25 @@ 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); |