From 4d066da23979b8de03b5915388136be6e293600f Mon Sep 17 00:00:00 2001
From: Kieran Bingham <kieran.bingham@ideasonboard.com>
Date: Wed, 20 Mar 2019 12:54:15 +0000
Subject: [PATCH] staging: bcm2835-codec: add media controller support

Provide a single media device to contain all of the bcm2835_codec
devices created.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 .../vc04_services/bcm2835-codec/Kconfig       |  2 +-
 .../bcm2835-codec/bcm2835-v4l2-codec.c        | 41 +++++++++++++++++--
 2 files changed, 38 insertions(+), 5 deletions(-)

--- a/drivers/staging/vc04_services/bcm2835-codec/Kconfig
+++ b/drivers/staging/vc04_services/bcm2835-codec/Kconfig
@@ -1,6 +1,6 @@
 config VIDEO_CODEC_BCM2835
 	tristate "BCM2835 Video codec support"
-	depends on MEDIA_SUPPORT
+	depends on MEDIA_SUPPORT && MEDIA_CONTROLLER
 	depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
 	select BCM2835_VCHIQ_MMAL
 	select VIDEOBUF2_DMA_CONTIG
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
@@ -458,6 +458,7 @@ struct bcm2835_codec_ctx {
 
 struct bcm2835_codec_driver {
 	struct platform_device *pdev;
+	struct media_device	mdev;
 
 	struct bcm2835_codec_dev *encode;
 	struct bcm2835_codec_dev *decode;
@@ -2596,6 +2597,7 @@ static int bcm2835_codec_create(struct b
 	struct platform_device *pdev = drv->pdev;
 	struct bcm2835_codec_dev *dev;
 	struct video_device *vfd;
+	int function;
 	int video_nr;
 	int ret;
 
@@ -2615,18 +2617,21 @@ static int bcm2835_codec_create(struct b
 	if (ret)
 		goto vchiq_finalise;
 
-	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
-	if (ret)
-		goto vchiq_finalise;
-
 	atomic_set(&dev->num_inst, 0);
 	mutex_init(&dev->dev_mutex);
 
+	/* Initialise the video device */
 	dev->vfd = bcm2835_codec_videodev;
+
 	vfd = &dev->vfd;
 	vfd->lock = &dev->dev_mutex;
 	vfd->v4l2_dev = &dev->v4l2_dev;
 	vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+	vfd->v4l2_dev->mdev = &drv->mdev;
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret)
+		goto vchiq_finalise;
 
 	switch (role) {
 	case DECODE:
@@ -2634,11 +2639,13 @@ static int bcm2835_codec_create(struct b
 		v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
 		v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
 		v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
+		function = MEDIA_ENT_F_PROC_VIDEO_DECODER;
 		video_nr = decode_video_nr;
 		break;
 	case ENCODE:
 		v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
 		v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
+		function = MEDIA_ENT_F_PROC_VIDEO_ENCODER;
 		video_nr = encode_video_nr;
 		break;
 	case ISP:
@@ -2648,6 +2655,7 @@ static int bcm2835_codec_create(struct b
 		v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
 		v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
 		v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
+		function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
 		video_nr = isp_video_nr;
 		break;
 	default:
@@ -2676,6 +2684,10 @@ static int bcm2835_codec_create(struct b
 		goto err_m2m;
 	}
 
+	ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, function);
+	if (ret)
+		goto err_m2m;
+
 	v4l2_info(&dev->v4l2_dev, "Loaded V4L2 %s\n",
 		  roles[role]);
 	return 0;
@@ -2697,6 +2709,7 @@ static int bcm2835_codec_destroy(struct
 
 	v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME ", %s\n",
 		  roles[dev->role]);
+	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
 	v4l2_m2m_release(dev->m2m_dev);
 	video_unregister_device(&dev->vfd);
 	v4l2_device_unregister(&dev->v4l2_dev);
@@ -2708,6 +2721,7 @@ static int bcm2835_codec_destroy(struct
 static int bcm2835_codec_probe(struct platform_device *pdev)
 {
 	struct bcm2835_codec_driver *drv;
+	struct media_device *mdev;
 	int ret = 0;
 
 	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
@@ -2715,6 +2729,17 @@ static int bcm2835_codec_probe(struct pl
 		return -ENOMEM;
 
 	drv->pdev = pdev;
+	mdev = &drv->mdev;
+	mdev->dev = &pdev->dev;
+
+	strscpy(mdev->model, bcm2835_codec_videodev.name, sizeof(mdev->model));
+	strscpy(mdev->serial, "0000", sizeof(mdev->serial));
+	snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
+		 pdev->name);
+
+	/* This should return the vgencmd version information or such .. */
+	mdev->hw_revision = 1;
+	media_device_init(mdev);
 
 	ret = bcm2835_codec_create(drv, &drv->decode, DECODE);
 	if (ret)
@@ -2728,6 +2753,10 @@ static int bcm2835_codec_probe(struct pl
 	if (ret)
 		goto out;
 
+	/* Register the media device node */
+	if (media_device_register(mdev) < 0)
+		goto out;
+
 	platform_set_drvdata(pdev, drv);
 
 	return 0;
@@ -2748,12 +2777,16 @@ static int bcm2835_codec_remove(struct p
 {
 	struct bcm2835_codec_driver *drv = platform_get_drvdata(pdev);
 
+	media_device_unregister(&drv->mdev);
+
 	bcm2835_codec_destroy(drv->isp);
 
 	bcm2835_codec_destroy(drv->encode);
 
 	bcm2835_codec_destroy(drv->decode);
 
+	media_device_cleanup(&drv->mdev);
+
 	return 0;
 }
 
