media: vimc: add test_pattern and h/vflip controls to the sensor
authorHans Verkuil <hverkuil@xs4all.nl>
Mon, 6 Nov 2017 10:20:01 +0000 (05:20 -0500)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Fri, 8 Dec 2017 15:44:55 +0000 (10:44 -0500)
Add support for the test_pattern control and the h/vflip controls.

This makes it possible to switch to more interesting test patterns and to
test control handling in v4l-subdevs.

There are more tpg-related controls that can be added, but this is a good
start.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
[hans.verkuil@cisco.com: fix small whitespace checkpatch warning]
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
drivers/media/platform/vimc/vimc-common.h
drivers/media/platform/vimc/vimc-sensor.c

index dca528a..2e9981b 100644 (file)
 #include <media/media-device.h>
 #include <media/v4l2-device.h>
 
+/* VIMC-specific controls */
+#define VIMC_CID_VIMC_BASE             (0x00f00000 | 0xf000)
+#define VIMC_CID_VIMC_CLASS            (0x00f00000 | 1)
+#define VIMC_CID_TEST_PATTERN          (VIMC_CID_VIMC_BASE + 0)
+
 #define VIMC_FRAME_MAX_WIDTH 4096
 #define VIMC_FRAME_MAX_HEIGHT 2160
 #define VIMC_FRAME_MIN_WIDTH 16
index 02e68c8..ca1c522 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/v4l2-mediabus.h>
 #include <linux/vmalloc.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-tpg.h>
 
@@ -38,6 +39,7 @@ struct vimc_sen_device {
        u8 *frame;
        /* The active format */
        struct v4l2_mbus_framefmt mbus_format;
+       struct v4l2_ctrl_handler hdl;
 };
 
 static const struct v4l2_mbus_framefmt fmt_default = {
@@ -291,6 +293,31 @@ static const struct v4l2_subdev_ops vimc_sen_ops = {
        .video = &vimc_sen_video_ops,
 };
 
+static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vimc_sen_device *vsen =
+               container_of(ctrl->handler, struct vimc_sen_device, hdl);
+
+       switch (ctrl->id) {
+       case VIMC_CID_TEST_PATTERN:
+               tpg_s_pattern(&vsen->tpg, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               tpg_s_hflip(&vsen->tpg, ctrl->val);
+               break;
+       case V4L2_CID_VFLIP:
+               tpg_s_vflip(&vsen->tpg, ctrl->val);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = {
+       .s_ctrl = vimc_sen_s_ctrl,
+};
+
 static void vimc_sen_comp_unbind(struct device *comp, struct device *master,
                                 void *master_data)
 {
@@ -299,10 +326,28 @@ static void vimc_sen_comp_unbind(struct device *comp, struct device *master,
                                container_of(ved, struct vimc_sen_device, ved);
 
        vimc_ent_sd_unregister(ved, &vsen->sd);
+       v4l2_ctrl_handler_free(&vsen->hdl);
        tpg_free(&vsen->tpg);
        kfree(vsen);
 }
 
+/* Image Processing Controls */
+static const struct v4l2_ctrl_config vimc_sen_ctrl_class = {
+       .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
+       .id = VIMC_CID_VIMC_CLASS,
+       .name = "VIMC Controls",
+       .type = V4L2_CTRL_TYPE_CTRL_CLASS,
+};
+
+static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern = {
+       .ops = &vimc_sen_ctrl_ops,
+       .id = VIMC_CID_TEST_PATTERN,
+       .name = "Test Pattern",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .max = TPG_PAT_NOISE,
+       .qmenu = tpg_pattern_strings,
+};
+
 static int vimc_sen_comp_bind(struct device *comp, struct device *master,
                              void *master_data)
 {
@@ -316,6 +361,20 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
        if (!vsen)
                return -ENOMEM;
 
+       v4l2_ctrl_handler_init(&vsen->hdl, 4);
+
+       v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_class, NULL);
+       v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_test_pattern, NULL);
+       v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+                         V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+                         V4L2_CID_HFLIP, 0, 1, 1, 0);
+       vsen->sd.ctrl_handler = &vsen->hdl;
+       if (vsen->hdl.error) {
+               ret = vsen->hdl.error;
+               goto err_free_vsen;
+       }
+
        /* Initialize ved and sd */
        ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev,
                                   pdata->entity_name,
@@ -323,7 +382,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
                                   (const unsigned long[1]) {MEDIA_PAD_FL_SOURCE},
                                   &vimc_sen_ops);
        if (ret)
-               goto err_free_vsen;
+               goto err_free_hdl;
 
        dev_set_drvdata(comp, &vsen->ved);
        vsen->dev = comp;
@@ -342,6 +401,8 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
 
 err_unregister_ent_sd:
        vimc_ent_sd_unregister(&vsen->ved,  &vsen->sd);
+err_free_hdl:
+       v4l2_ctrl_handler_free(&vsen->hdl);
 err_free_vsen:
        kfree(vsen);