From 06cd9857f8faa63321506a75988c475906a32970 Mon Sep 17 00:00:00 2001
From: Kieran Bingham <kieran.bingham@ideasonboard.com>
Date: Wed, 20 Mar 2019 12:54:47 +0000
Subject: [PATCH] media: bcm2835: unicam: add media controller support

Add a media controller device node to represent the Unicam device.
The attached sensor will be automatically added to the media graph by
V4L2 core.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 drivers/media/platform/bcm2835/Kconfig        |  2 +-
 .../media/platform/bcm2835/bcm2835-unicam.c   | 46 ++++++++++++++++++-
 2 files changed, 45 insertions(+), 3 deletions(-)

--- a/drivers/media/platform/bcm2835/Kconfig
+++ b/drivers/media/platform/bcm2835/Kconfig
@@ -2,7 +2,7 @@
 
 config VIDEO_BCM2835_UNICAM
 	tristate "Broadcom BCM2835 Unicam video capture driver"
-	depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+	depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
 	depends on ARCH_BCM2835 || COMPILE_TEST
 	select VIDEOBUF2_DMA_CONTIG
 	select V4L2_FWNODE
--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
@@ -314,6 +314,9 @@ struct unicam_device {
 	struct clk *clock;
 	/* V4l2 device */
 	struct v4l2_device v4l2_dev;
+	struct media_device mdev;
+	struct media_pad pad;
+
 	/* parent device */
 	struct platform_device *pdev;
 	/* subdevice async Notifier */
@@ -1912,6 +1915,8 @@ static int unicam_probe_complete(struct
 		unicam->v4l2_dev.ctrl_handler = NULL;
 
 	video_set_drvdata(vdev, unicam);
+	vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
+
 	ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
 	if (ret) {
 		unicam_err(unicam, "Unable to register video device.\n");
@@ -1953,6 +1958,16 @@ static int unicam_probe_complete(struct
 		return ret;
 	}
 
+	ret = media_create_pad_link(&unicam->sensor->entity, 0,
+				    &unicam->video_dev.entity, 0,
+				    MEDIA_LNK_FL_ENABLED |
+				    MEDIA_LNK_FL_IMMUTABLE);
+	if (ret) {
+		unicam_err(unicam, "Unable to create pad links.\n");
+		video_unregister_device(&unicam->video_dev);
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -2155,18 +2170,38 @@ static int unicam_probe(struct platform_
 		return -EINVAL;
 	}
 
+	unicam->mdev.dev = &pdev->dev;
+	strscpy(unicam->mdev.model, UNICAM_MODULE_NAME,
+		sizeof(unicam->mdev.model));
+	strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial));
+	snprintf(unicam->mdev.bus_info, sizeof(unicam->mdev.bus_info),
+		 "platform:%s", pdev->name);
+	unicam->mdev.hw_revision = 1;
+
+	media_entity_pads_init(&unicam->video_dev.entity, 1, &unicam->pad);
+	media_device_init(&unicam->mdev);
+
+	unicam->v4l2_dev.mdev = &unicam->mdev;
+
 	ret = v4l2_device_register(&pdev->dev, &unicam->v4l2_dev);
 	if (ret) {
 		unicam_err(unicam,
 			   "Unable to register v4l2 device.\n");
-		return ret;
+		goto media_cleanup;
+	}
+
+	ret = media_device_register(&unicam->mdev);
+	if (ret < 0) {
+		unicam_err(unicam,
+			   "Unable to register media-controller device.\n");
+		goto probe_out_v4l2_unregister;
 	}
 
 	/* Reserve space for the controls */
 	hdl = &unicam->ctrl_handler;
 	ret = v4l2_ctrl_handler_init(hdl, 16);
 	if (ret < 0)
-		goto probe_out_v4l2_unregister;
+		goto media_unregister;
 	unicam->v4l2_dev.ctrl_handler = hdl;
 
 	/* set the driver data in platform device */
@@ -2185,8 +2220,13 @@ static int unicam_probe(struct platform_
 
 free_hdl:
 	v4l2_ctrl_handler_free(hdl);
+media_unregister:
+	media_device_unregister(&unicam->mdev);
 probe_out_v4l2_unregister:
 	v4l2_device_unregister(&unicam->v4l2_dev);
+media_cleanup:
+	media_device_cleanup(&unicam->mdev);
+
 	return ret;
 }
 
@@ -2204,6 +2244,8 @@ static int unicam_remove(struct platform
 	video_unregister_device(&unicam->video_dev);
 	if (unicam->sensor_config)
 		v4l2_subdev_free_pad_config(unicam->sensor_config);
+	media_device_unregister(&unicam->mdev);
+	media_device_cleanup(&unicam->mdev);
 
 	return 0;
 }