Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2020 NVIDIA CORPORATION.  All rights reserved.
0004  */
0005 
0006 #include <linux/host1x.h>
0007 #include <linux/module.h>
0008 #include <linux/platform_device.h>
0009 
0010 #include <media/v4l2-event.h>
0011 
0012 #include "video.h"
0013 
0014 static void tegra_v4l2_dev_release(struct v4l2_device *v4l2_dev)
0015 {
0016     struct tegra_video_device *vid;
0017 
0018     vid = container_of(v4l2_dev, struct tegra_video_device, v4l2_dev);
0019 
0020     /* cleanup channels here as all video device nodes are released */
0021     tegra_channels_cleanup(vid->vi);
0022 
0023     v4l2_device_unregister(v4l2_dev);
0024     media_device_unregister(&vid->media_dev);
0025     media_device_cleanup(&vid->media_dev);
0026     kfree(vid);
0027 }
0028 
0029 static void tegra_v4l2_dev_notify(struct v4l2_subdev *sd,
0030                   unsigned int notification, void *arg)
0031 {
0032     struct tegra_vi_channel *chan;
0033     const struct v4l2_event *ev = arg;
0034 
0035     if (notification != V4L2_DEVICE_NOTIFY_EVENT)
0036         return;
0037 
0038     chan = v4l2_get_subdev_hostdata(sd);
0039     v4l2_event_queue(&chan->video, arg);
0040     if (ev->type == V4L2_EVENT_SOURCE_CHANGE && vb2_is_streaming(&chan->queue))
0041         vb2_queue_error(&chan->queue);
0042 }
0043 
0044 static int host1x_video_probe(struct host1x_device *dev)
0045 {
0046     struct tegra_video_device *vid;
0047     int ret;
0048 
0049     vid = kzalloc(sizeof(*vid), GFP_KERNEL);
0050     if (!vid)
0051         return -ENOMEM;
0052 
0053     dev_set_drvdata(&dev->dev, vid);
0054 
0055     vid->media_dev.dev = &dev->dev;
0056     strscpy(vid->media_dev.model, "NVIDIA Tegra Video Input Device",
0057         sizeof(vid->media_dev.model));
0058 
0059     media_device_init(&vid->media_dev);
0060     ret = media_device_register(&vid->media_dev);
0061     if (ret < 0) {
0062         dev_err(&dev->dev,
0063             "failed to register media device: %d\n", ret);
0064         goto cleanup;
0065     }
0066 
0067     vid->v4l2_dev.mdev = &vid->media_dev;
0068     vid->v4l2_dev.release = tegra_v4l2_dev_release;
0069     vid->v4l2_dev.notify = tegra_v4l2_dev_notify;
0070     ret = v4l2_device_register(&dev->dev, &vid->v4l2_dev);
0071     if (ret < 0) {
0072         dev_err(&dev->dev,
0073             "V4L2 device registration failed: %d\n", ret);
0074         goto unregister_media;
0075     }
0076 
0077     ret = host1x_device_init(dev);
0078     if (ret < 0)
0079         goto unregister_v4l2;
0080 
0081     if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)) {
0082         /*
0083          * Both vi and csi channels are available now.
0084          * Register v4l2 nodes and create media links for TPG.
0085          */
0086         ret = tegra_v4l2_nodes_setup_tpg(vid);
0087         if (ret < 0) {
0088             dev_err(&dev->dev,
0089                 "failed to setup tpg graph: %d\n", ret);
0090             goto device_exit;
0091         }
0092     }
0093 
0094     return 0;
0095 
0096 device_exit:
0097     host1x_device_exit(dev);
0098     /* vi exit ops does not clean channels, so clean them here */
0099     tegra_channels_cleanup(vid->vi);
0100 unregister_v4l2:
0101     v4l2_device_unregister(&vid->v4l2_dev);
0102 unregister_media:
0103     media_device_unregister(&vid->media_dev);
0104 cleanup:
0105     media_device_cleanup(&vid->media_dev);
0106     kfree(vid);
0107     return ret;
0108 }
0109 
0110 static int host1x_video_remove(struct host1x_device *dev)
0111 {
0112     struct tegra_video_device *vid = dev_get_drvdata(&dev->dev);
0113 
0114     if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
0115         tegra_v4l2_nodes_cleanup_tpg(vid);
0116 
0117     host1x_device_exit(dev);
0118 
0119     /* This calls v4l2_dev release callback on last reference */
0120     v4l2_device_put(&vid->v4l2_dev);
0121 
0122     return 0;
0123 }
0124 
0125 static const struct of_device_id host1x_video_subdevs[] = {
0126 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
0127     { .compatible = "nvidia,tegra210-csi", },
0128     { .compatible = "nvidia,tegra210-vi", },
0129 #endif
0130     { }
0131 };
0132 
0133 static struct host1x_driver host1x_video_driver = {
0134     .driver = {
0135         .name = "tegra-video",
0136     },
0137     .probe = host1x_video_probe,
0138     .remove = host1x_video_remove,
0139     .subdevs = host1x_video_subdevs,
0140 };
0141 
0142 static struct platform_driver * const drivers[] = {
0143     &tegra_csi_driver,
0144     &tegra_vi_driver,
0145 };
0146 
0147 static int __init host1x_video_init(void)
0148 {
0149     int err;
0150 
0151     err = host1x_driver_register(&host1x_video_driver);
0152     if (err < 0)
0153         return err;
0154 
0155     err = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
0156     if (err < 0)
0157         goto unregister_host1x;
0158 
0159     return 0;
0160 
0161 unregister_host1x:
0162     host1x_driver_unregister(&host1x_video_driver);
0163     return err;
0164 }
0165 module_init(host1x_video_init);
0166 
0167 static void __exit host1x_video_exit(void)
0168 {
0169     platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
0170     host1x_driver_unregister(&host1x_video_driver);
0171 }
0172 module_exit(host1x_video_exit);
0173 
0174 MODULE_AUTHOR("Sowjanya Komatineni <skomatineni@nvidia.com>");
0175 MODULE_DESCRIPTION("NVIDIA Tegra Host1x Video driver");
0176 MODULE_LICENSE("GPL v2");