media: vimc: add ancillary lens

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>
This commit is contained in:
Yunke Cao 2022-06-28 01:53:52 +01:00 committed by Mauro Carvalho Chehab
parent 46347e3ec6
commit d534b9520a
4 changed files with 170 additions and 21 deletions

View 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

View 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

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

View file

@ -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
};