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: e130291212df5 ("[media] media: Add i.MX media core driver") Signed-off-by: Steve Longerbeam <slongerbeam@xxxxxxxxx> Cc: stable@xxxxxxxxxxxxxxx --- drivers/staging/media/imx/imx-media-dev.c | 7 -- .../staging/media/imx/imx-media-internal-sd.c | 22 +----- drivers/staging/media/imx/imx-media-of.c | 76 ++++++++++++------- drivers/staging/media/imx/imx-media.h | 3 +- 4 files changed, 53 insertions(+), 55 deletions(-) diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index edf9c80bbbc8..924166cf957b 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -487,13 +487,6 @@ static int imx_media_probe(struct platform_device *pdev) goto notifier_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 notifier_cleanup; - } - /* no subdevs? just bail */ if (list_empty(&imxmd->notifier.asd_list)) { ret = -ENODEV; diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c index b8e763dbbecb..3811c12d475b 100644 --- a/drivers/staging/media/imx/imx-media-internal-sd.c +++ b/drivers/staging/media/imx/imx-media-internal-sd.c @@ -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 @@ -322,25 +323,10 @@ static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id) } if (ret) - return ret; + goto remove; } 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; remove: imx_media_remove_ipu_internal_subdevs(imxmd); diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c index 2da81a5af274..32ed1a99813f 100644 --- a/drivers/staging/media/imx/imx-media-of.c +++ b/drivers/staging/media/imx/imx-media-of.c @@ -20,50 +20,68 @@ #include <video/imx-ipu-v3.h> #include "imx-media.h" -static int 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; - } - - /* 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; -} - 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); if (!csi_np) break; - ret = of_add_csi(imxmd, csi_np); + if (!of_device_is_available(csi_np)) { + /* ignore this CSI if not available */ + of_node_put(csi_np); + continue; + } + + /* 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 */ + 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) + goto err_out; + } + + ipu_found[ipu_id] = true; + of_node_put(csi_np); - if (ret) - return ret; } return 0; + +err_out: + imx_media_remove_ipu_internal_subdevs(imxmd); + of_node_put(csi_np); + return ret; } /* diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index 0f915baeac8a..d2432b8ab67d 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -237,7 +237,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); -- 2.17.1