mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
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:
parent
46347e3ec6
commit
d534b9520a
4 changed files with 170 additions and 21 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
102
drivers/media/test-drivers/vimc/vimc-lens.c
Normal file
102
drivers/media/test-drivers/vimc/vimc-lens.c
Normal 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
|
||||
};
|
Loading…
Reference in a new issue