From patchwork Tue Oct 3 12:08:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sakari Ailus X-Patchwork-Id: 729120 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 40993E7544F for ; Tue, 3 Oct 2023 12:08:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232208AbjJCMIn (ORCPT ); Tue, 3 Oct 2023 08:08:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50734 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232136AbjJCMIl (ORCPT ); Tue, 3 Oct 2023 08:08:41 -0400 Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.24]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3053BB3 for ; Tue, 3 Oct 2023 05:08:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1696334918; x=1727870918; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=OaJpNe+tEK/yaoQ1BvTwGBi0fduXK+ePMAJgM7P+Aug=; b=kwQD5xb4aebGNvPV9UotidzorgP+lqGWzOo/gs7x+3hdZWfpqoBz1/1G 2ByOrBsLkGxmqtS8mCkXRwPGTYi3Vhk5jDoC3FCRzebNtQuQH1u8la+HR xuS2ezWyVmBe3t3F11f65n0rqa6nsoMlHVUt8QoCQv+Ys/nrKMr5K/o3e iTRaucquSe6OjtF2iZSEO0o/9uIqkqNmZ39o8cYFlnjheYx0jCiX4MyCL pOVUsz6FlTr3E7DxZa23Yxq4xObUrjcU5zoRol/1Rpp5Fo11hbw/2xUCz uDz47vwRXSAUvxFW4zj9J/dqwXjbjGJPZfjc2SktLOrWJEymhGSOJnC97 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10851"; a="385681557" X-IronPort-AV: E=Sophos;i="6.03,197,1694761200"; d="scan'208";a="385681557" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Oct 2023 05:08:37 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10851"; a="780285946" X-IronPort-AV: E=Sophos;i="6.03,197,1694761200"; d="scan'208";a="780285946" Received: from turnipsi.fi.intel.com (HELO kekkonen.fi.intel.com) ([10.237.72.44]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Oct 2023 05:08:34 -0700 Received: from svinhufvud.ger.corp.intel.com (localhost [IPv6:::1]) by kekkonen.fi.intel.com (Postfix) with ESMTP id 512BE120A56; Tue, 3 Oct 2023 15:08:31 +0300 (EEST) From: Sakari Ailus To: linux-media@vger.kernel.org Cc: Laurent Pinchart , tomi.valkeinen@ideasonboard.com, bingbu.cao@intel.com, hongju.wang@intel.com, hverkuil@xs4all.nl, Andrey Konovalov , Jacopo Mondi , Dmitry Perchanov , "Ng, Khai Wen" Subject: [PATCH v6 22/28] media: ccs: Use {enable,disable}_streams operations Date: Tue, 3 Oct 2023 15:08:07 +0300 Message-Id: <20231003120813.77726-13-sakari.ailus@linux.intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231003115237.76828-1-sakari.ailus@linux.intel.com> References: <20231003115237.76828-1-sakari.ailus@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Switch from s_stream() video op to enable_streams() and disable_streams() pad operations. They are preferred and required for streams support. Signed-off-by: Sakari Ailus --- drivers/media/i2c/ccs/ccs-core.c | 183 +++++++++++++++---------------- 1 file changed, 86 insertions(+), 97 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 0c518145b2c8..70e7582bbf5f 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1705,22 +1705,64 @@ static int ccs_power_off(struct device *dev) } /* ----------------------------------------------------------------------------- - * Video stream management + * V4L2 subdev video operations */ -static int ccs_start_streaming(struct ccs_sensor *sensor) +static int ccs_pm_get_init(struct ccs_sensor *sensor) { + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + /* + * It can't use pm_runtime_resume_and_get() here, as the driver + * relies at the returned value to detect if the device was already + * active or not. + */ + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) + goto error; + + /* Device was already active, so don't set controls */ + if (rval == 1) + return 0; + + /* Restore V4L2 controls to the previously suspended device */ + rval = __v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); + if (rval) + goto error; + + rval = __v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); + if (rval) + goto error; + + /* Keep PM runtime usage_count incremented on success */ + return 0; +error: + pm_runtime_put(&client->dev); + return rval; +} + +static int ccs_enable_streams(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); unsigned int binning_mode; int rval; - mutex_lock(&sensor->mutex); + if (pad != CCS_PAD_SRC) + return -EINVAL; + + rval = ccs_pm_get_init(sensor); + if (rval) + return rval; rval = ccs_write(sensor, CSI_DATA_FORMAT, (sensor->csi_format->width << 8) | sensor->csi_format->compressed); if (rval) - goto out; + goto err_pm_put; /* Binning configuration */ if (sensor->binning_horizontal == 1 && @@ -1733,38 +1775,38 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) rval = ccs_write(sensor, BINNING_TYPE, binning_type); if (rval < 0) - goto out; + goto err_pm_put; binning_mode = 1; } rval = ccs_write(sensor, BINNING_MODE, binning_mode); if (rval < 0) - goto out; + goto err_pm_put; /* Set up PLL */ rval = ccs_pll_configure(sensor); if (rval) - goto out; + goto err_pm_put; /* Analog crop start coordinates */ rval = ccs_write(sensor, X_ADDR_START, sensor->pa_src.left); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, Y_ADDR_START, sensor->pa_src.top); if (rval < 0) - goto out; + goto err_pm_put; /* Analog crop end coordinates */ rval = ccs_write(sensor, X_ADDR_END, sensor->pa_src.left + sensor->pa_src.width - 1); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, Y_ADDR_END, sensor->pa_src.top + sensor->pa_src.height - 1); if (rval < 0) - goto out; + goto err_pm_put; /* * Output from pixel array, including blanking, is set using @@ -1777,22 +1819,22 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) rval = ccs_write(sensor, DIGITAL_CROP_X_OFFSET, sensor->scaler_sink.left); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, DIGITAL_CROP_Y_OFFSET, sensor->scaler_sink.top); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, DIGITAL_CROP_IMAGE_WIDTH, sensor->scaler_sink.width); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, DIGITAL_CROP_IMAGE_HEIGHT, sensor->scaler_sink.height); if (rval < 0) - goto out; + goto err_pm_put; } /* Scaling */ @@ -1800,20 +1842,20 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) != CCS_SCALING_CAPABILITY_NONE) { rval = ccs_write(sensor, SCALING_MODE, sensor->scaling_mode); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, SCALE_M, sensor->scale_m); if (rval < 0) - goto out; + goto err_pm_put; } /* Output size from sensor */ rval = ccs_write(sensor, X_OUTPUT_SIZE, sensor->src_src.width); if (rval < 0) - goto out; + goto err_pm_put; rval = ccs_write(sensor, Y_OUTPUT_SIZE, sensor->src_src.height); if (rval < 0) - goto out; + goto err_pm_put; if (CCS_LIM(sensor, FLASH_MODE_CAPABILITY) & (CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE | @@ -1822,109 +1864,52 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) sensor->hwcfg.strobe_setup->trigger != 0) { rval = ccs_setup_flash_strobe(sensor); if (rval) - goto out; + goto err_pm_put; } rval = ccs_call_quirk(sensor, pre_streamon); if (rval) { dev_err(&client->dev, "pre_streamon quirks failed\n"); - goto out; + goto err_pm_put; } rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_STREAMING); -out: - mutex_unlock(&sensor->mutex); - - return rval; -} - -static int ccs_stop_streaming(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - mutex_lock(&sensor->mutex); - rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_SOFTWARE_STANDBY); - if (rval) - goto out; - - rval = ccs_call_quirk(sensor, post_streamoff); - if (rval) - dev_err(&client->dev, "post_streamoff quirks failed\n"); - -out: - mutex_unlock(&sensor->mutex); - return rval; -} - -/* ----------------------------------------------------------------------------- - * V4L2 subdev video operations - */ - -static int ccs_pm_get_init(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - /* - * It can't use pm_runtime_resume_and_get() here, as the driver - * relies at the returned value to detect if the device was already - * active or not. - */ - rval = pm_runtime_get_sync(&client->dev); - if (rval < 0) - goto error; - - /* Device was already active, so don't set controls */ - if (rval == 1) - return 0; + sensor->streaming = true; - /* Restore V4L2 controls to the previously suspended device */ - rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); - if (rval) - goto error; + return 0; - rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); - if (rval) - goto error; +err_pm_put: + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); - /* Keep PM runtime usage_count incremented on success */ - return 0; -error: - pm_runtime_put(&client->dev); return rval; } -static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) +static int ccs_disable_streams(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { struct ccs_sensor *sensor = to_ccs_sensor(subdev); struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; - if (!enable) { - ccs_stop_streaming(sensor); - sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - - return 0; - } + if (pad != CCS_PAD_SRC) + return -EINVAL; - rval = ccs_pm_get_init(sensor); + rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_SOFTWARE_STANDBY); if (rval) return rval; - sensor->streaming = true; + rval = ccs_call_quirk(sensor, post_streamoff); + if (rval) + dev_err(&client->dev, "post_streamoff quirks failed\n"); - rval = ccs_start_streaming(sensor); - if (rval < 0) { - sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - } + sensor->streaming = false; + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); - return rval; + return 0; } static int ccs_pre_streamon(struct v4l2_subdev *subdev, u32 flags) @@ -1950,7 +1935,9 @@ static int ccs_pre_streamon(struct v4l2_subdev *subdev, u32 flags) } } + mutex_lock(&sensor->mutex); rval = ccs_pm_get_init(sensor); + mutex_unlock(&sensor->mutex); if (rval) return rval; @@ -3033,7 +3020,7 @@ static int ccs_init_cfg(struct v4l2_subdev *sd, } static const struct v4l2_subdev_video_ops ccs_video_ops = { - .s_stream = ccs_set_stream, + .s_stream = v4l2_subdev_s_stream_helper, .pre_streamon = ccs_pre_streamon, .post_streamoff = ccs_post_streamoff, }; @@ -3045,6 +3032,8 @@ static const struct v4l2_subdev_pad_ops ccs_pad_ops = { .set_fmt = ccs_set_format, .get_selection = ccs_get_selection, .set_selection = ccs_set_selection, + .enable_streams = ccs_enable_streams, + .disable_streams = ccs_disable_streams, }; static const struct v4l2_subdev_sensor_ops ccs_sensor_ops = {