media: Allow drivers to be built without V4L2

When building the NVIDIA out-of-tree drivers against 3rd party Linux
kernels where V4L2 support is not be enabled by default, the camera
drivers fail to build. Although this is expected, it is preferred that
the driver can still be built but then fail when loaded. Update the
camera drivers to guard around the V4L2 functions so that the drivers
can still be built but will return an error where needed.

Bug 4119327

Change-Id: I3a1115e5f0451153831c396244c01d7525cb51a1
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2979254
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Jon Hunter
2023-09-12 16:45:47 +01:00
committed by mobile promotions
parent 84302c4c14
commit 79e8e9cf3a
6 changed files with 74 additions and 1 deletions

View File

@@ -1,5 +1,18 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
ifdef CONFIG_V4L2_ASYNC
subdir-ccflags-y += -DCONFIG_V4L2_ASYNC
endif
ifdef CONFIG_V4L2_FWNODE
subdir-ccflags-y += -DCONFIG_V4L2_FWNODE
endif
ifdef CONFIG_VIDEOBUF2_DMA_CONTIG
subdir-ccflags-y += -DCONFIG_VIDEOBUF2_DMA_CONTIG
endif
obj-m += i2c/
obj-m += platform/

View File

@@ -2757,9 +2757,14 @@ static int cam_probe(struct i2c_client *client,
}
#endif
#if defined(CONFIG_V4L2_ASYNC)
err = v4l2_async_register_subdev(priv->subdev);
if (err)
goto exit;
#else
dev_err(&client->dev, "CONFIG_V4L2_ASYNC not enabled!\n");
return -ENOTSUPP;
#endif
dev_info(&client->dev, "Detected ar1335 sensor\n");
@@ -2832,7 +2837,9 @@ static void cam_remove(struct i2c_client *client)
return;
#endif
#if defined(CONFIG_V4L2_ASYNC)
v4l2_async_unregister_subdev(priv->subdev);
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&priv->subdev->entity);
#endif

View File

@@ -56,10 +56,15 @@ int tegra_vb2_dma_init(struct device *dev, void **alloc_ctx,
if (atomic_inc_return(refcount) > 1)
return 0;
#if defined(CONFIG_VIDEOBUF2_DMA_CONTIG)
if (vb2_dma_contig_set_max_seg_size(dev, SZ_64K)) {
dev_err(dev, "failed to init vb2 buffer\n");
ret = -ENOMEM;
}
#else
dev_err(dev, "CONFIG_VIDEOBUF2_DMA_CONTIG is not enabled!\n");
ret = -ENOTSUPP;
#endif
return ret;
}
EXPORT_SYMBOL(tegra_vb2_dma_init);

View File

@@ -940,11 +940,16 @@ static int tegra_csi_channel_init_one(struct tegra_csi_channel *chan)
}
if (!chan->pg_mode) {
#if defined(CONFIG_V4L2_ASYNC)
ret = v4l2_async_register_subdev(sd);
if (ret < 0) {
dev_err(csi->dev, "failed to register subdev\n");
media_entity_cleanup(&sd->entity);
}
#else
dev_err(csi->dev, "CONFIG_V4L2_ASYNC not enabled!\n");
return -ENOTSUPP;
#endif
}
return ret;
}
@@ -1151,7 +1156,9 @@ int tegra_csi_media_controller_remove(struct tegra_csi_device *csi)
list_for_each_entry(chan, &csi->csi_chans, list) {
sd = &chan->subdev;
#if defined(CONFIG_V4L2_ASYNC)
v4l2_async_unregister_subdev(sd);
#endif
media_entity_cleanup(&sd->entity);
}
return 0;

View File

@@ -229,7 +229,11 @@ int tegracam_v4l2subdev_register(struct tegracam_device *tc_dev,
}
#endif
#if defined(CONFIG_V4L2_ASYNC)
return v4l2_async_register_subdev(sd);
#else
return -ENOTSUPP;
#endif
}
EXPORT_SYMBOL_GPL(tegracam_v4l2subdev_register);
@@ -244,7 +248,9 @@ void tegracam_v4l2subdev_unregister(struct tegracam_device *tc_dev)
sd = &s_data->subdev;
v4l2_ctrl_handler_free(s_data->ctrl_handler);
#if defined(CONFIG_V4L2_ASYNC)
v4l2_async_unregister_subdev(sd);
#endif
#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&sd->entity);
#endif

View File

@@ -76,7 +76,12 @@ static int tegra_vi_graph_build_one(struct tegra_channel *chan,
dev_dbg(chan->vi->dev, "processing endpoint %pOF\n",
ep);
#if defined(CONFIG_V4L2_FWNODE)
ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
#else
dev_err(chan->vi->dev, "CONFIG_V4L2_FWNODE not enabled!\n");
ret = -ENOTSUPP;
#endif
if (ret < 0) {
dev_err(chan->vi->dev,
"failed to parse link for %pOF\n", ep);
@@ -87,7 +92,9 @@ static int tegra_vi_graph_build_one(struct tegra_channel *chan,
dev_err(chan->vi->dev,
"invalid port number %u for %pOF\n",
link.local_port, to_of_node(link.local_node));
#if defined(CONFIG_V4L2_FWNODE)
v4l2_fwnode_put_link(&link);
#endif
ret = -EINVAL;
break;
}
@@ -100,7 +107,9 @@ static int tegra_vi_graph_build_one(struct tegra_channel *chan,
if (local_pad->flags & MEDIA_PAD_FL_SINK) {
dev_dbg(chan->vi->dev, "skipping sink port %pOF:%u\n",
to_of_node(link.local_node), link.local_port);
#if defined(CONFIG_V4L2_FWNODE)
v4l2_fwnode_put_link(&link);
#endif
continue;
}
@@ -108,7 +117,9 @@ static int tegra_vi_graph_build_one(struct tegra_channel *chan,
if (link.remote_node == of_fwnode_handle(chan->vi->dev->of_node)) {
dev_dbg(chan->vi->dev, "skipping channel port %pOF:%u\n",
to_of_node(link.local_node), link.local_port);
#if defined(CONFIG_V4L2_FWNODE)
v4l2_fwnode_put_link(&link);
#endif
continue;
}
@@ -117,7 +128,9 @@ static int tegra_vi_graph_build_one(struct tegra_channel *chan,
if (ent == NULL) {
dev_err(chan->vi->dev, "no entity found for %pOF\n",
to_of_node(link.remote_node));
#if defined(CONFIG_V4L2_FWNODE)
v4l2_fwnode_put_link(&link);
#endif
ret = -EINVAL;
break;
}
@@ -127,14 +140,18 @@ static int tegra_vi_graph_build_one(struct tegra_channel *chan,
if (link.remote_port >= remote->num_pads) {
dev_err(chan->vi->dev, "invalid port number %u on %pOF\n",
link.remote_port, to_of_node(link.remote_node));
#if defined(CONFIG_V4L2_FWNODE)
v4l2_fwnode_put_link(&link);
#endif
ret = -EINVAL;
break;
}
remote_pad = &remote->pads[link.remote_port];
#if defined(CONFIG_V4L2_FWNODE)
v4l2_fwnode_put_link(&link);
#endif
/* Create the media link. */
dev_dbg(chan->vi->dev, "creating %s:%u -> %s:%u link\n",
@@ -176,17 +193,24 @@ static int tegra_vi_graph_build_links(struct tegra_channel *chan)
ep = chan->endpoint_node;
dev_dbg(chan->vi->dev, "processing endpoint %pOF\n", ep);
#if defined(CONFIG_V4L2_FWNODE)
ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
#else
dev_err(chan->vi->dev, "CONFIG_V4L2_FWNODE not enabled!\n");
ret = -ENOTSUPP;
#endif
if (ret < 0) {
dev_err(chan->vi->dev, "failed to parse link for %pOF\n",
ep);
return -EINVAL;
return ret;
}
if (link.local_port >= chan->vi->num_channels) {
dev_err(chan->vi->dev, "wrong channel number for port %u\n",
link.local_port);
#if defined(CONFIG_V4L2_FWNODE)
v4l2_fwnode_put_link(&link);
#endif
return -EINVAL;
}
@@ -205,7 +229,9 @@ static int tegra_vi_graph_build_links(struct tegra_channel *chan)
if (ent->entity == NULL) {
dev_err(chan->vi->dev, "entity not bounded %pOF\n",
to_of_node(link.remote_node));
#if defined(CONFIG_V4L2_FWNODE)
v4l2_fwnode_put_link(&link);
#endif
return -EINVAL;
}
@@ -214,7 +240,9 @@ static int tegra_vi_graph_build_links(struct tegra_channel *chan)
sink = &chan->video->entity;
sink_pad = &chan->pad;
#if defined(CONFIG_V4L2_FWNODE)
v4l2_fwnode_put_link(&link);
#endif
/* Create the media link. */
dev_dbg(chan->vi->dev, "creating %s:%u -> %s:%u link\n",
@@ -382,10 +410,12 @@ void tegra_vi_graph_cleanup(struct tegra_mc_vi *vi)
struct tegra_channel *chan;
list_for_each_entry(chan, &vi->vi_chans, list) {
#if defined(CONFIG_V4L2_ASYNC)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)
v4l2_async_notifier_unregister(&chan->notifier);
#else
v4l2_async_nf_unregister(&chan->notifier);
#endif
#endif
list_for_each_entry_safe(entity, entityp,
&chan->entities, list) {
@@ -613,6 +643,7 @@ int tegra_vi_graph_init(struct tegra_mc_vi *vi)
num_subdevs = chan->num_subdevs;
i = 0;
#if defined(CONFIG_V4L2_ASYNC)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)
v4l2_async_notifier_init(&chan->notifier);
list_for_each_entry(entity, &chan->entities, list)
@@ -633,6 +664,10 @@ int tegra_vi_graph_init(struct tegra_mc_vi *vi)
#else
ret = v4l2_async_nf_register(&vi->v4l2_dev,
&chan->notifier);
#endif
#else
dev_err(vi->dev, "CONFIG_V4L2_ASYNC is not enabled!\n");
ret = -ENOTSUPP;
#endif
if (ret < 0) {
dev_err(vi->dev, "notifier registration failed\n");