Merge tag 'drivers-5.10-2020-10-12' of git://git.kernel.dk/linux-block
[linux-2.6-block.git] / drivers / staging / media / tegra-video / video.c
CommitLineData
3d8a97ea
SK
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 "video.h"
11
12static void tegra_v4l2_dev_release(struct v4l2_device *v4l2_dev)
13{
14 struct tegra_video_device *vid;
15
16 vid = container_of(v4l2_dev, struct tegra_video_device, v4l2_dev);
17
18 /* cleanup channels here as all video device nodes are released */
19 tegra_channels_cleanup(vid->vi);
20
21 v4l2_device_unregister(v4l2_dev);
22 media_device_unregister(&vid->media_dev);
23 media_device_cleanup(&vid->media_dev);
24 kfree(vid);
25}
26
27static int host1x_video_probe(struct host1x_device *dev)
28{
29 struct tegra_video_device *vid;
30 int ret;
31
32 vid = kzalloc(sizeof(*vid), GFP_KERNEL);
33 if (!vid)
34 return -ENOMEM;
35
36 dev_set_drvdata(&dev->dev, vid);
37
38 vid->media_dev.dev = &dev->dev;
39 strscpy(vid->media_dev.model, "NVIDIA Tegra Video Input Device",
40 sizeof(vid->media_dev.model));
41
42 media_device_init(&vid->media_dev);
43 ret = media_device_register(&vid->media_dev);
44 if (ret < 0) {
45 dev_err(&dev->dev,
46 "failed to register media device: %d\n", ret);
47 goto cleanup;
48 }
49
50 vid->v4l2_dev.mdev = &vid->media_dev;
51 vid->v4l2_dev.release = tegra_v4l2_dev_release;
52 ret = v4l2_device_register(&dev->dev, &vid->v4l2_dev);
53 if (ret < 0) {
54 dev_err(&dev->dev,
55 "V4L2 device registration failed: %d\n", ret);
56 goto unregister_media;
57 }
58
59 ret = host1x_device_init(dev);
60 if (ret < 0)
61 goto unregister_v4l2;
62
341187bf
SK
63 if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)) {
64 /*
65 * Both vi and csi channels are available now.
66 * Register v4l2 nodes and create media links for TPG.
67 */
68 ret = tegra_v4l2_nodes_setup_tpg(vid);
69 if (ret < 0) {
70 dev_err(&dev->dev,
71 "failed to setup tpg graph: %d\n", ret);
72 goto device_exit;
73 }
3d8a97ea
SK
74 }
75
76 return 0;
77
78device_exit:
79 host1x_device_exit(dev);
80 /* vi exit ops does not clean channels, so clean them here */
81 tegra_channels_cleanup(vid->vi);
82unregister_v4l2:
83 v4l2_device_unregister(&vid->v4l2_dev);
84unregister_media:
85 media_device_unregister(&vid->media_dev);
86cleanup:
87 media_device_cleanup(&vid->media_dev);
88 kfree(vid);
89 return ret;
90}
91
92static int host1x_video_remove(struct host1x_device *dev)
93{
94 struct tegra_video_device *vid = dev_get_drvdata(&dev->dev);
95
341187bf
SK
96 if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
97 tegra_v4l2_nodes_cleanup_tpg(vid);
3d8a97ea
SK
98
99 host1x_device_exit(dev);
100
101 /* This calls v4l2_dev release callback on last reference */
102 v4l2_device_put(&vid->v4l2_dev);
103
104 return 0;
105}
106
107static const struct of_device_id host1x_video_subdevs[] = {
108#if defined(CONFIG_ARCH_TEGRA_210_SOC)
109 { .compatible = "nvidia,tegra210-csi", },
110 { .compatible = "nvidia,tegra210-vi", },
111#endif
112 { }
113};
114
115static struct host1x_driver host1x_video_driver = {
116 .driver = {
117 .name = "tegra-video",
118 },
119 .probe = host1x_video_probe,
120 .remove = host1x_video_remove,
121 .subdevs = host1x_video_subdevs,
122};
123
124static struct platform_driver * const drivers[] = {
125 &tegra_csi_driver,
126 &tegra_vi_driver,
127};
128
129static int __init host1x_video_init(void)
130{
131 int err;
132
133 err = host1x_driver_register(&host1x_video_driver);
134 if (err < 0)
135 return err;
136
137 err = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
138 if (err < 0)
139 goto unregister_host1x;
140
141 return 0;
142
143unregister_host1x:
144 host1x_driver_unregister(&host1x_video_driver);
145 return err;
146}
147module_init(host1x_video_init);
148
149static void __exit host1x_video_exit(void)
150{
151 platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
152 host1x_driver_unregister(&host1x_video_driver);
153}
154module_exit(host1x_video_exit);
155
156MODULE_AUTHOR("Sowjanya Komatineni <skomatineni@nvidia.com>");
157MODULE_DESCRIPTION("NVIDIA Tegra Host1x Video driver");
158MODULE_LICENSE("GPL v2");