media: vimc: add ancillary lens
authorYunke Cao <yunkec@google.com>
Tue, 28 Jun 2022 00:53:52 +0000 (01:53 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Fri, 15 Jul 2022 13:40:09 +0000 (14:40 +0100)
Add lens to vimc driver and link them with sensors using ancillary links.
Provides an example of ancillary link usage.The lens supports
FOCUS_ABSOLUTE control.

Test example: With default vimc topology
> media-ctl -p
Media controller API version 5.18.0
...
- entity 28: Lens A (0 pad, 0 link)
             type V4L2 subdev subtype Lens flags 0
             device node name /dev/v4l-subdev6
- entity 29: Lens B (0 pad, 0 link)
             type V4L2 subdev subtype Lens flags 0
             device node name /dev/v4l-subdev7
> v4l2-ctl -d /dev/v4l-subdev7 -C focus_absolute
focus_absolute: 0

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Yunke Cao <yunkec@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
drivers/media/test-drivers/vimc/Makefile
drivers/media/test-drivers/vimc/vimc-common.h
drivers/media/test-drivers/vimc/vimc-core.c
drivers/media/test-drivers/vimc/vimc-lens.c [new file with mode: 0644]

index a53b2b532e9f6101ec68dbfa7a0ccd36774fbb20..9b9631562473034a002cfceabb3cce057bab008e 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 vimc-y := vimc-core.o vimc-common.o vimc-streamer.o vimc-capture.o \
-               vimc-debayer.o vimc-scaler.o vimc-sensor.o
+               vimc-debayer.o vimc-scaler.o vimc-sensor.o vimc-lens.o
 
 obj-$(CONFIG_VIDEO_VIMC) += vimc.o
 
index ba19307725894f4de8b5b67c790879ef1f13c6de..37f6b687ce101a89b3d4806034bbc1d24857862e 100644 (file)
@@ -171,6 +171,7 @@ extern struct vimc_ent_type vimc_sen_type;
 extern struct vimc_ent_type vimc_deb_type;
 extern struct vimc_ent_type vimc_sca_type;
 extern struct vimc_ent_type vimc_cap_type;
+extern struct vimc_ent_type vimc_len_type;
 
 /**
  * vimc_pix_map_by_index - get vimc_pix_map struct by its index
index 06edf9d4d92c45205070b5c52c5e58052575a7c5..166323406c6b6ea83711fa3c5c49fa5864d1d790 100644 (file)
@@ -24,7 +24,7 @@ MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n"
 
 #define VIMC_MDEV_MODEL_NAME "VIMC MDEV"
 
-#define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) {        \
+#define VIMC_DATA_LINK(src, srcpad, sink, sinkpad, link_flags) {       \
        .src_ent = src,                                         \
        .src_pad = srcpad,                                      \
        .sink_ent = sink,                                       \
@@ -32,8 +32,13 @@ MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n"
        .flags = link_flags,                                    \
 }
 
-/* Structure which describes links between entities */
-struct vimc_ent_link {
+#define VIMC_ANCILLARY_LINK(primary, ancillary) {      \
+       .primary_ent = primary,                 \
+       .ancillary_ent = ancillary              \
+}
+
+/* Structure which describes data links between entities */
+struct vimc_data_link {
        unsigned int src_ent;
        u16 src_pad;
        unsigned int sink_ent;
@@ -41,12 +46,20 @@ struct vimc_ent_link {
        u32 flags;
 };
 
+/* Structure which describes ancillary links between entities */
+struct vimc_ancillary_link {
+       unsigned int primary_ent;
+       unsigned int ancillary_ent;
+};
+
 /* Structure which describes the whole topology */
 struct vimc_pipeline_config {
        const struct vimc_ent_config *ents;
        size_t num_ents;
-       const struct vimc_ent_link *links;
-       size_t num_links;
+       const struct vimc_data_link *data_links;
+       size_t num_data_links;
+       const struct vimc_ancillary_link *ancillary_links;
+       size_t num_ancillary_links;
 };
 
 /* --------------------------------------------------------------------------
@@ -91,32 +104,49 @@ static struct vimc_ent_config ent_config[] = {
                .name = "RGB/YUV Capture",
                .type = &vimc_cap_type
        },
+       {
+               .name = "Lens A",
+               .type = &vimc_len_type
+       },
+       {
+               .name = "Lens B",
+               .type = &vimc_len_type
+       },
 };
 
-static const struct vimc_ent_link ent_links[] = {
+static const struct vimc_data_link data_links[] = {
        /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */
-       VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+       VIMC_DATA_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
        /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */
-       VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+       VIMC_DATA_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
        /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */
-       VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+       VIMC_DATA_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
        /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */
-       VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+       VIMC_DATA_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
        /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */
-       VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED),
+       VIMC_DATA_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED),
        /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */
-       VIMC_ENT_LINK(3, 1, 7, 0, 0),
+       VIMC_DATA_LINK(3, 1, 7, 0, 0),
        /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */
-       VIMC_ENT_LINK(6, 0, 7, 0, 0),
+       VIMC_DATA_LINK(6, 0, 7, 0, 0),
        /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */
-       VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+       VIMC_DATA_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+};
+
+static const struct vimc_ancillary_link ancillary_links[] = {
+       /* Link: Sensor A -> Lens A */
+       VIMC_ANCILLARY_LINK(0, 9),
+       /* Link: Sensor B -> Lens B */
+       VIMC_ANCILLARY_LINK(1, 10),
 };
 
 static struct vimc_pipeline_config pipe_cfg = {
-       .ents           = ent_config,
-       .num_ents       = ARRAY_SIZE(ent_config),
-       .links          = ent_links,
-       .num_links      = ARRAY_SIZE(ent_links)
+       .ents                = ent_config,
+       .num_ents            = ARRAY_SIZE(ent_config),
+       .data_links          = data_links,
+       .num_data_links      = ARRAY_SIZE(data_links),
+       .ancillary_links     = ancillary_links,
+       .num_ancillary_links = ARRAY_SIZE(ancillary_links),
 };
 
 /* -------------------------------------------------------------------------- */
@@ -135,8 +165,8 @@ static int vimc_create_links(struct vimc_device *vimc)
        int ret;
 
        /* Initialize the links between entities */
-       for (i = 0; i < vimc->pipe_cfg->num_links; i++) {
-               const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i];
+       for (i = 0; i < vimc->pipe_cfg->num_data_links; i++) {
+               const struct vimc_data_link *link = &vimc->pipe_cfg->data_links[i];
 
                struct vimc_ent_device *ved_src =
                        vimc->ent_devs[link->src_ent];
@@ -150,6 +180,22 @@ static int vimc_create_links(struct vimc_device *vimc)
                        goto err_rm_links;
        }
 
+       for (i = 0; i < vimc->pipe_cfg->num_ancillary_links; i++) {
+               const struct vimc_ancillary_link *link = &vimc->pipe_cfg->ancillary_links[i];
+
+               struct vimc_ent_device *ved_primary =
+                       vimc->ent_devs[link->primary_ent];
+               struct vimc_ent_device *ved_ancillary =
+                       vimc->ent_devs[link->ancillary_ent];
+               struct media_link *ret_link =
+                       media_create_ancillary_link(ved_primary->ent, ved_ancillary->ent);
+
+               if (IS_ERR(ret_link)) {
+                       ret = PTR_ERR(link);
+                       goto err_rm_links;
+               }
+       }
+
        return 0;
 
 err_rm_links:
diff --git a/drivers/media/test-drivers/vimc/vimc-lens.c b/drivers/media/test-drivers/vimc/vimc-lens.c
new file mode 100644 (file)
index 0000000..dfe824d
--- /dev/null
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * vimc-lens.c Virtual Media Controller Driver
+ * Copyright (C) 2022 Google, Inc
+ * Author: yunkec@google.com (Yunke Cao)
+ */
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+
+#include "vimc-common.h"
+
+#define VIMC_LEN_MAX_FOCUS_POS 1023
+#define VIMC_LEN_MAX_FOCUS_STEP        1
+
+struct vimc_len_device {
+       struct vimc_ent_device ved;
+       struct v4l2_subdev sd;
+       struct v4l2_ctrl_handler hdl;
+       u32 focus_absolute;
+};
+
+static const struct v4l2_subdev_core_ops vimc_len_core_ops = {
+       .log_status = v4l2_ctrl_subdev_log_status,
+       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_ops vimc_len_ops = {
+       .core = &vimc_len_core_ops
+};
+
+static int vimc_len_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vimc_len_device *vlen =
+               container_of(ctrl->handler, struct vimc_len_device, hdl);
+       if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) {
+               vlen->focus_absolute = ctrl->val;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops vimc_len_ctrl_ops = {
+       .s_ctrl = vimc_len_s_ctrl,
+};
+
+static struct vimc_ent_device *vimc_len_add(struct vimc_device *vimc,
+                                           const char *vcfg_name)
+{
+       struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
+       struct vimc_len_device *vlen;
+       int ret;
+
+       /* Allocate the vlen struct */
+       vlen = kzalloc(sizeof(*vlen), GFP_KERNEL);
+       if (!vlen)
+               return ERR_PTR(-ENOMEM);
+
+       v4l2_ctrl_handler_init(&vlen->hdl, 1);
+
+       v4l2_ctrl_new_std(&vlen->hdl, &vimc_len_ctrl_ops,
+                         V4L2_CID_FOCUS_ABSOLUTE, 0,
+                         VIMC_LEN_MAX_FOCUS_POS, VIMC_LEN_MAX_FOCUS_STEP, 0);
+       vlen->sd.ctrl_handler = &vlen->hdl;
+       if (vlen->hdl.error) {
+               ret = vlen->hdl.error;
+               goto err_free_vlen;
+       }
+       vlen->ved.dev = vimc->mdev.dev;
+
+       ret = vimc_ent_sd_register(&vlen->ved, &vlen->sd, v4l2_dev,
+                                  vcfg_name, MEDIA_ENT_F_LENS, 0,
+                                  NULL, &vimc_len_ops);
+       if (ret)
+               goto err_free_hdl;
+
+       return &vlen->ved;
+
+err_free_hdl:
+       v4l2_ctrl_handler_free(&vlen->hdl);
+err_free_vlen:
+       kfree(vlen);
+
+       return ERR_PTR(ret);
+}
+
+static void vimc_len_release(struct vimc_ent_device *ved)
+{
+       struct vimc_len_device *vlen =
+               container_of(ved, struct vimc_len_device, ved);
+
+       v4l2_ctrl_handler_free(&vlen->hdl);
+       media_entity_cleanup(vlen->ved.ent);
+       kfree(vlen);
+}
+
+struct vimc_ent_type vimc_len_type = {
+       .add = vimc_len_add,
+       .release = vimc_len_release
+};