162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * vimc-lens.c Virtual Media Controller Driver 462306a36Sopenharmony_ci * Copyright (C) 2022 Google, Inc 562306a36Sopenharmony_ci * Author: yunkec@google.com (Yunke Cao) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 962306a36Sopenharmony_ci#include <media/v4l2-event.h> 1062306a36Sopenharmony_ci#include <media/v4l2-subdev.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "vimc-common.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define VIMC_LENS_MAX_FOCUS_POS 1023 1562306a36Sopenharmony_ci#define VIMC_LENS_MAX_FOCUS_STEP 1 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct vimc_lens_device { 1862306a36Sopenharmony_ci struct vimc_ent_device ved; 1962306a36Sopenharmony_ci struct v4l2_subdev sd; 2062306a36Sopenharmony_ci struct v4l2_ctrl_handler hdl; 2162306a36Sopenharmony_ci u32 focus_absolute; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic const struct v4l2_subdev_core_ops vimc_lens_core_ops = { 2562306a36Sopenharmony_ci .log_status = v4l2_ctrl_subdev_log_status, 2662306a36Sopenharmony_ci .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 2762306a36Sopenharmony_ci .unsubscribe_event = v4l2_event_subdev_unsubscribe, 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const struct v4l2_subdev_ops vimc_lens_ops = { 3162306a36Sopenharmony_ci .core = &vimc_lens_core_ops 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int vimc_lens_s_ctrl(struct v4l2_ctrl *ctrl) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct vimc_lens_device *vlens = 3762306a36Sopenharmony_ci container_of(ctrl->handler, struct vimc_lens_device, hdl); 3862306a36Sopenharmony_ci if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { 3962306a36Sopenharmony_ci vlens->focus_absolute = ctrl->val; 4062306a36Sopenharmony_ci return 0; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci return -EINVAL; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops vimc_lens_ctrl_ops = { 4662306a36Sopenharmony_ci .s_ctrl = vimc_lens_s_ctrl, 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic struct vimc_ent_device *vimc_lens_add(struct vimc_device *vimc, 5062306a36Sopenharmony_ci const char *vcfg_name) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; 5362306a36Sopenharmony_ci struct vimc_lens_device *vlens; 5462306a36Sopenharmony_ci int ret; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* Allocate the vlens struct */ 5762306a36Sopenharmony_ci vlens = kzalloc(sizeof(*vlens), GFP_KERNEL); 5862306a36Sopenharmony_ci if (!vlens) 5962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci v4l2_ctrl_handler_init(&vlens->hdl, 1); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci v4l2_ctrl_new_std(&vlens->hdl, &vimc_lens_ctrl_ops, 6462306a36Sopenharmony_ci V4L2_CID_FOCUS_ABSOLUTE, 0, 6562306a36Sopenharmony_ci VIMC_LENS_MAX_FOCUS_POS, VIMC_LENS_MAX_FOCUS_STEP, 0); 6662306a36Sopenharmony_ci vlens->sd.ctrl_handler = &vlens->hdl; 6762306a36Sopenharmony_ci if (vlens->hdl.error) { 6862306a36Sopenharmony_ci ret = vlens->hdl.error; 6962306a36Sopenharmony_ci goto err_free_vlens; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci vlens->ved.dev = vimc->mdev.dev; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci ret = vimc_ent_sd_register(&vlens->ved, &vlens->sd, v4l2_dev, 7462306a36Sopenharmony_ci vcfg_name, MEDIA_ENT_F_LENS, 0, 7562306a36Sopenharmony_ci NULL, &vimc_lens_ops); 7662306a36Sopenharmony_ci if (ret) 7762306a36Sopenharmony_ci goto err_free_hdl; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return &vlens->ved; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cierr_free_hdl: 8262306a36Sopenharmony_ci v4l2_ctrl_handler_free(&vlens->hdl); 8362306a36Sopenharmony_cierr_free_vlens: 8462306a36Sopenharmony_ci kfree(vlens); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return ERR_PTR(ret); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void vimc_lens_release(struct vimc_ent_device *ved) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct vimc_lens_device *vlens = 9262306a36Sopenharmony_ci container_of(ved, struct vimc_lens_device, ved); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci v4l2_ctrl_handler_free(&vlens->hdl); 9562306a36Sopenharmony_ci media_entity_cleanup(vlens->ved.ent); 9662306a36Sopenharmony_ci kfree(vlens); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistruct vimc_ent_type vimc_lens_type = { 10062306a36Sopenharmony_ci .add = vimc_lens_add, 10162306a36Sopenharmony_ci .release = vimc_lens_release 10262306a36Sopenharmony_ci}; 103