File Index
Files and directories
Sign in
FILE

video.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/media/tegra-video/video.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2020 NVIDIA CORPORATION.  All rights reserved.
  4 */
  5
  6#include <linux/host1x.h>
  7#include <linux/module.h>
  8#include <linux/platform_device.h>
  9
 10#include <media/v4l2-event.h>
 11
 12#include "video.h"
 13
 14static void tegra_v4l2_dev_release(struct v4l2_device *v4l2_dev)
 15{
 16	struct tegra_video_device *vid;
 17
 18	vid = container_of(v4l2_dev, struct tegra_video_device, v4l2_dev);
 19
 20	/* cleanup channels here as all video device nodes are released */
 21	tegra_channels_cleanup(vid->vi);
 22
 23	v4l2_device_unregister(v4l2_dev);
 24	media_device_unregister(&vid->media_dev);
 25	media_device_cleanup(&vid->media_dev);
 26	kfree(vid);
 27}
 28
 29static void tegra_v4l2_dev_notify(struct v4l2_subdev *sd,
 30				  unsigned int notification, void *arg)
 31{
 32	struct tegra_vi_channel *chan;
 33	const struct v4l2_event *ev = arg;
 34
 35	if (notification != V4L2_DEVICE_NOTIFY_EVENT)
 36		return;
 37
 38	chan = v4l2_get_subdev_hostdata(sd);
 39	v4l2_event_queue(&chan->video, arg);
 40	if (ev->type == V4L2_EVENT_SOURCE_CHANGE && vb2_is_streaming(&chan->queue))
 41		vb2_queue_error(&chan->queue);
 42}
 43
 44static int host1x_video_probe(struct host1x_device *dev)
 45{
 46	struct tegra_video_device *vid;
 47	int ret;
 48
 49	vid = kzalloc(sizeof(*vid), GFP_KERNEL);
 50	if (!vid)
 51		return -ENOMEM;
 52
 53	dev_set_drvdata(&dev->dev, vid);
 54
 55	vid->media_dev.dev = &dev->dev;
 56	strscpy(vid->media_dev.model, "NVIDIA Tegra Video Input Device",
 57		sizeof(vid->media_dev.model));
 58
 59	media_device_init(&vid->media_dev);
 60	ret = media_device_register(&vid->media_dev);
 61	if (ret < 0) {
 62		dev_err(&dev->dev,
 63			"failed to register media device: %d\n", ret);
 64		goto cleanup;
 65	}
 66
 67	vid->v4l2_dev.mdev = &vid->media_dev;
 68	vid->v4l2_dev.release = tegra_v4l2_dev_release;
 69	vid->v4l2_dev.notify = tegra_v4l2_dev_notify;
 70	ret = v4l2_device_register(&dev->dev, &vid->v4l2_dev);
 71	if (ret < 0) {
 72		dev_err(&dev->dev,
 73			"V4L2 device registration failed: %d\n", ret);
 74		goto unregister_media;
 75	}
 76
 77	ret = host1x_device_init(dev);
 78	if (ret < 0)
 79		goto unregister_v4l2;
 80
 81	if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)) {
 82		/*
 83		 * Both vi and csi channels are available now.
 84		 * Register v4l2 nodes and create media links for TPG.
 85		 */
 86		ret = tegra_v4l2_nodes_setup_tpg(vid);
 87		if (ret < 0) {
 88			dev_err(&dev->dev,
 89				"failed to setup tpg graph: %d\n", ret);
 90			goto device_exit;
 91		}
 92	}
 93
 94	return 0;
 95
 96device_exit:
 97	host1x_device_exit(dev);
 98	/* vi exit ops does not clean channels, so clean them here */
 99	tegra_channels_cleanup(vid->vi);
100unregister_v4l2:
101	v4l2_device_unregister(&vid->v4l2_dev);
102unregister_media:
103	media_device_unregister(&vid->media_dev);
104cleanup:
105	media_device_cleanup(&vid->media_dev);
106	kfree(vid);
107	return ret;
108}
109
110static int host1x_video_remove(struct host1x_device *dev)
111{
112	struct tegra_video_device *vid = dev_get_drvdata(&dev->dev);
113
114	if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
115		tegra_v4l2_nodes_cleanup_tpg(vid);
116
117	host1x_device_exit(dev);
118
119	/* This calls v4l2_dev release callback on last reference */
120	v4l2_device_put(&vid->v4l2_dev);
121
122	return 0;
123}
124
125static const struct of_device_id host1x_video_subdevs[] = {
126#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
127	{ .compatible = "nvidia,tegra20-vip", },
128	{ .compatible = "nvidia,tegra20-vi", },
129#endif
130#if defined(CONFIG_ARCH_TEGRA_210_SOC)
131	{ .compatible = "nvidia,tegra210-csi", },
132	{ .compatible = "nvidia,tegra210-vi", },
133#endif
134	{ }
135};
136
137static struct host1x_driver host1x_video_driver = {
138	.driver = {
139		.name = "tegra-video",
140	},
141	.probe = host1x_video_probe,
142	.remove = host1x_video_remove,
143	.subdevs = host1x_video_subdevs,
144};
145
146static struct platform_driver * const drivers[] = {
147	&tegra_csi_driver,
148	&tegra_vip_driver,
149	&tegra_vi_driver,
150};
151
152static int __init host1x_video_init(void)
153{
154	int err;
155
156	err = host1x_driver_register(&host1x_video_driver);
157	if (err < 0)
158		return err;
159
160	err = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
161	if (err < 0)
162		goto unregister_host1x;
163
164	return 0;
165
166unregister_host1x:
167	host1x_driver_unregister(&host1x_video_driver);
168	return err;
169}
170module_init(host1x_video_init);
171
172static void __exit host1x_video_exit(void)
173{
174	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
175	host1x_driver_unregister(&host1x_video_driver);
176}
177module_exit(host1x_video_exit);
178
179MODULE_AUTHOR("Sowjanya Komatineni <skomatineni@nvidia.com>");
180MODULE_DESCRIPTION("NVIDIA Tegra Host1x Video driver");
181MODULE_LICENSE("GPL v2");
~/ Read-only file preview.