[RFC PATCH 14/26] [media] Add i.MX SoC wide media device driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This driver registers a single, SoC wide media device, which all entities
in the media graph can be registered with via OF graph bindings.

Signed-off-by: Philipp Zabel <p.zabel@xxxxxxxxxxxxxx>
---
 drivers/media/platform/Kconfig         |   2 +
 drivers/media/platform/imx/Kconfig     |  13 +++
 drivers/media/platform/imx/Makefile    |   1 +
 drivers/media/platform/imx/imx-media.c | 174 +++++++++++++++++++++++++++++++++
 include/media/imx.h                    |  25 +++++
 5 files changed, 215 insertions(+)
 create mode 100644 drivers/media/platform/imx/imx-media.c
 create mode 100644 include/media/imx.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 8e9c26c..3fe7e28 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -35,6 +35,8 @@ source "drivers/media/platform/omap/Kconfig"
 
 source "drivers/media/platform/blackfin/Kconfig"
 
+source "drivers/media/platform/imx/Kconfig"
+
 config VIDEO_SH_VOU
 	tristate "SuperH VOU video output driver"
 	depends on MEDIA_CAMERA_SUPPORT
diff --git a/drivers/media/platform/imx/Kconfig b/drivers/media/platform/imx/Kconfig
index 506326a..d2f1693 100644
--- a/drivers/media/platform/imx/Kconfig
+++ b/drivers/media/platform/imx/Kconfig
@@ -1,3 +1,16 @@
+config MEDIA_IMX
+	tristate "Multimedia Support for Freescale i.MX"
+	depends on MEDIA_CONTROLLER
+	---help---
+	  This driver provides a SoC wide media controller device that all
+	  multimedia components in i.MX5 and i.MX6 SoCs can register with.
+
+config MEDIA_IMX_IPU
+	tristate "i.MX Image Processing Unit (v3) core driver"
+	---help---
+	  This driver provides core support for the i.MX IPUv3 contained in
+	  i.MX5 and i.MX6 SoCs.
+
 config VIDEO_IMX_IPU_COMMON
 	tristate
 
diff --git a/drivers/media/platform/imx/Makefile b/drivers/media/platform/imx/Makefile
index 5c9da82..60f451a 100644
--- a/drivers/media/platform/imx/Makefile
+++ b/drivers/media/platform/imx/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_MEDIA_IMX)			+= imx-media.o
 obj-$(CONFIG_VIDEO_IMX_IPU_COMMON)	+= imx-ipu.o
 obj-$(CONFIG_VIDEO_IMX_IPU_SCALER)	+= imx-ipu-scaler.o
 obj-$(CONFIG_VIDEO_IMX_IPU_VDIC)	+= imx-ipu-vdic.o
diff --git a/drivers/media/platform/imx/imx-media.c b/drivers/media/platform/imx/imx-media.c
new file mode 100644
index 0000000..ae63c49
--- /dev/null
+++ b/drivers/media/platform/imx/imx-media.c
@@ -0,0 +1,174 @@
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <media/media-device.h>
+#include <media/v4l2-device.h>
+#include <video/imx-ipu-v3.h>
+
+struct ipu_media_controller {
+	struct v4l2_device v4l2_dev;
+	struct media_device mdev;
+};
+
+static struct ipu_media_controller *ipu_media;
+
+struct media_device *ipu_find_media_device(void)
+{
+	return &ipu_media->mdev;
+}
+EXPORT_SYMBOL_GPL(ipu_find_media_device);
+
+struct ipu_media_link {
+	struct v4l2_async_notifier	asn;
+	struct v4l2_async_subdev	asd;
+	struct v4l2_async_subdev	*asdp;
+	struct v4l2_subdev		*sd;
+	int padno;
+	struct device_node		*endpoint;
+	u32				media_link_flags;
+};
+
+static int ipu_media_bound(struct v4l2_async_notifier *notifier,
+			   struct v4l2_subdev *sd,
+			   struct v4l2_async_subdev *asd)
+{
+	struct ipu_media_controller *im = ipu_media;
+	struct ipu_media_link *link = container_of(notifier,
+						   struct ipu_media_link, asn);
+	struct device_node *np, *rp;
+	uint32_t portno = 0;
+	int ret;
+
+	if ((sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) {
+		ret = v4l2_device_register_subdev_node(&im->v4l2_dev, sd);
+		if (ret)
+			return ret;
+	}
+
+	np = link->endpoint;
+	rp = of_graph_get_remote_port(np);
+	of_property_read_u32(rp, "reg", &portno);
+
+	ret = media_entity_create_link(&sd->entity, portno, &link->sd->entity,
+			link->padno, link->media_link_flags);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void ipu_media_unbind(struct v4l2_async_notifier *notifier,
+			     struct v4l2_subdev *sd,
+			     struct v4l2_async_subdev *asd)
+{
+	if ((sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) {
+		video_unregister_device(sd->devnode);
+		kfree(sd->devnode);
+	}
+}
+
+struct ipu_media_link *ipu_media_entity_create_link(struct v4l2_subdev *sd,
+		int padno, struct device_node *endpoint,
+		u32 media_link_flags)
+{
+	struct ipu_media_controller *im = ipu_media;
+	struct ipu_media_link *link;
+	int ret;
+	struct device_node *rpp;
+
+	rpp = of_graph_get_remote_port_parent(endpoint);
+	if (!rpp)
+		return ERR_PTR(-EINVAL);
+
+	pr_info("%s: link on %s pad %d endpoint: %s remotenodeparent: %s\n",
+		__func__, sd->name, padno, endpoint->full_name, rpp->full_name);
+	if (!im)
+		return ERR_PTR(-ENODEV);
+
+	link = kzalloc(sizeof(*link), GFP_KERNEL);
+	if (!link)
+		return ERR_PTR(-ENOMEM);
+
+	link->sd = sd;
+	link->padno = padno;
+	link->endpoint = endpoint;
+	link->media_link_flags = media_link_flags;
+
+	link->asd.match_type = V4L2_ASYNC_MATCH_OF;
+	link->asd.match.of.node = rpp;
+
+	link->asdp = &link->asd;
+
+	link->asn.bound = ipu_media_bound;
+	link->asn.unbind = ipu_media_unbind;
+	link->asn.subdevs = &link->asdp;
+	link->asn.num_subdevs = 1;
+	link->asn.v4l2_dev = &im->v4l2_dev;
+
+	ret = v4l2_async_notifier_register(&im->v4l2_dev, &link->asn);
+	if (ret) {
+		kfree(link);
+		return ERR_PTR(ret);
+	}
+
+	return link;
+}
+EXPORT_SYMBOL_GPL(ipu_media_entity_create_link);
+
+void ipu_media_entity_remove_link(struct ipu_media_link *link)
+{
+	v4l2_async_notifier_unregister(&link->asn);
+
+	kfree(link);
+}
+EXPORT_SYMBOL_GPL(ipu_media_entity_remove_link);
+
+struct v4l2_device *ipu_media_get_v4l2_dev(void)
+{
+	if (!ipu_media)
+		return NULL;
+
+	return &ipu_media->v4l2_dev;
+}
+EXPORT_SYMBOL_GPL(ipu_media_get_v4l2_dev);
+
+int ipu_media_device_register(struct device *dev)
+{
+	struct media_device *mdev;
+	int ret;
+
+	if (ipu_media)
+		return 0;
+
+	ipu_media = devm_kzalloc(dev, sizeof(*ipu_media), GFP_KERNEL);
+	if (!ipu_media)
+		return -ENOMEM;
+
+	mdev = &ipu_media->mdev;
+
+	mdev->dev = dev;
+
+	strlcpy(mdev->model, "i.MX IPUv3", sizeof(mdev->model));
+
+	ret = media_device_register(mdev);
+	if (ret)
+		return ret;
+
+	ipu_media->v4l2_dev.mdev = mdev;
+
+	ret = v4l2_device_register(mdev->dev, &ipu_media->v4l2_dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_media_device_register);
diff --git a/include/media/imx.h b/include/media/imx.h
new file mode 100644
index 0000000..42be5f4
--- /dev/null
+++ b/include/media/imx.h
@@ -0,0 +1,25 @@
+struct v4l2_subdev;
+struct device_node;
+struct ipu_media_link;
+struct v4l2_device;
+struct media_device;
+struct device;
+
+struct ipu_media_link *ipu_media_entity_create_link(struct v4l2_subdev *sd,
+		int padno, struct device_node *remote_node,
+		u32 media_link_flags);
+
+void ipu_media_entity_remove_link(struct ipu_media_link *link);
+
+struct v4l2_device *ipu_media_get_v4l2_dev(void);
+
+struct media_device *ipu_find_media_device(void);
+
+#ifdef CONFIG_MEDIA_IMX
+int ipu_media_device_register(struct device *dev);
+#else
+static inline int ipu_media_device_register(struct device *dev)
+{
+	return 0;
+}
+#endif
-- 
2.0.0.rc2

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux