1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Media driver for Freescale i.MX5/6 SOC
4 *
5 * Open Firmware parsing.
6 *
7 * Copyright (c) 2016 Mentor Graphics Inc.
8 */
9#include <linux/of_platform.h>
10#include <media/v4l2-ctrls.h>
11#include <media/v4l2-device.h>
12#include <media/v4l2-fwnode.h>
13#include <media/v4l2-subdev.h>
14#include <media/videobuf2-dma-contig.h>
15#include <linux/of_graph.h>
16#include <video/imx-ipu-v3.h>
17#include "imx-media.h"
18
19static int imx_media_of_add_csi(struct imx_media_dev *imxmd,
20				struct device_node *csi_np)
21{
22	struct v4l2_async_connection *asd;
23	int ret = 0;
24
25	if (!of_device_is_available(csi_np)) {
26		dev_dbg(imxmd->md.dev, "%s: %pOFn not enabled\n", __func__,
27			csi_np);
28		return -ENODEV;
29	}
30
31	/* add CSI fwnode to async notifier */
32	asd = v4l2_async_nf_add_fwnode(&imxmd->notifier,
33				       of_fwnode_handle(csi_np),
34				       struct v4l2_async_connection);
35	if (IS_ERR(asd)) {
36		ret = PTR_ERR(asd);
37		if (ret == -EEXIST)
38			dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n",
39				__func__, csi_np);
40	}
41
42	return ret;
43}
44
45int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
46			     struct device_node *np)
47{
48	struct device_node *csi_np;
49	int i, ret;
50
51	for (i = 0; ; i++) {
52		csi_np = of_parse_phandle(np, "ports", i);
53		if (!csi_np)
54			break;
55
56		ret = imx_media_of_add_csi(imxmd, csi_np);
57		if (ret) {
58			/* unavailable or already added is not an error */
59			if (ret == -ENODEV || ret == -EEXIST) {
60				of_node_put(csi_np);
61				continue;
62			}
63
64			/* other error, can't continue */
65			goto err_out;
66		}
67	}
68
69	return 0;
70
71err_out:
72	of_node_put(csi_np);
73	return ret;
74}
75EXPORT_SYMBOL_GPL(imx_media_add_of_subdevs);
76