From patchwork Mon Jul 10 15:52:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 701399 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 405A7EB64DA for ; Mon, 10 Jul 2023 15:54:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232302AbjGJPy0 (ORCPT ); Mon, 10 Jul 2023 11:54:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52480 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231728AbjGJPyY (ORCPT ); Mon, 10 Jul 2023 11:54:24 -0400 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 521151BC for ; Mon, 10 Jul 2023 08:53:59 -0700 (PDT) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4F5C52FA2; Mon, 10 Jul 2023 17:51:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1689004291; bh=R5rQEDxywx61h5CoR3GzJJo7Bw2jxFZbsRkL1fj550Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Nymj7FJZRFbLxKrQ3zZeQB/+v7kPK5y8CmVFi6wRYJ3yUZodzLof8bRS1IbZtOam2 E4O7NpDarPAJfXXfzG+077gtTGz63lUJaSh8Mz8CA5Xh4ARXk2Lq/8SnicTzxO0bPF LXpwkSJ3uTM04Tv0A+Wv6CX38DoEdUZ7c0B7IG0I= From: Jacopo Mondi To: linux-media@vger.kernel.org Cc: Jacopo Mondi , Dave Stevenson , Hans Verkuil , Sakari Ailus , Laurent Pinchart , Tomi Valkeinen , Jean-Michel Hautbois Subject: [PATCH v2 5/7] media: i2c: imx219: Use subdev active state Date: Mon, 10 Jul 2023 17:52:01 +0200 Message-Id: <20230710155203.92366-6-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230710155203.92366-1-jacopo.mondi@ideasonboard.com> References: <20230710155203.92366-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Port the imx219 sensor driver to use the subdev active state. Move all the format configuration to the subdevice state and simplify the format handling, locking and initialization. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Reviewed-by: Umang Jain --- drivers/media/i2c/imx219.c | 179 ++++++++++--------------------------- 1 file changed, 48 insertions(+), 131 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 6963e24e1bc2..73e06583d651 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -460,8 +460,6 @@ struct imx219 { struct v4l2_subdev sd; struct media_pad pad; - struct v4l2_mbus_framefmt fmt; - struct clk *xclk; /* system clock to IMX219 */ u32 xclk_freq; @@ -481,12 +479,6 @@ struct imx219 { /* Current mode */ const struct imx219_mode *mode; - /* - * Mutex for serialized access: - * Protect sensor module set pad format and start/stop streaming safely. - */ - struct mutex mutex; - /* Streaming on/off */ bool streaming; @@ -576,8 +568,6 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code) { unsigned int i; - lockdep_assert_held(&imx219->mutex); - for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++) if (imx219_mbus_formats[i] == code) break; @@ -591,20 +581,6 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code) return imx219_mbus_formats[i]; } -static void imx219_set_default_format(struct imx219 *imx219) -{ - struct v4l2_mbus_framefmt *fmt; - - fmt = &imx219->fmt; - fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10; - fmt->colorspace = V4L2_COLORSPACE_RAW; - fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - fmt->width = supported_modes[0].width; - fmt->height = supported_modes[0].height; - fmt->field = V4L2_FIELD_NONE; - fmt->xfer_func = V4L2_XFER_FUNC_NONE; -} - static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx219 *imx219 = @@ -701,9 +677,6 @@ static int imx219_init_cfg(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - /* imx219_get_format_code() wants mutex locked. */ - mutex_lock(&imx219->mutex); - /* Initialize try_fmt */ format = v4l2_subdev_get_pad_format(sd, state, 0); format->width = supported_modes[0].width; @@ -723,8 +696,6 @@ static int imx219_init_cfg(struct v4l2_subdev *sd, crop->width = IMX219_PIXEL_ARRAY_WIDTH; crop->height = IMX219_PIXEL_ARRAY_HEIGHT; - mutex_unlock(&imx219->mutex); - return 0; } @@ -737,9 +708,7 @@ static int imx219_enum_mbus_code(struct v4l2_subdev *sd, if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) return -EINVAL; - mutex_lock(&imx219->mutex); code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]); - mutex_unlock(&imx219->mutex); return 0; } @@ -754,9 +723,7 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; - mutex_lock(&imx219->mutex); code = imx219_get_format_code(imx219, fse->code); - mutex_unlock(&imx219->mutex); if (fse->code != code) return -EINVAL; @@ -785,52 +752,16 @@ static void imx219_update_pad_format(struct imx219 *imx219, imx219_reset_colorspace(&fmt->format); } -static int __imx219_get_pad_format(struct imx219 *imx219, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(&imx219->sd, sd_state, - fmt->pad); - /* update the code which could change due to vflip or hflip: */ - try_fmt->code = imx219_get_format_code(imx219, try_fmt->code); - fmt->format = *try_fmt; - } else { - imx219_update_pad_format(imx219, imx219->mode, fmt); - fmt->format.code = imx219_get_format_code(imx219, - imx219->fmt.code); - } - - return 0; -} - -static int imx219_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct imx219 *imx219 = to_imx219(sd); - int ret; - - mutex_lock(&imx219->mutex); - ret = __imx219_get_pad_format(imx219, sd_state, fmt); - mutex_unlock(&imx219->mutex); - - return ret; -} - static int imx219_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct imx219 *imx219 = to_imx219(sd); const struct imx219_mode *mode; - struct v4l2_mbus_framefmt *framefmt; int exposure_max, exposure_def, hblank; + struct v4l2_mbus_framefmt *format; unsigned int i; - mutex_lock(&imx219->mutex); - for (i = 0; i < ARRAY_SIZE(imx219_mbus_formats); i++) if (imx219_mbus_formats[i] == fmt->format.code) break; @@ -844,13 +775,14 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, ARRAY_SIZE(supported_modes), width, height, fmt->format.width, fmt->format.height); + imx219_update_pad_format(imx219, mode, fmt); - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); - *framefmt = fmt->format; - } else if (imx219->mode != mode || - imx219->fmt.code != fmt->format.code) { - imx219->fmt = fmt->format; + format = v4l2_subdev_get_pad_format(sd, sd_state, 0); + + if (imx219->mode == mode && format->code == fmt->format.code) + return 0; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { imx219->mode = mode; /* Update limits and set FPS to default */ __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, @@ -876,14 +808,15 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, hblank); } - mutex_unlock(&imx219->mutex); + *format = fmt->format; return 0; } -static int imx219_set_framefmt(struct imx219 *imx219) +static int imx219_set_framefmt(struct imx219 *imx219, + const struct v4l2_mbus_framefmt *format) { - switch (imx219->fmt.code) { + switch (format->code) { case MEDIA_BUS_FMT_SRGGB8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: @@ -902,7 +835,8 @@ static int imx219_set_framefmt(struct imx219 *imx219) return -EINVAL; } -static int imx219_set_binning(struct imx219 *imx219) +static int imx219_set_binning(struct imx219 *imx219, + const struct v4l2_mbus_framefmt *format) { if (!imx219->mode->binning) { return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, @@ -910,7 +844,7 @@ static int imx219_set_binning(struct imx219 *imx219) IMX219_BINNING_NONE); } - switch (imx219->fmt.code) { + switch (format->code) { case MEDIA_BUS_FMT_SRGGB8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: @@ -931,34 +865,13 @@ static int imx219_set_binning(struct imx219 *imx219) return -EINVAL; } -static const struct v4l2_rect * -__imx219_get_pad_crop(struct imx219 *imx219, - struct v4l2_subdev_state *sd_state, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - switch (which) { - case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(&imx219->sd, sd_state, pad); - case V4L2_SUBDEV_FORMAT_ACTIVE: - return &imx219->mode->crop; - } - - return NULL; -} - static int imx219_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { switch (sel->target) { case V4L2_SEL_TGT_CROP: { - struct imx219 *imx219 = to_imx219(sd); - - mutex_lock(&imx219->mutex); - sel->r = *__imx219_get_pad_crop(imx219, sd_state, sel->pad, - sel->which); - mutex_unlock(&imx219->mutex); - + sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0); return 0; } @@ -990,9 +903,11 @@ static int imx219_configure_lanes(struct imx219 *imx219) IMX219_CSI_2_LANE_MODE : IMX219_CSI_4_LANE_MODE); }; -static int imx219_start_streaming(struct imx219 *imx219) +static int imx219_start_streaming(struct imx219 *imx219, + struct v4l2_subdev_state *state) { struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); + const struct v4l2_mbus_framefmt *format; const struct imx219_reg_list *reg_list; int ret; @@ -1022,14 +937,15 @@ static int imx219_start_streaming(struct imx219 *imx219) goto err_rpm_put; } - ret = imx219_set_framefmt(imx219); + format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0); + ret = imx219_set_framefmt(imx219, format); if (ret) { dev_err(&client->dev, "%s failed to set frame format: %d\n", __func__, ret); goto err_rpm_put; } - ret = imx219_set_binning(imx219); + ret = imx219_set_binning(imx219, format); if (ret) { dev_err(&client->dev, "%s failed to set binning: %d\n", __func__, ret); @@ -1078,35 +994,30 @@ static void imx219_stop_streaming(struct imx219 *imx219) static int imx219_set_stream(struct v4l2_subdev *sd, int enable) { struct imx219 *imx219 = to_imx219(sd); + struct v4l2_subdev_state *state; int ret = 0; - mutex_lock(&imx219->mutex); - if (imx219->streaming == enable) { - mutex_unlock(&imx219->mutex); - return 0; - } + state = v4l2_subdev_lock_and_get_active_state(sd); + + if (imx219->streaming == enable) + goto unlock; if (enable) { /* * Apply default & customized values * and then start streaming. */ - ret = imx219_start_streaming(imx219); + ret = imx219_start_streaming(imx219, state); if (ret) - goto err_unlock; + goto unlock; } else { imx219_stop_streaming(imx219); } imx219->streaming = enable; - mutex_unlock(&imx219->mutex); - - return ret; - -err_unlock: - mutex_unlock(&imx219->mutex); - +unlock: + v4l2_subdev_unlock_state(state); return ret; } @@ -1171,10 +1082,13 @@ static int __maybe_unused imx219_resume(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx219 *imx219 = to_imx219(sd); + struct v4l2_subdev_state *state; int ret; if (imx219->streaming) { - ret = imx219_start_streaming(imx219); + state = v4l2_subdev_lock_and_get_active_state(sd); + ret = imx219_start_streaming(imx219, state); + v4l2_subdev_unlock_state(state); if (ret) goto error; } @@ -1237,7 +1151,7 @@ static const struct v4l2_subdev_video_ops imx219_video_ops = { static const struct v4l2_subdev_pad_ops imx219_pad_ops = { .init_cfg = imx219_init_cfg, .enum_mbus_code = imx219_enum_mbus_code, - .get_fmt = imx219_get_pad_format, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx219_set_pad_format, .get_selection = imx219_get_selection, .enum_frame_size = imx219_enum_frame_size, @@ -1270,9 +1184,6 @@ static int imx219_init_controls(struct imx219 *imx219) if (ret) return ret; - mutex_init(&imx219->mutex); - ctrl_hdlr->lock = &imx219->mutex; - /* By default, PIXEL_RATE is read only */ imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_PIXEL_RATE, @@ -1369,7 +1280,6 @@ static int imx219_init_controls(struct imx219 *imx219) error: v4l2_ctrl_handler_free(ctrl_hdlr); - mutex_destroy(&imx219->mutex); return ret; } @@ -1377,7 +1287,6 @@ static int imx219_init_controls(struct imx219 *imx219) static void imx219_free_controls(struct imx219 *imx219) { v4l2_ctrl_handler_free(imx219->sd.ctrl_handler); - mutex_destroy(&imx219->mutex); } static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219) @@ -1514,19 +1423,23 @@ static int imx219_probe(struct i2c_client *client) /* Initialize source pad */ imx219->pad.flags = MEDIA_PAD_FL_SOURCE; - /* Initialize default format */ - imx219_set_default_format(imx219); - ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad); if (ret) { dev_err(dev, "failed to init entity pads: %d\n", ret); goto error_handler_free; } + imx219->sd.state_lock = imx219->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&imx219->sd); + if (ret < 0) { + dev_err(dev, "subdev init error: %d\n", ret); + goto error_media_entity; + } + ret = v4l2_async_register_subdev_sensor(&imx219->sd); if (ret < 0) { dev_err(dev, "failed to register sensor sub-device: %d\n", ret); - goto error_media_entity; + goto error_subdev_cleanup; } /* Enable runtime PM and turn off the device */ @@ -1536,6 +1449,9 @@ static int imx219_probe(struct i2c_client *client) return 0; +error_subdev_cleanup: + v4l2_subdev_cleanup(&imx219->sd); + error_media_entity: media_entity_cleanup(&imx219->sd.entity); @@ -1554,6 +1470,7 @@ static void imx219_remove(struct i2c_client *client) struct imx219 *imx219 = to_imx219(sd); v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); imx219_free_controls(imx219);