From 28725443a44ba4ed854195cd2916a0ae59c4259f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 16 Jan 2023 15:44:50 +0100 Subject: [PATCH] media: i2c: imx290: Use runtime PM autosuspend Upstream commit a8c3e0c1bf1e Use runtime PM autosuspend to avoid powering off the sensor during fast stop-reconfigure-restart cycles. This also fixes runtime PM handling in the probe function that didn't suspend the device, effectively leaving it resumed forever. While at it, improve documentation of power management in probe() and remove(). Signed-off-by: Laurent Pinchart Acked-by: Alexander Stein Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 58 +++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 13 deletions(-) --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -626,7 +626,8 @@ static int imx290_set_ctrl(struct v4l2_c break; } - pm_runtime_put(imx290->dev); + pm_runtime_mark_last_busy(imx290->dev); + pm_runtime_put_autosuspend(imx290->dev); return ret; } @@ -827,12 +828,13 @@ static int imx290_set_stream(struct v4l2 ret = imx290_start_streaming(imx290, state); if (ret) { dev_err(imx290->dev, "Start stream failed\n"); - pm_runtime_put(imx290->dev); + pm_runtime_put_sync(imx290->dev); goto unlock; } } else { imx290_stop_streaming(imx290); - pm_runtime_put(imx290->dev); + pm_runtime_mark_last_busy(imx290->dev); + pm_runtime_put_autosuspend(imx290->dev); } unlock: @@ -1269,33 +1271,59 @@ static int imx290_probe(struct i2c_clien if (ret) return ret; - /* Initialize and register subdev. */ + /* Initialize the V4L2 subdev. */ ret = imx290_subdev_init(imx290); if (ret) return ret; - ret = v4l2_async_register_subdev(&imx290->sd); - if (ret < 0) { - dev_err(dev, "Could not register v4l2 device\n"); - goto err_subdev; - } - - /* Power on the device to match runtime PM state below */ + /* + * Enable power management. The driver supports runtime PM, but needs to + * work when runtime PM is disabled in the kernel. To that end, power + * the sensor on manually here. + */ ret = imx290_power_on(dev); if (ret < 0) { dev_err(dev, "Could not power on the device\n"); goto err_subdev; } + /* + * Enable runtime PM with autosuspend. As the device has been powered + * manually, mark it as active, and increase the usage count without + * resuming the device. + */ pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); pm_runtime_enable(dev); - pm_runtime_idle(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + + /* + * Finally, register the V4L2 subdev. This must be done after + * initializing everything as the subdev can be used immediately after + * being registered. + */ + ret = v4l2_async_register_subdev(&imx290->sd); + if (ret < 0) { + dev_err(dev, "Could not register v4l2 device\n"); + goto err_pm; + } + + /* + * Decrease the PM usage count. The device will get suspended after the + * autosuspend delay, turning the power off. + */ + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; +err_pm: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + imx290_power_off(dev); err_subdev: imx290_subdev_cleanup(imx290); - return ret; } @@ -1307,6 +1335,10 @@ static void imx290_remove(struct i2c_cli v4l2_async_unregister_subdev(sd); imx290_subdev_cleanup(imx290); + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ pm_runtime_disable(imx290->dev); if (!pm_runtime_status_suspended(imx290->dev)) imx290_power_off(imx290->dev);