On Media Controller enabled systems this patch allows the user to
communicate with the driver directly over /dev/v4l-subdev* device nodes
using VIDIOC_SUBDEV_* ioctl()s.

Signed-off-by: Guennadi Liakhovetski <g.liakhovet...@gmx.de>
---
 drivers/media/video/imx074.c |   85 +++++++++++++++++++++++++++++++++++++-----
 1 files changed, 75 insertions(+), 10 deletions(-)

diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c
index 8775e26..9745887 100644
--- a/drivers/media/video/imx074.c
+++ b/drivers/media/video/imx074.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
+#include <media/media-entity.h>
 #include <media/soc_camera.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-chip-ident.h>
@@ -75,6 +76,7 @@ struct imx074_datafmt {
 
 struct imx074 {
        struct v4l2_subdev              subdev;
+       struct media_pad                pad;
        const struct imx074_datafmt     *fmt;
 };
 
@@ -172,8 +174,7 @@ static int imx074_try_fmt(struct v4l2_subdev *sd,
 static int imx074_s_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct imx074 *priv = to_imx074(client);
+       struct imx074 *priv = container_of(sd, struct imx074, subdev);
 
        dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
 
@@ -191,9 +192,7 @@ static int imx074_s_fmt(struct v4l2_subdev *sd,
 static int imx074_g_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct imx074 *priv = to_imx074(client);
-
+       struct imx074 *priv = container_of(sd, struct imx074, subdev);
        const struct imx074_datafmt *fmt = priv->fmt;
 
        mf->code        = fmt->code;
@@ -293,9 +292,62 @@ static struct v4l2_subdev_core_ops imx074_subdev_core_ops 
= {
        .g_chip_ident   = imx074_g_chip_ident,
 };
 
+static int imx074_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh 
*fh,
+                                struct v4l2_subdev_mbus_code_enum *ce)
+{
+       if (ce->index >= ARRAY_SIZE(imx074_colour_fmts))
+               return -EINVAL;
+
+       ce->code = imx074_colour_fmts[ce->index].code;
+       return 0;
+}
+
+static int imx074_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *sd_fmt)
+{
+       struct v4l2_mbus_framefmt *mf;
+
+       if (sd_fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               return imx074_g_fmt(sd, &sd_fmt->format);
+
+       mf = v4l2_subdev_get_try_format(fh, sd_fmt->pad);
+       sd_fmt->format = *mf;
+       return 0;
+}
+
+static int imx074_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *sd_fmt)
+{
+       struct v4l2_mbus_framefmt *mf;
+
+       if (sd_fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               return imx074_s_fmt(sd, &sd_fmt->format);
+
+       mf = v4l2_subdev_get_try_format(fh, sd_fmt->pad);
+       *mf = sd_fmt->format;
+       return imx074_try_fmt(sd, mf);
+}
+
+struct v4l2_subdev_pad_ops imx074_subdev_pad_ops = {
+       .enum_mbus_code = imx074_enum_mbus_code,
+       .get_fmt        = imx074_get_fmt,
+       .set_fmt        = imx074_set_fmt,
+};
+
 static struct v4l2_subdev_ops imx074_subdev_ops = {
        .core   = &imx074_subdev_core_ops,
        .video  = &imx074_subdev_video_ops,
+       .pad    = &imx074_subdev_pad_ops,
+};
+
+static int imx074_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0);
+       return mf ? imx074_try_fmt(sd, mf) : 0;
+}
+
+static const struct v4l2_subdev_internal_ops imx074_subdev_internal_ops = {
+       .open = imx074_open,
 };
 
 static int imx074_video_probe(struct i2c_client *client)
@@ -427,16 +479,27 @@ static int imx074_probe(struct i2c_client *client,
        if (!priv)
                return -ENOMEM;
 
+       priv->fmt = &imx074_colour_fmts[0];
+
        v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops);
+       priv->subdev.internal_ops = &imx074_subdev_internal_ops;
+       priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
-       priv->fmt       = &imx074_colour_fmts[0];
+       priv->pad.flags = MEDIA_PAD_FL_SOURCE;
+       ret = subdev_media_entity_init(&priv->subdev, 1, &priv->pad, 0);
+       if (ret < 0)
+               goto emeinit;
 
        ret = imx074_video_probe(client);
-       if (ret < 0) {
-               kfree(priv);
-               return ret;
-       }
+       if (ret < 0)
+               goto evprobe;
+
+       return ret;
 
+evprobe:
+       subdev_media_entity_cleanup(&priv->subdev);
+emeinit:
+       kfree(priv);
        return ret;
 }
 
@@ -447,6 +510,8 @@ static int imx074_remove(struct i2c_client *client)
 
        if (icl->free_bus)
                icl->free_bus(icl);
+       v4l2_device_unregister_subdev(&priv->subdev);
+       subdev_media_entity_cleanup(&priv->subdev);
        kfree(priv);
 
        return 0;
-- 
1.7.2.5

--
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