From 79e8e9cf3ad9b6b0b32a1d9b48cedfb1576d59e4 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 12 Sep 2023 16:45:47 +0100 Subject: [PATCH] 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 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2979254 Tested-by: mobile promotions Reviewed-by: mobile promotions --- drivers/media/Makefile | 13 +++++++ drivers/media/i2c/ar1335_common.c | 7 ++++ .../tegra/camera/camera_version_utils.c | 5 +++ drivers/media/platform/tegra/camera/csi/csi.c | 7 ++++ .../platform/tegra/camera/tegracam_v4l2.c | 6 +++ .../media/platform/tegra/camera/vi/graph.c | 37 ++++++++++++++++++- 6 files changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 3f292f7e..63451347 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -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/ diff --git a/drivers/media/i2c/ar1335_common.c b/drivers/media/i2c/ar1335_common.c index 7601c11c..f26ac6a3 100644 --- a/drivers/media/i2c/ar1335_common.c +++ b/drivers/media/i2c/ar1335_common.c @@ -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 diff --git a/drivers/media/platform/tegra/camera/camera_version_utils.c b/drivers/media/platform/tegra/camera/camera_version_utils.c index 40488d18..c581e65a 100644 --- a/drivers/media/platform/tegra/camera/camera_version_utils.c +++ b/drivers/media/platform/tegra/camera/camera_version_utils.c @@ -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); diff --git a/drivers/media/platform/tegra/camera/csi/csi.c b/drivers/media/platform/tegra/camera/csi/csi.c index bbe795b9..0bec4d59 100644 --- a/drivers/media/platform/tegra/camera/csi/csi.c +++ b/drivers/media/platform/tegra/camera/csi/csi.c @@ -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; diff --git a/drivers/media/platform/tegra/camera/tegracam_v4l2.c b/drivers/media/platform/tegra/camera/tegracam_v4l2.c index ed1d3c2b..02e08610 100644 --- a/drivers/media/platform/tegra/camera/tegracam_v4l2.c +++ b/drivers/media/platform/tegra/camera/tegracam_v4l2.c @@ -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 diff --git a/drivers/media/platform/tegra/camera/vi/graph.c b/drivers/media/platform/tegra/camera/vi/graph.c index 2fd7c2ea..45015fee 100644 --- a/drivers/media/platform/tegra/camera/vi/graph.c +++ b/drivers/media/platform/tegra/camera/vi/graph.c @@ -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");