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

media: imx: Don't register IPU subdevs/links if CSI port missing



The second IPU internal sub-devices were being registered and links
to them created even when the second IPU is not present. This is wrong
for i.MX6 S/DL and i.MX53 which have only a single IPU.

Fixes: e1302912 ("[media] media: Add i.MX media core driver")

Signed-off-by: default avatarSteve Longerbeam <slongerbeam@gmail.com>
Reviewed-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 085b26da
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -477,13 +477,6 @@ static int imx_media_probe(struct platform_device *pdev)
		goto cleanup;
	}

	ret = imx_media_add_ipu_internal_subdevs(imxmd);
	if (ret) {
		v4l2_err(&imxmd->v4l2_dev,
			 "add_ipu_internal_subdevs failed with %d\n", ret);
		goto cleanup;
	}

	ret = imx_media_dev_notifier_register(imxmd);
	if (ret)
		goto del_int;
+4 −18
Original line number Diff line number Diff line
@@ -298,13 +298,14 @@ static int add_internal_subdev(struct imx_media_dev *imxmd,
}

/* adds the internal subdevs in one ipu */
static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id)
int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd,
				       int ipu_id)
{
	enum isd_enum i;
	int ret;

	for (i = 0; i < num_isd; i++) {
		const struct internal_subdev *isd = &int_subdev[i];
		int ret;

		/*
		 * the CSIs are represented in the device-tree, so those
@@ -321,24 +322,9 @@ static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id)
			break;
		}

		if (ret)
			return ret;
	}

	return 0;
}

int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd)
{
	int ret;

	ret = add_ipu_internal_subdevs(imxmd, 0);
	if (ret)
		goto remove;

	ret = add_ipu_internal_subdevs(imxmd, 1);
		if (ret)
			goto remove;
	}

	return 0;

+39 −19
Original line number Diff line number Diff line
@@ -23,36 +23,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 +49,43 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
			break;

		ret = imx_media_of_add_csi(imxmd, csi_np);
		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)
			return 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;
}

/*
+2 −1
Original line number Diff line number Diff line
@@ -252,7 +252,8 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd);
void imx_media_fim_free(struct imx_media_fim *fim);

/* imx-media-internal-sd.c */
int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd);
int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd,
				       int ipu_id);
int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd,
					struct v4l2_subdev *sd);
void imx_media_remove_ipu_internal_subdevs(struct imx_media_dev *imxmd);
+1 −1
Original line number Diff line number Diff line
@@ -1271,7 +1271,7 @@ static int imx7_csi_probe(struct platform_device *pdev)
	platform_set_drvdata(pdev, &csi->sd);

	ret = imx_media_of_add_csi(imxmd, node);
	if (ret < 0)
	if (ret < 0 && ret != -ENODEV && ret != -EEXIST)
		goto cleanup;

	ret = imx_media_dev_notifier_register(imxmd);