aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/media/imx/imx-media-of.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/media/imx/imx-media-of.c')
-rw-r--r--drivers/staging/media/imx/imx-media-of.c79
1 files changed, 49 insertions, 30 deletions
diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c
index 03446335ac03..990e82aa8e42 100644
--- a/drivers/staging/media/imx/imx-media-of.c
+++ b/drivers/staging/media/imx/imx-media-of.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* Media driver for Freescale i.MX5/6 SOC
*
* Open Firmware parsing.
*
* Copyright (c) 2016 Mentor Graphics Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/of_platform.h>
#include <media/v4l2-ctrls.h>
@@ -23,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);
@@ -60,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;
}
/*
@@ -145,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);