From patchwork Thu Feb 10 11:09:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 541982 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 94C0AC433F5 for ; Thu, 10 Feb 2022 11:09:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240565AbiBJLJM (ORCPT ); Thu, 10 Feb 2022 06:09:12 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:43278 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237987AbiBJLJL (ORCPT ); Thu, 10 Feb 2022 06:09:11 -0500 Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::225]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 58B12B71 for ; Thu, 10 Feb 2022 03:09:12 -0800 (PST) Received: (Authenticated sender: jacopo@jmondi.org) by mail.gandi.net (Postfix) with ESMTPSA id C944B1C0012; Thu, 10 Feb 2022 11:09:07 +0000 (UTC) From: Jacopo Mondi To: slongerbeam@gmail.com Cc: laurent.pinchart@ideasonboard.com, sakari.ailus@iki.fi, hverkuil-cisco@xs4all.nl, mirela.rabulea@nxp.com, xavier.roumegue@oss.nxp.com, tomi.valkeinen@ideasonboard.com, hugues.fruchet@st.com, prabhakar.mahadev-lad.rj@bp.renesas.com, aford173@gmail.com, festevam@gmail.com, eugen.hristev@microchip.com, jbrunet@baylibre.com, mchehab@kernel.org, linux-media@vger.kernel.org, Jacopo Mondi Subject: [PATCH v2 14/23] media: ov5640: Add VBLANK control Date: Thu, 10 Feb 2022 12:09:59 +0100 Message-Id: <20220210111004.152859-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.35.0 In-Reply-To: <20220210110458.152494-1-jacopo@jmondi.org> References: <20220210110458.152494-1-jacopo@jmondi.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add the VBLANK control which allows to select the duration of the frame vertical blankings and allows to control the framerate. The VBLANK control also modifies the exposure time range, which cannot exceed the maximum frame length. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- drivers/media/i2c/ov5640.c | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index ade9adb43fda..30b706a98eb9 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -29,6 +29,12 @@ #define OV5640_XCLK_MIN 6000000 #define OV5640_XCLK_MAX 54000000 +#define OV5640_LINK_RATE_MAX 490000000U + +/* FIXME: not documented. */ +#define OV5640_MIN_VBLANK 24 +#define OV5640_MAX_VTS 1968 + #define OV5640_DEFAULT_SLAVE_ID 0x3c #define OV5640_LINK_RATE_MAX 490000000U @@ -301,6 +307,7 @@ struct ov5640_ctrls { struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *link_freq; struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; struct { struct v4l2_ctrl *auto_exp; struct v4l2_ctrl *exposure; @@ -2553,6 +2560,7 @@ static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) const struct ov5640_mode_info *mode = sensor->current_mode; struct v4l2_mbus_framefmt *fmt = &sensor->fmt; enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate; + s64 exposure_val, exposure_max; unsigned int hblank; unsigned int i = 0; u32 pixel_rate; @@ -2610,6 +2618,20 @@ static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) __v4l2_ctrl_modify_range(sensor->ctrls.hblank, hblank, hblank, 1, hblank); + __v4l2_ctrl_modify_range(sensor->ctrls.vblank, + OV5640_MIN_VBLANK, + OV5640_MAX_VTS - mode->crop.height, 1, + mode->vblank_def); + __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, mode->vblank_def); + + exposure_max = mode->crop.height + mode->vblank_def - 4; + exposure_val = clamp((s64)sensor->ctrls.exposure->val, + (s64)sensor->ctrls.exposure->minimum, + (s64)exposure_max); + __v4l2_ctrl_modify_range(sensor->ctrls.exposure, + sensor->ctrls.exposure->minimum, + exposure_max, 1, exposure_val); + return 0; } @@ -2982,6 +3004,15 @@ static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value) (BIT(2) | BIT(1)) : 0); } +static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value) +{ + const struct ov5640_mode_info *mode = sensor->current_mode; + + /* Update the VTOT timing register value. */ + return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, + mode->crop.height + value); +} + static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); @@ -3012,10 +3043,23 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); struct ov5640_dev *sensor = to_ov5640_dev(sd); + const struct ov5640_mode_info *mode = sensor->current_mode; + unsigned int exp_max; int ret; /* v4l2_ctrl_lock() locks our own mutex */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update the exposure range to the newly programmed vblank. */ + exp_max = mode->crop.height + ctrl->val - 4; + __v4l2_ctrl_modify_range(sensor->ctrls.exposure, + sensor->ctrls.exposure->minimum, + exp_max, sensor->ctrls.exposure->step, + mode->vblank_def); + break; + } + /* * If the device is not powered up by the host driver do * not apply any controls to H/W at this time. Instead @@ -3055,6 +3099,9 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_VFLIP: ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); break; + case V4L2_CID_VBLANK: + ret = ov5640_set_ctrl_vblank(sensor, ctrl->val); + break; default: ret = -EINVAL; break; @@ -3074,6 +3121,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; struct ov5640_ctrls *ctrls = &sensor->ctrls; struct v4l2_ctrl_handler *hdl = &ctrls->handler; + unsigned int max_vblank; unsigned int hblank; int ret; @@ -3097,6 +3145,11 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank, hblank, 1, hblank); + max_vblank = OV5640_MAX_VTS - mode->crop.height; + ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, + OV5640_MIN_VBLANK, max_vblank, + 1, mode->vblank_def); + /* Auto/manual white balance */ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE,