Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f6a0c59 authored by Steve Longerbeam's avatar Steve Longerbeam Committed by Mauro Carvalho Chehab
Browse files

media: staging/imx: remove static subdev arrays



For more complex OF graphs, there will be more async subdevices
registered. Remove the static subdev[IMX_MEDIA_MAX_SUBDEVS] array,
so that imx-media places no limits on the number of async subdevs
that can be added and registered.

There were two uses for 'struct imx_media_subdev'. First was to act
as the async subdev list to be passed to v4l2_async_notifier_register().

Second was to aid in inheriting subdev controls to the capture devices,
and this is done by creating a list of capture devices that can be reached
from a subdev's source pad. So 'struct imx_media_subdev' also contained
a static array of 'struct imx_media_pad' for placing the capture device
lists at each pad.

'struct imx_media_subdev' has been completely removed. Instead, at async
completion, allocate an array of 'struct imx_media_pad' and attach it to
the subdev's host_priv pointer, in order to support subdev controls
inheritance.

Likewise, remove static async_ptrs[IMX_MEDIA_MAX_SUBDEVS] array.
Instead, allocate a 'struct imx_media_async_subdev' when forming
the async list, and add it to an asd_list list_head in
imx_media_add_async_subdev(). At async completion, allocate the
asd pointer list and pull the asd's off asd_list for
v4l2_async_notifier_register().

Signed-off-by: default avatarSteve Longerbeam <steve_longerbeam@mentor.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 4eef678d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -300,7 +300,7 @@ static int prp_link_validate(struct v4l2_subdev *sd,
{
	struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
	struct prp_priv *priv = ic_priv->prp_priv;
	struct imx_media_subdev *csi;
	struct v4l2_subdev *csi;
	int ret;

	ret = v4l2_subdev_link_validate_default(sd, link,
@@ -333,7 +333,7 @@ static int prp_link_validate(struct v4l2_subdev *sd,
	}

	if (csi) {
		switch (csi->sd->grp_id) {
		switch (csi->grp_id) {
		case IMX_MEDIA_GRP_ID_CSI0:
			priv->csi_id = 0;
			break;
+4 −5
Original line number Diff line number Diff line
@@ -138,7 +138,6 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv,
				     struct v4l2_fwnode_endpoint *ep)
{
	struct device_node *endpoint, *port;
	struct imx_media_subdev *imxsd;
	struct media_entity *src;
	struct v4l2_subdev *sd;
	struct media_pad *pad;
@@ -154,10 +153,10 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv,
		 * CSI-2 receiver if it is in the path, otherwise stay
		 * with video mux.
		 */
		imxsd = imx_media_find_upstream_subdev(priv->md, src,
		sd = imx_media_find_upstream_subdev(priv->md, src,
						    IMX_MEDIA_GRP_ID_CSI2);
		if (!IS_ERR(imxsd))
			src = &imxsd->sd->entity;
		if (!IS_ERR(sd))
			src = &sd->entity;
	}

	/* get source pad of entity directly upstream from src */
+120 −95
Original line number Diff line number Diff line
@@ -33,28 +33,28 @@ static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
}

/*
 * Find a subdev by fwnode or device name. This is called during
 * Find an asd by fwnode or device name. This is called during
 * driver load to form the async subdev list and bind them.
 */
struct imx_media_subdev *
imx_media_find_async_subdev(struct imx_media_dev *imxmd,
static struct v4l2_async_subdev *
find_async_subdev(struct imx_media_dev *imxmd,
		  struct fwnode_handle *fwnode,
		  const char *devname)
{
	struct imx_media_subdev *imxsd;
	int i;
	struct imx_media_async_subdev *imxasd;
	struct v4l2_async_subdev *asd;

	for (i = 0; i < imxmd->subdev_notifier.num_subdevs; i++) {
		imxsd = &imxmd->subdev[i];
		switch (imxsd->asd.match_type) {
	list_for_each_entry(imxasd, &imxmd->asd_list, list) {
		asd = &imxasd->asd;
		switch (asd->match_type) {
		case V4L2_ASYNC_MATCH_FWNODE:
			if (fwnode && imxsd->asd.match.fwnode.fwnode == fwnode)
				return imxsd;
			if (fwnode && asd->match.fwnode.fwnode == fwnode)
				return asd;
			break;
		case V4L2_ASYNC_MATCH_DEVNAME:
			if (devname &&
			    !strcmp(imxsd->asd.match.device_name.name, devname))
				return imxsd;
			if (devname && !strcmp(asd->match.device_name.name,
					       devname))
				return asd;
			break;
		default:
			break;
@@ -72,51 +72,47 @@ imx_media_find_async_subdev(struct imx_media_dev *imxmd,
 * given platform_device. This is called during driver load when
 * forming the async subdev list.
 */
struct imx_media_subdev *
imx_media_add_async_subdev(struct imx_media_dev *imxmd,
int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
			       struct fwnode_handle *fwnode,
			       struct platform_device *pdev)
{
	struct device_node *np = to_of_node(fwnode);
	struct imx_media_subdev *imxsd;
	struct imx_media_async_subdev *imxasd;
	struct v4l2_async_subdev *asd;
	const char *devname = NULL;
	int sd_idx;
	int ret = 0;

	mutex_lock(&imxmd->mutex);

	if (pdev)
		devname = dev_name(&pdev->dev);

	/* return -EEXIST if this subdev already added */
	if (imx_media_find_async_subdev(imxmd, fwnode, devname)) {
	/* return -EEXIST if this asd already added */
	if (find_async_subdev(imxmd, fwnode, devname)) {
		dev_dbg(imxmd->md.dev, "%s: already added %s\n",
			__func__, np ? np->name : devname);
		imxsd = ERR_PTR(-EEXIST);
		ret = -EEXIST;
		goto out;
	}

	sd_idx = imxmd->subdev_notifier.num_subdevs;
	if (sd_idx >= IMX_MEDIA_MAX_SUBDEVS) {
		dev_err(imxmd->md.dev, "%s: too many subdevs! can't add %s\n",
			__func__, np ? np->name : devname);
		imxsd = ERR_PTR(-ENOSPC);
	imxasd = devm_kzalloc(imxmd->md.dev, sizeof(*imxasd), GFP_KERNEL);
	if (!imxasd) {
		ret = -ENOMEM;
		goto out;
	}
	asd = &imxasd->asd;

	imxsd = &imxmd->subdev[sd_idx];

	asd = &imxsd->asd;
	if (fwnode) {
		asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
		asd->match.fwnode.fwnode = fwnode;
	} else {
		asd->match_type = V4L2_ASYNC_MATCH_DEVNAME;
		asd->match.device_name.name = devname;
		imxsd->pdev = pdev;
		imxasd->pdev = pdev;
	}

	imxmd->async_ptrs[sd_idx] = asd;
	list_add_tail(&imxasd->list, &imxmd->asd_list);

	imxmd->subdev_notifier.num_subdevs++;

	dev_dbg(imxmd->md.dev, "%s: added %s, match type %s\n",
@@ -124,7 +120,7 @@ imx_media_add_async_subdev(struct imx_media_dev *imxmd,

out:
	mutex_unlock(&imxmd->mutex);
	return imxsd;
	return ret;
}

/*
@@ -162,56 +158,48 @@ static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
				  struct v4l2_async_subdev *asd)
{
	struct imx_media_dev *imxmd = notifier2dev(notifier);
	struct imx_media_subdev *imxsd;
	int ret = 0;

	mutex_lock(&imxmd->mutex);

	imxsd = imx_media_find_async_subdev(imxmd, sd->fwnode,
					    dev_name(sd->dev));
	if (!imxsd) {
		ret = -EINVAL;
		goto out;
	}

	if (sd->grp_id & IMX_MEDIA_GRP_ID_CSI) {
		ret = imx_media_get_ipu(imxmd, sd);
		if (ret)
			goto out_unlock;
			goto out;
	}

	/* attach the subdev */
	imxsd->sd = sd;
	v4l2_info(&imxmd->v4l2_dev, "subdev %s bound\n", sd->name);
out:
	if (ret)
		v4l2_warn(&imxmd->v4l2_dev,
			  "Received unknown subdev %s\n", sd->name);
	else
		v4l2_info(&imxmd->v4l2_dev,
			  "Registered subdev %s\n", sd->name);

out_unlock:
	mutex_unlock(&imxmd->mutex);
	return ret;
}

/*
 * create the media links from all pads and their links.
 * Called after all subdevs have registered.
 * create the media links for all subdevs that registered async.
 * Called after all async subdevs have bound.
 */
static int imx_media_create_links(struct imx_media_dev *imxmd)
static int imx_media_create_links(struct v4l2_async_notifier *notifier)
{
	struct imx_media_subdev *imxsd;
	struct imx_media_dev *imxmd = notifier2dev(notifier);
	struct v4l2_subdev *sd;
	int i, ret;

	for (i = 0; i < imxmd->num_subdevs; i++) {
		imxsd = &imxmd->subdev[i];
		sd = imxsd->sd;
	int ret;

		if (((sd->grp_id & IMX_MEDIA_GRP_ID_CSI) || imxsd->pdev)) {
			/* this is an internal subdev or a CSI */
			ret = imx_media_create_internal_links(imxmd, imxsd);
	/*
	 * Only links are created between subdevices that are known
	 * to the async notifier. If there are other non-async subdevices,
	 * they were created internally by some subdevice (smiapp is one
	 * example). In those cases it is expected the subdevice is
	 * responsible for creating those internal links.
	 */
	list_for_each_entry(sd, &notifier->done, async_list) {
		switch (sd->grp_id) {
		case IMX_MEDIA_GRP_ID_VDIC:
		case IMX_MEDIA_GRP_ID_IC_PRP:
		case IMX_MEDIA_GRP_ID_IC_PRPENC:
		case IMX_MEDIA_GRP_ID_IC_PRPVF:
		case IMX_MEDIA_GRP_ID_CSI0:
		case IMX_MEDIA_GRP_ID_CSI1:
			ret = imx_media_create_internal_links(imxmd, sd);
			if (ret)
				return ret;
			/*
@@ -220,10 +208,12 @@ static int imx_media_create_links(struct imx_media_dev *imxmd)
			 * to the CSI sink pads.
			 */
			if (sd->grp_id & IMX_MEDIA_GRP_ID_CSI)
				imx_media_create_csi_of_links(imxmd, imxsd);
		} else {
				imx_media_create_csi_of_links(imxmd, sd);
			break;
		default:
			/* this is an external fwnode subdev */
			imx_media_create_of_links(imxmd, imxsd);
			imx_media_create_of_links(imxmd, sd);
			break;
		}
	}

@@ -239,7 +229,6 @@ static int imx_media_add_vdev_to_pad(struct imx_media_dev *imxmd,
				     struct media_pad *srcpad)
{
	struct media_entity *entity = srcpad->entity;
	struct imx_media_subdev *imxsd;
	struct imx_media_pad *imxpad;
	struct media_link *link;
	struct v4l2_subdev *sd;
@@ -250,14 +239,18 @@ static int imx_media_add_vdev_to_pad(struct imx_media_dev *imxmd,
		return 0;

	sd = media_entity_to_v4l2_subdev(entity);
	imxsd = imx_media_find_subdev_by_sd(imxmd, sd);
	if (IS_ERR(imxsd)) {
		v4l2_err(&imxmd->v4l2_dev, "failed to find subdev for entity %s, sd %p err %ld\n",
			 entity->name, sd, PTR_ERR(imxsd));

	imxpad = to_imx_media_pad(sd, srcpad->index);
	if (!imxpad) {
		v4l2_warn(&imxmd->v4l2_dev, "%s:%u has no vdev list!\n",
			  entity->name, srcpad->index);
		/*
		 * shouldn't happen, but no reason to fail driver load,
		 * just skip this entity.
		 */
		return 0;
	}

	imxpad = &imxsd->pad[srcpad->index];
	vdev_idx = imxpad->num_vdevs;

	/* just return if we've been here before */
@@ -296,6 +289,27 @@ static int imx_media_add_vdev_to_pad(struct imx_media_dev *imxmd,
	return 0;
}

static int imx_media_alloc_pad_vdev_lists(struct imx_media_dev *imxmd)
{
	struct imx_media_pad *imxpads;
	struct media_entity *entity;
	struct v4l2_subdev *sd;

	list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
		entity = &sd->entity;
		imxpads = devm_kzalloc(imxmd->md.dev,
				       entity->num_pads * sizeof(*imxpads),
				       GFP_KERNEL);
		if (!imxpads)
			return -ENOMEM;

		/* attach imxpads to the subdev's host private pointer */
		sd->host_priv = imxpads;
	}

	return 0;
}

/* form the vdev lists in all imx-media source pads */
static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd)
{
@@ -303,6 +317,10 @@ static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd)
	struct media_link *link;
	int i, ret;

	ret = imx_media_alloc_pad_vdev_lists(imxmd);
	if (ret)
		return ret;

	for (i = 0; i < imxmd->num_vdevs; i++) {
		vdev = imxmd->vdev[i];
		link = list_first_entry(&vdev->vfd->entity.links,
@@ -319,20 +337,11 @@ static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd)
static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
{
	struct imx_media_dev *imxmd = notifier2dev(notifier);
	int i, ret;
	int ret;

	mutex_lock(&imxmd->mutex);

	/* make sure all subdevs were bound */
	for (i = 0; i < imxmd->num_subdevs; i++) {
		if (!imxmd->subdev[i].sd) {
			v4l2_err(&imxmd->v4l2_dev, "unbound subdev!\n");
			ret = -ENODEV;
			goto unlock;
		}
	}

	ret = imx_media_create_links(imxmd);
	ret = imx_media_create_links(notifier);
	if (ret)
		goto unlock;

@@ -401,7 +410,6 @@ static int imx_media_link_notify(struct media_link *link, u32 flags,
				 unsigned int notification)
{
	struct media_entity *source = link->source->entity;
	struct imx_media_subdev *imxsd;
	struct imx_media_pad *imxpad;
	struct imx_media_dev *imxmd;
	struct video_device *vfd;
@@ -421,10 +429,11 @@ static int imx_media_link_notify(struct media_link *link, u32 flags,

	imxmd = dev_get_drvdata(sd->v4l2_dev->dev);

	imxsd = imx_media_find_subdev_by_sd(imxmd, sd);
	if (IS_ERR(imxsd))
		return PTR_ERR(imxsd);
	imxpad = &imxsd->pad[pad_idx];
	imxpad = to_imx_media_pad(sd, pad_idx);
	if (!imxpad) {
		/* shouldn't happen, but no reason to fail link setup */
		return 0;
	}

	/*
	 * Before disabling a link, reset controls for all video
@@ -468,8 +477,10 @@ static int imx_media_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *node = dev->of_node;
	struct imx_media_async_subdev *imxasd;
	struct v4l2_async_subdev **subdevs;
	struct imx_media_dev *imxmd;
	int ret;
	int num_subdevs, i, ret;

	imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
	if (!imxmd)
@@ -498,6 +509,8 @@ static int imx_media_probe(struct platform_device *pdev)

	dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);

	INIT_LIST_HEAD(&imxmd->asd_list);

	ret = imx_media_add_of_subdevs(imxmd, node);
	if (ret) {
		v4l2_err(&imxmd->v4l2_dev,
@@ -512,15 +525,27 @@ static int imx_media_probe(struct platform_device *pdev)
		goto unreg_dev;
	}

	num_subdevs = imxmd->subdev_notifier.num_subdevs;

	/* no subdevs? just bail */
	imxmd->num_subdevs = imxmd->subdev_notifier.num_subdevs;
	if (imxmd->num_subdevs == 0) {
	if (num_subdevs == 0) {
		ret = -ENODEV;
		goto unreg_dev;
	}

	subdevs = devm_kzalloc(imxmd->md.dev, sizeof(*subdevs) * num_subdevs,
			       GFP_KERNEL);
	if (!subdevs) {
		ret = -ENOMEM;
		goto unreg_dev;
	}

	i = 0;
	list_for_each_entry(imxasd, &imxmd->asd_list, list)
		subdevs[i++] = &imxasd->asd;

	/* prepare the async subdev notifier and register it */
	imxmd->subdev_notifier.subdevs = imxmd->async_ptrs;
	imxmd->subdev_notifier.subdevs = subdevs;
	imxmd->subdev_notifier.ops = &imx_media_subdev_ops;
	ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
					   &imxmd->subdev_notifier);
+23 −28
Original line number Diff line number Diff line
@@ -68,6 +68,8 @@ struct internal_link {
	int remote_pad;
};

/* max pads per internal-sd */
#define MAX_INTERNAL_PADS   8
/* max links per internal-sd pad */
#define MAX_INTERNAL_LINKS  8

@@ -77,7 +79,7 @@ struct internal_pad {

static const struct internal_subdev {
	const struct internal_subdev_id *id;
	struct internal_pad pad[IMX_MEDIA_MAX_PADS];
	struct internal_pad pad[MAX_INTERNAL_PADS];
} int_subdev[num_isd] = {
	[isd_csi0] = {
		.id = &isd_id[isd_csi0],
@@ -181,8 +183,8 @@ static const struct internal_subdev *find_intsd_by_grp_id(u32 grp_id)
	return NULL;
}

static struct imx_media_subdev *find_sink(struct imx_media_dev *imxmd,
					  struct imx_media_subdev *src,
static struct v4l2_subdev *find_sink(struct imx_media_dev *imxmd,
				     struct v4l2_subdev *src,
				     const struct internal_link *link)
{
	char sink_devname[32];
@@ -194,20 +196,20 @@ static struct imx_media_subdev *find_sink(struct imx_media_dev *imxmd,
	 * a CSI, it has different struct ipu_client_platformdata which
	 * does not contain IPU id.
	 */
	if (sscanf(src->sd->name, "ipu%d", &ipu_id) != 1)
	if (sscanf(src->name, "ipu%d", &ipu_id) != 1)
		return NULL;

	isd_to_devname(sink_devname, sizeof(sink_devname),
		       link->remote, ipu_id - 1);

	return imx_media_find_async_subdev(imxmd, NULL, sink_devname);
	return imx_media_find_subdev_by_devname(imxmd, sink_devname);
}

static int create_ipu_internal_link(struct imx_media_dev *imxmd,
				    struct imx_media_subdev *src,
				    struct v4l2_subdev *src,
				    const struct internal_link *link)
{
	struct imx_media_subdev *sink;
	struct v4l2_subdev *sink;
	int ret;

	sink = find_sink(imxmd, src, link);
@@ -215,11 +217,11 @@ static int create_ipu_internal_link(struct imx_media_dev *imxmd,
		return -ENODEV;

	v4l2_info(&imxmd->v4l2_dev, "%s:%d -> %s:%d\n",
		  src->sd->name, link->local_pad,
		  sink->sd->name, link->remote_pad);
		  src->name, link->local_pad,
		  sink->name, link->remote_pad);

	ret = media_create_pad_link(&src->sd->entity, link->local_pad,
				    &sink->sd->entity, link->remote_pad, 0);
	ret = media_create_pad_link(&src->entity, link->local_pad,
				    &sink->entity, link->remote_pad, 0);
	if (ret)
		v4l2_err(&imxmd->v4l2_dev,
			 "create_pad_link failed: %d\n", ret);
@@ -228,16 +230,15 @@ static int create_ipu_internal_link(struct imx_media_dev *imxmd,
}

int imx_media_create_internal_links(struct imx_media_dev *imxmd,
				    struct imx_media_subdev *imxsd)
				    struct v4l2_subdev *sd)
{
	struct v4l2_subdev *sd = imxsd->sd;
	const struct internal_subdev *intsd;
	const struct internal_pad *intpad;
	const struct internal_link *link;
	struct media_pad *pad;
	int i, j, ret;

	intsd = find_intsd_by_grp_id(imxsd->sd->grp_id);
	intsd = find_intsd_by_grp_id(sd->grp_id);
	if (!intsd)
		return -ENODEV;

@@ -255,7 +256,7 @@ int imx_media_create_internal_links(struct imx_media_dev *imxmd,
			if (!link->remote)
				break;

			ret = create_ipu_internal_link(imxmd, imxsd, link);
			ret = create_ipu_internal_link(imxmd, sd, link);
			if (ret)
				return ret;
		}
@@ -271,7 +272,6 @@ static int add_internal_subdev(struct imx_media_dev *imxmd,
{
	struct imx_media_internal_sd_platformdata pdata;
	struct platform_device_info pdevinfo = {0};
	struct imx_media_subdev *imxsd;
	struct platform_device *pdev;

	pdata.grp_id = isd->id->grp_id;
@@ -294,11 +294,7 @@ static int add_internal_subdev(struct imx_media_dev *imxmd,
	if (IS_ERR(pdev))
		return PTR_ERR(pdev);

	imxsd = imx_media_add_async_subdev(imxmd, NULL, pdev);
	if (IS_ERR(imxsd))
		return PTR_ERR(imxsd);

	return 0;
	return imx_media_add_async_subdev(imxmd, NULL, pdev);
}

/* adds the internal subdevs in one ipu */
@@ -353,13 +349,12 @@ int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd)

void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd)
{
	struct imx_media_subdev *imxsd;
	int i;
	struct imx_media_async_subdev *imxasd;

	for (i = 0; i < imxmd->subdev_notifier.num_subdevs; i++) {
		imxsd = &imxmd->subdev[i];
		if (!imxsd->pdev)
	list_for_each_entry(imxasd, &imxmd->asd_list, list) {
		if (!imxasd->pdev)
			continue;
		platform_device_unregister(imxsd->pdev);

		platform_device_unregister(imxasd->pdev);
	}
}
+13 −18
Original line number Diff line number Diff line
@@ -76,7 +76,6 @@ static int
of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
		bool is_csi_port)
{
	struct imx_media_subdev *imxsd;
	int i, num_ports, ret;

	if (!of_device_is_available(sd_np)) {
@@ -87,9 +86,8 @@ of_parse_subdev(struct imx_media_dev *imxmd, struct device_node *sd_np,
	}

	/* register this subdev with async notifier */
	imxsd = imx_media_add_async_subdev(imxmd, of_fwnode_handle(sd_np),
	ret = imx_media_add_async_subdev(imxmd, of_fwnode_handle(sd_np),
					 NULL);
	ret = PTR_ERR_OR_ZERO(imxsd);
	if (ret) {
		if (ret == -EEXIST) {
			/* already added, everything is fine */
@@ -159,37 +157,35 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
}

/*
 * Create a single media link to/from imxsd using a fwnode link.
 * Create a single media link to/from sd using a fwnode link.
 *
 * NOTE: this function assumes an OF port node is equivalent to
 * a media pad (port id equal to media pad index), and that an
 * OF endpoint node is equivalent to a media link.
 */
static int create_of_link(struct imx_media_dev *imxmd,
			  struct imx_media_subdev *imxsd,
			  struct v4l2_subdev *sd,
			  struct v4l2_fwnode_link *link)
{
	struct v4l2_subdev *sd = imxsd->sd;
	struct imx_media_subdev *remote;
	struct v4l2_subdev *src, *sink;
	struct v4l2_subdev *remote, *src, *sink;
	int src_pad, sink_pad;

	if (link->local_port >= sd->entity.num_pads)
		return -EINVAL;

	remote = imx_media_find_async_subdev(imxmd, link->remote_node, NULL);
	remote = imx_media_find_subdev_by_fwnode(imxmd, link->remote_node);
	if (!remote)
		return 0;

	if (sd->entity.pads[link->local_port].flags & MEDIA_PAD_FL_SINK) {
		src = remote->sd;
		src = remote;
		src_pad = link->remote_port;
		sink = sd;
		sink_pad = link->local_port;
	} else {
		src = sd;
		src_pad = link->local_port;
		sink = remote->sd;
		sink = remote;
		sink_pad = link->remote_port;
	}

@@ -206,12 +202,11 @@ static int create_of_link(struct imx_media_dev *imxmd,
}

/*
 * Create media links to/from imxsd using its device-tree endpoints.
 * Create media links to/from sd using its device-tree endpoints.
 */
int imx_media_create_of_links(struct imx_media_dev *imxmd,
			      struct imx_media_subdev *imxsd)
			      struct v4l2_subdev *sd)
{
	struct v4l2_subdev *sd = imxsd->sd;
	struct v4l2_fwnode_link link;
	struct device_node *ep;
	int ret;
@@ -221,7 +216,7 @@ int imx_media_create_of_links(struct imx_media_dev *imxmd,
		if (ret)
			continue;

		ret = create_of_link(imxmd, imxsd, &link);
		ret = create_of_link(imxmd, sd, &link);
		v4l2_fwnode_put_link(&link);
		if (ret)
			return ret;
@@ -235,9 +230,9 @@ int imx_media_create_of_links(struct imx_media_dev *imxmd,
 * using its device-tree endpoints.
 */
int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
				  struct imx_media_subdev *csi)
				  struct v4l2_subdev *csi)
{
	struct device_node *csi_np = csi->sd->dev->of_node;
	struct device_node *csi_np = csi->dev->of_node;
	struct fwnode_handle *fwnode, *csi_ep;
	struct v4l2_fwnode_link link;
	struct device_node *ep;
Loading