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.za...@pengutronix.de>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to