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.liakhovetski@xxxxxx> --- drivers/media/video/mt9t112.c | 97 ++++++++++++++++++++++++++++++++++------- 1 files changed, 81 insertions(+), 16 deletions(-) diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 32114a3..bb95ad1 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -25,6 +25,7 @@ #include <linux/v4l2-mediabus.h> #include <linux/videodev2.h> +#include <media/media-entity.h> #include <media/mt9t112.h> #include <media/soc_camera.h> #include <media/v4l2-chip-ident.h> @@ -87,6 +88,7 @@ struct mt9t112_format { struct mt9t112_priv { struct v4l2_subdev subdev; + struct media_pad pad; struct mt9t112_camera_info *info; struct i2c_client *client; struct v4l2_rect frame; @@ -739,8 +741,7 @@ static int mt9t112_init_camera(const struct i2c_client *client) static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); + struct mt9t112_priv *priv = container_of(sd, struct mt9t112_priv, subdev); id->ident = priv->model; id->revision = 0; @@ -790,7 +791,7 @@ static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); + struct mt9t112_priv *priv = container_of(sd, struct mt9t112_priv, subdev); int ret = 0; if (!enable) { @@ -888,8 +889,7 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); + struct mt9t112_priv *priv = container_of(sd, struct mt9t112_priv, subdev); a->c = priv->frame; a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -899,8 +899,7 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); + struct mt9t112_priv *priv = container_of(sd, struct mt9t112_priv, subdev); struct v4l2_rect *rect = &a->c; return mt9t112_set_params(priv, rect, priv->format->code); @@ -909,8 +908,7 @@ static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) static int mt9t112_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); + struct mt9t112_priv *priv = container_of(sd, struct mt9t112_priv, subdev); mf->width = priv->frame.width; mf->height = priv->frame.height; @@ -924,8 +922,7 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd, static int mt9t112_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); + struct mt9t112_priv *priv = container_of(sd, struct mt9t112_priv, subdev); struct v4l2_rect rect = { .width = mf->width, .height = mf->height, @@ -996,8 +993,8 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9t112_priv *priv = container_of(sd, struct mt9t112_priv, subdev); struct soc_camera_link *icl = soc_camera_i2c_to_link(client); - struct mt9t112_priv *priv = to_mt9t112(client); if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) priv->flags |= PCLK_RISING; @@ -1018,14 +1015,67 @@ static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { .s_mbus_config = mt9t112_s_mbus_config, }; -/************************************************************************ - i2c driver -************************************************************************/ +static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *ce) +{ + if (ce->index >= ARRAY_SIZE(mt9t112_cfmts)) + return -EINVAL; + + ce->code = mt9t112_cfmts[ce->index].code; + return 0; +} + +static int mt9t112_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 mt9t112_g_fmt(sd, &sd_fmt->format); + + mf = v4l2_subdev_get_try_format(fh, sd_fmt->pad); + sd_fmt->format = *mf; + return 0; +} + +static int mt9t112_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 mt9t112_s_fmt(sd, &sd_fmt->format); + + mf = v4l2_subdev_get_try_format(fh, sd_fmt->pad); + *mf = sd_fmt->format; + return mt9t112_try_fmt(sd, mf); +} + +struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { + .enum_mbus_code = mt9t112_enum_mbus_code, + .get_fmt = mt9t112_get_fmt, + .set_fmt = mt9t112_set_fmt, +}; + static struct v4l2_subdev_ops mt9t112_subdev_ops = { .core = &mt9t112_subdev_core_ops, .video = &mt9t112_subdev_video_ops, + .pad = &mt9t112_subdev_pad_ops, }; +static int mt9t112_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0); + return mf ? mt9t112_try_fmt(sd, mf) : 0; +} + +static const struct v4l2_subdev_internal_ops mt9t112_subdev_internal_ops = { + .open = mt9t112_open, +}; + +/************************************************************************ + i2c driver +************************************************************************/ static int mt9t112_camera_probe(struct i2c_client *client) { struct mt9t112_priv *priv = to_mt9t112(client); @@ -1081,21 +1131,36 @@ static int mt9t112_probe(struct i2c_client *client, priv->info = icl->priv; v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); + priv->subdev.internal_ops = &mt9t112_subdev_internal_ops; + priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + priv->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = subdev_media_entity_init(&priv->subdev, 1, &priv->pad, 0); + if (ret < 0) + goto emeinit; ret = mt9t112_camera_probe(client); if (ret) - kfree(priv); + goto evprobe; /* Cannot fail: using the default supported pixel code */ mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8); return ret; + +evprobe: + subdev_media_entity_cleanup(&priv->subdev); +emeinit: + kfree(priv); + return ret; } static int mt9t112_remove(struct i2c_client *client) { struct mt9t112_priv *priv = to_mt9t112(client); + 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html