2 * Media driver for Freescale i.MX5/6 SOC
4 * Open Firmware parsing.
6 * Copyright (c) 2016 Mentor Graphics Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 #include <linux/of_platform.h>
14 #include <media/v4l2-ctrls.h>
15 #include <media/v4l2-device.h>
16 #include <media/v4l2-fwnode.h>
17 #include <media/v4l2-subdev.h>
18 #include <media/videobuf2-dma-contig.h>
19 #include <linux/of_graph.h>
20 #include <video/imx-ipu-v3.h>
21 #include "imx-media.h"
23 static int of_add_csi(struct imx_media_dev *imxmd, struct device_node *csi_np)
27 if (!of_device_is_available(csi_np)) {
28 dev_dbg(imxmd->md.dev, "%s: %s not enabled\n", __func__,
30 /* unavailable is not an error */
34 /* add CSI fwnode to async notifier */
35 ret = imx_media_add_async_subdev(imxmd, of_fwnode_handle(csi_np), NULL);
38 /* already added, everything is fine */
42 /* other error, can't continue */
49 int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
50 struct device_node *np)
52 struct device_node *csi_np;
56 csi_np = of_parse_phandle(np, "ports", i);
60 ret = of_add_csi(imxmd, csi_np);
70 * Create a single media link to/from sd using a fwnode link.
72 * NOTE: this function assumes an OF port node is equivalent to
73 * a media pad (port id equal to media pad index), and that an
74 * OF endpoint node is equivalent to a media link.
76 static int create_of_link(struct imx_media_dev *imxmd,
77 struct v4l2_subdev *sd,
78 struct v4l2_fwnode_link *link)
80 struct v4l2_subdev *remote, *src, *sink;
81 int src_pad, sink_pad;
83 if (link->local_port >= sd->entity.num_pads)
86 remote = imx_media_find_subdev_by_fwnode(imxmd, link->remote_node);
90 if (sd->entity.pads[link->local_port].flags & MEDIA_PAD_FL_SINK) {
92 src_pad = link->remote_port;
94 sink_pad = link->local_port;
97 src_pad = link->local_port;
99 sink_pad = link->remote_port;
102 /* make sure link doesn't already exist before creating */
103 if (media_entity_find_link(&src->entity.pads[src_pad],
104 &sink->entity.pads[sink_pad]))
107 v4l2_info(sd->v4l2_dev, "%s:%d -> %s:%d\n",
108 src->name, src_pad, sink->name, sink_pad);
110 return media_create_pad_link(&src->entity, src_pad,
111 &sink->entity, sink_pad, 0);
115 * Create media links to/from sd using its device-tree endpoints.
117 int imx_media_create_of_links(struct imx_media_dev *imxmd,
118 struct v4l2_subdev *sd)
120 struct v4l2_fwnode_link link;
121 struct device_node *ep;
124 for_each_endpoint_of_node(sd->dev->of_node, ep) {
125 ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
129 ret = create_of_link(imxmd, sd, &link);
130 v4l2_fwnode_put_link(&link);
139 * Create media links to the given CSI subdevice's sink pads,
140 * using its device-tree endpoints.
142 int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
143 struct v4l2_subdev *csi)
145 struct device_node *csi_np = csi->dev->of_node;
146 struct fwnode_handle *fwnode, *csi_ep;
147 struct v4l2_fwnode_link link;
148 struct device_node *ep;
151 link.local_node = of_fwnode_handle(csi_np);
152 link.local_port = CSI_SINK_PAD;
154 for_each_child_of_node(csi_np, ep) {
155 csi_ep = of_fwnode_handle(ep);
157 fwnode = fwnode_graph_get_remote_endpoint(csi_ep);
161 fwnode = fwnode_get_parent(fwnode);
162 fwnode_property_read_u32(fwnode, "reg", &link.remote_port);
163 fwnode = fwnode_get_next_parent(fwnode);
164 if (is_of_node(fwnode) &&
165 of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
166 fwnode = fwnode_get_next_parent(fwnode);
167 link.remote_node = fwnode;
169 ret = create_of_link(imxmd, csi, &link);
170 fwnode_handle_put(link.remote_node);