root/drivers/staging/media/imx/imx-media-of.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. imx_media_of_add_csi
  2. imx_media_add_of_subdevs
  3. create_of_link
  4. imx_media_create_of_links
  5. imx_media_create_csi_of_links

   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 
  19 int imx_media_of_add_csi(struct imx_media_dev *imxmd,
  20                          struct device_node *csi_np)
  21 {
  22         struct v4l2_async_subdev *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_notifier_add_fwnode_subdev(&imxmd->notifier,
  33                                                     of_fwnode_handle(csi_np),
  34                                                     sizeof(*asd));
  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 EXPORT_SYMBOL_GPL(imx_media_of_add_csi);
  45 
  46 int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
  47                              struct device_node *np)
  48 {
  49         struct device_node *csi_np;
  50         int i, ret;
  51 
  52         for (i = 0; ; i++) {
  53                 csi_np = of_parse_phandle(np, "ports", i);
  54                 if (!csi_np)
  55                         break;
  56 
  57                 ret = imx_media_of_add_csi(imxmd, csi_np);
  58                 if (ret) {
  59                         /* unavailable or already added is not an error */
  60                         if (ret == -ENODEV || ret == -EEXIST) {
  61                                 of_node_put(csi_np);
  62                                 continue;
  63                         }
  64 
  65                         /* other error, can't continue */
  66                         goto err_out;
  67                 }
  68         }
  69 
  70         return 0;
  71 
  72 err_out:
  73         of_node_put(csi_np);
  74         return ret;
  75 }
  76 EXPORT_SYMBOL_GPL(imx_media_add_of_subdevs);
  77 
  78 /*
  79  * Create a single media link to/from sd using a fwnode link.
  80  *
  81  * NOTE: this function assumes an OF port node is equivalent to
  82  * a media pad (port id equal to media pad index), and that an
  83  * OF endpoint node is equivalent to a media link.
  84  */
  85 static int create_of_link(struct imx_media_dev *imxmd,
  86                           struct v4l2_subdev *sd,
  87                           struct v4l2_fwnode_link *link)
  88 {
  89         struct v4l2_subdev *remote, *src, *sink;
  90         int src_pad, sink_pad;
  91 
  92         if (link->local_port >= sd->entity.num_pads)
  93                 return -EINVAL;
  94 
  95         remote = imx_media_find_subdev_by_fwnode(imxmd, link->remote_node);
  96         if (!remote)
  97                 return 0;
  98 
  99         if (sd->entity.pads[link->local_port].flags & MEDIA_PAD_FL_SINK) {
 100                 src = remote;
 101                 src_pad = link->remote_port;
 102                 sink = sd;
 103                 sink_pad = link->local_port;
 104         } else {
 105                 src = sd;
 106                 src_pad = link->local_port;
 107                 sink = remote;
 108                 sink_pad = link->remote_port;
 109         }
 110 
 111         /* make sure link doesn't already exist before creating */
 112         if (media_entity_find_link(&src->entity.pads[src_pad],
 113                                    &sink->entity.pads[sink_pad]))
 114                 return 0;
 115 
 116         v4l2_info(sd->v4l2_dev, "%s:%d -> %s:%d\n",
 117                   src->name, src_pad, sink->name, sink_pad);
 118 
 119         return media_create_pad_link(&src->entity, src_pad,
 120                                      &sink->entity, sink_pad, 0);
 121 }
 122 
 123 /*
 124  * Create media links to/from sd using its device-tree endpoints.
 125  */
 126 int imx_media_create_of_links(struct imx_media_dev *imxmd,
 127                               struct v4l2_subdev *sd)
 128 {
 129         struct v4l2_fwnode_link link;
 130         struct device_node *ep;
 131         int ret;
 132 
 133         for_each_endpoint_of_node(sd->dev->of_node, ep) {
 134                 ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
 135                 if (ret)
 136                         continue;
 137 
 138                 ret = create_of_link(imxmd, sd, &link);
 139                 v4l2_fwnode_put_link(&link);
 140                 if (ret)
 141                         return ret;
 142         }
 143 
 144         return 0;
 145 }
 146 EXPORT_SYMBOL_GPL(imx_media_create_of_links);
 147 
 148 /*
 149  * Create media links to the given CSI subdevice's sink pads,
 150  * using its device-tree endpoints.
 151  */
 152 int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
 153                                   struct v4l2_subdev *csi)
 154 {
 155         struct device_node *csi_np = csi->dev->of_node;
 156         struct device_node *ep;
 157 
 158         for_each_child_of_node(csi_np, ep) {
 159                 struct fwnode_handle *fwnode, *csi_ep;
 160                 struct v4l2_fwnode_link link;
 161                 int ret;
 162 
 163                 memset(&link, 0, sizeof(link));
 164 
 165                 link.local_node = of_fwnode_handle(csi_np);
 166                 link.local_port = CSI_SINK_PAD;
 167 
 168                 csi_ep = of_fwnode_handle(ep);
 169 
 170                 fwnode = fwnode_graph_get_remote_endpoint(csi_ep);
 171                 if (!fwnode)
 172                         continue;
 173 
 174                 fwnode = fwnode_get_parent(fwnode);
 175                 fwnode_property_read_u32(fwnode, "reg", &link.remote_port);
 176                 fwnode = fwnode_get_next_parent(fwnode);
 177                 if (is_of_node(fwnode) &&
 178                     of_node_name_eq(to_of_node(fwnode), "ports"))
 179                         fwnode = fwnode_get_next_parent(fwnode);
 180                 link.remote_node = fwnode;
 181 
 182                 ret = create_of_link(imxmd, csi, &link);
 183                 fwnode_handle_put(link.remote_node);
 184                 if (ret)
 185                         return ret;
 186         }
 187 
 188         return 0;
 189 }
 190 EXPORT_SYMBOL_GPL(imx_media_create_csi_of_links);

/* [<][>][^][v][top][bottom][index][help] */