From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Sakari Ailus <sakari.ailus@linux.intel.com>
Cc: Paul Elder <paul.elder@ideasonboard.com>,
Steve Longerbeam <slongerbeam@gmail.com>,
Hans Verkuil <hverkuil-cisco@xs4all.nl>,
"Paul J. Murphy" <paul.j.murphy@intel.com>,
Martina Krasteva <martinax.krasteva@intel.com>,
Shawn Tu <shawnx.tu@intel.com>, Arec Kao <arec.kao@intel.com>,
Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>,
Jimmy Su <jimmy.su@intel.com>,
Martin Kepplinger <martink@posteo.de>,
Daniel Scally <djrscally@gmail.com>,
Jacopo Mondi <jmondi@jmondi.org>,
Paul Kocialkowski <paul.kocialkowski@bootlin.com>,
linux-media@vger.kernel.org
Subject: Re: [PATCH v2] media: ov5640: Use runtime PM
Date: Fri, 11 Mar 2022 14:30:09 +0200 [thread overview]
Message-ID: <YitA0dI2mM4ACdaL@pendragon.ideasonboard.com> (raw)
In-Reply-To: <Yis/WZFBC49uoRg6@paasikivi.fi.intel.com>
Hi Sakari,
On Fri, Mar 11, 2022 at 02:23:53PM +0200, Sakari Ailus wrote:
> On Fri, Mar 11, 2022 at 08:12:59PM +0900, Paul Elder wrote:
> > Switch to using runtime PM for power management.
> >
> > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
> >
> > ---
> > Changes in v2:
> > - replace manual tracking of power status with pm_runtime_get_if_in_use
> > - power on the sensor before reading the checking the chip id
> > - add dependency on PM to Kconfig
> > ---
> > drivers/media/i2c/Kconfig | 1 +
> > drivers/media/i2c/ov5640.c | 112 ++++++++++++++++++++++---------------
> > 2 files changed, 67 insertions(+), 46 deletions(-)
> >
> > diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> > index e7194c1be4d2..97c3611d9304 100644
> > --- a/drivers/media/i2c/Kconfig
> > +++ b/drivers/media/i2c/Kconfig
> > @@ -1025,6 +1025,7 @@ config VIDEO_OV5640
> > tristate "OmniVision OV5640 sensor support"
> > depends on OF
> > depends on GPIOLIB && VIDEO_V4L2 && I2C
> > + depends on PM
>
> I think this is not needed as the sensor is powered on explicitly in probe.
>
> You should similarly power it off explicitly in remove, set the runtime PM
> status suspended and disable runtime PM. See e.g. imx319 driver for an
> example. It doesn't have resume callback but that doesn't really matter ---
> it's just ACPI-only.
Do we want to continue supporting !PM ? Does it have any real use case
when dealing with camera sensors ?
> > select MEDIA_CONTROLLER
> > select VIDEO_V4L2_SUBDEV_API
> > select V4L2_FWNODE
> > diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
> > index 4de83d0ef85d..454ffd3c6d59 100644
> > --- a/drivers/media/i2c/ov5640.c
> > +++ b/drivers/media/i2c/ov5640.c
> > @@ -15,6 +15,7 @@
> > #include <linux/init.h>
> > #include <linux/module.h>
> > #include <linux/of_device.h>
> > +#include <linux/pm_runtime.h>
> > #include <linux/regulator/consumer.h>
> > #include <linux/slab.h>
> > #include <linux/types.h>
> > @@ -445,8 +446,6 @@ struct ov5640_dev {
> > /* lock to protect all members below */
> > struct mutex lock;
> >
> > - int power_count;
> > -
> > struct v4l2_mbus_framefmt fmt;
> > bool pending_fmt_change;
> >
> > @@ -2693,37 +2692,6 @@ static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
> >
> > /* --------------- Subdev Operations --------------- */
> >
> > -static int ov5640_s_power(struct v4l2_subdev *sd, int on)
> > -{
> > - struct ov5640_dev *sensor = to_ov5640_dev(sd);
> > - int ret = 0;
> > -
> > - mutex_lock(&sensor->lock);
> > -
> > - /*
> > - * If the power count is modified from 0 to != 0 or from != 0 to 0,
> > - * update the power state.
> > - */
> > - if (sensor->power_count == !on) {
> > - ret = ov5640_set_power(sensor, !!on);
> > - if (ret)
> > - goto out;
> > - }
> > -
> > - /* Update the power count. */
> > - sensor->power_count += on ? 1 : -1;
> > - WARN_ON(sensor->power_count < 0);
> > -out:
> > - mutex_unlock(&sensor->lock);
> > -
> > - if (on && !ret && sensor->power_count == 1) {
> > - /* restore controls */
> > - ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
> > - }
> > -
> > - return ret;
> > -}
> > -
> > static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
> > struct v4l2_fract *fi,
> > u32 width, u32 height)
> > @@ -3288,6 +3256,9 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
> >
> > /* v4l2_ctrl_lock() locks our own mutex */
> >
> > + if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
> > + return 0;
> > +
> > switch (ctrl->id) {
> > case V4L2_CID_AUTOGAIN:
> > val = ov5640_get_gain(sensor);
> > @@ -3303,6 +3274,8 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
> > break;
> > }
> >
> > + pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
> > +
> > return 0;
> > }
> >
> > @@ -3334,7 +3307,7 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
> > * not apply any controls to H/W at this time. Instead
> > * the controls will be restored right after power-up.
> > */
> > - if (sensor->power_count == 0)
> > + if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
> > return 0;
> >
> > switch (ctrl->id) {
> > @@ -3376,6 +3349,8 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
> > break;
> > }
> >
> > + pm_runtime_put_autosuspend(&sensor->i2c_client->dev);
> > +
> > return ret;
> > }
> >
> > @@ -3657,6 +3632,12 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
> > struct ov5640_dev *sensor = to_ov5640_dev(sd);
> > int ret = 0;
> >
> > + if (enable) {
> > + ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev);
> > + if (ret < 0)
> > + return ret;
> > + }
> > +
> > mutex_lock(&sensor->lock);
> >
> > if (sensor->streaming == !enable) {
> > @@ -3681,8 +3662,13 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
> > if (!ret)
> > sensor->streaming = enable;
> > }
> > +
> > out:
> > mutex_unlock(&sensor->lock);
> > +
> > + if (!enable || ret)
> > + pm_runtime_put(&sensor->i2c_client->dev);
> > +
> > return ret;
> > }
> >
> > @@ -3704,7 +3690,6 @@ static int ov5640_init_cfg(struct v4l2_subdev *sd,
> > }
> >
> > static const struct v4l2_subdev_core_ops ov5640_core_ops = {
> > - .s_power = ov5640_s_power,
> > .log_status = v4l2_ctrl_subdev_log_status,
> > .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
> > .unsubscribe_event = v4l2_event_subdev_unsubscribe,
> > @@ -3750,15 +3735,11 @@ static int ov5640_check_chip_id(struct ov5640_dev *sensor)
> > int ret = 0;
> > u16 chip_id;
> >
> > - ret = ov5640_set_power_on(sensor);
> > - if (ret)
> > - return ret;
> > -
> > ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
> > if (ret) {
> > dev_err(&client->dev, "%s: failed to read chip identifier\n",
> > __func__);
> > - goto power_off;
> > + return ret;
> > }
> >
> > if (chip_id != 0x5640) {
> > @@ -3767,8 +3748,6 @@ static int ov5640_check_chip_id(struct ov5640_dev *sensor)
> > ret = -ENXIO;
> > }
> >
> > -power_off:
> > - ov5640_set_power_off(sensor);
> > return ret;
> > }
> >
> > @@ -3863,20 +3842,35 @@ static int ov5640_probe(struct i2c_client *client)
> >
> > mutex_init(&sensor->lock);
> >
> > - ret = ov5640_check_chip_id(sensor);
> > + ret = ov5640_init_controls(sensor);
> > if (ret)
> > goto entity_cleanup;
> >
> > - ret = ov5640_init_controls(sensor);
> > + ret = ov5640_set_power(sensor, true);
> > if (ret)
> > - goto entity_cleanup;
> > + goto free_ctrls;
> > +
> > + pm_runtime_set_active(dev);
> > + pm_runtime_enable(dev);
> > + pm_runtime_get(dev);
> > +
> > + ret = ov5640_check_chip_id(sensor);
> > + if (ret)
> > + goto err_pm_runtime;
> >
> > ret = v4l2_async_register_subdev_sensor(&sensor->sd);
> > if (ret)
> > - goto free_ctrls;
> > + goto err_pm_runtime;
> > +
> > + pm_runtime_set_autosuspend_delay(dev, 1000);
> > + pm_runtime_use_autosuspend(dev);
> > + pm_runtime_put_autosuspend(dev);
> >
> > return 0;
> >
> > +err_pm_runtime:
> > + pm_runtime_disable(dev);
> > + pm_runtime_put_noidle(dev);
> > free_ctrls:
> > v4l2_ctrl_handler_free(&sensor->ctrls.handler);
> > entity_cleanup:
> > @@ -3898,6 +3892,31 @@ static int ov5640_remove(struct i2c_client *client)
> > return 0;
> > }
> >
> > +static int __maybe_unused ov5640_sensor_suspend(struct device *dev)
> > +{
> > + struct v4l2_subdev *sd = dev_get_drvdata(dev);
> > + struct ov5640_dev *ov5640 = to_ov5640_dev(sd);
> > +
> > + return ov5640_set_power(ov5640, false);
> > +}
> > +
> > +static int __maybe_unused ov5640_sensor_resume(struct device *dev)
> > +{
> > + struct v4l2_subdev *sd = dev_get_drvdata(dev);
> > + struct ov5640_dev *ov5640 = to_ov5640_dev(sd);
> > + int ret;
> > +
> > + ret = ov5640_set_power(ov5640, true);
> > + if (ret)
> > + return ret;
> > +
> > + return v4l2_ctrl_handler_setup(&ov5640->ctrls.handler);
> > +}
> > +
> > +static const struct dev_pm_ops ov5640_pm_ops = {
> > + SET_RUNTIME_PM_OPS(ov5640_sensor_suspend, ov5640_sensor_resume, NULL)
> > +};
> > +
> > static const struct i2c_device_id ov5640_id[] = {
> > {"ov5640", 0},
> > {},
> > @@ -3914,6 +3933,7 @@ static struct i2c_driver ov5640_i2c_driver = {
> > .driver = {
> > .name = "ov5640",
> > .of_match_table = ov5640_dt_ids,
> > + .pm = &ov5640_pm_ops,
> > },
> > .id_table = ov5640_id,
> > .probe_new = ov5640_probe,
>
> --
> Kind regards,
>
> Sakari Ailus
--
Regards,
Laurent Pinchart
next prev parent reply other threads:[~2022-03-11 12:30 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-11 11:12 [PATCH v2] media: ov5640: Use runtime PM Paul Elder
2022-03-11 12:23 ` Sakari Ailus
2022-03-11 12:30 ` Laurent Pinchart [this message]
2022-03-11 13:15 ` Sakari Ailus
2022-03-11 13:20 ` Laurent Pinchart
2022-03-11 13:32 ` Sakari Ailus
2022-03-13 13:01 ` Laurent Pinchart
2022-03-13 13:38 ` Sakari Ailus
2022-03-13 14:16 ` Laurent Pinchart
2022-03-14 20:01 ` Sakari Ailus
2022-03-14 20:05 ` Laurent Pinchart
2022-03-14 21:11 ` Sakari Ailus
2022-03-29 13:02 ` Laurent Pinchart
2022-04-14 9:29 ` Sakari Ailus
2022-08-01 7:17 ` Tomasz Figa
2022-08-01 7:23 ` Tomasz Figa
2022-08-01 13:47 ` Laurent Pinchart
2022-08-01 20:39 ` Sakari Ailus
2022-03-18 22:28 ` Laurent Pinchart
2022-03-21 10:58 ` Sakari Ailus
2022-03-21 11:24 ` Laurent Pinchart
2022-03-22 12:05 ` Sakari Ailus
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YitA0dI2mM4ACdaL@pendragon.ideasonboard.com \
--to=laurent.pinchart@ideasonboard.com \
--cc=arec.kao@intel.com \
--cc=djrscally@gmail.com \
--cc=hverkuil-cisco@xs4all.nl \
--cc=jimmy.su@intel.com \
--cc=jmondi@jmondi.org \
--cc=kieran.bingham+renesas@ideasonboard.com \
--cc=linux-media@vger.kernel.org \
--cc=martinax.krasteva@intel.com \
--cc=martink@posteo.de \
--cc=paul.elder@ideasonboard.com \
--cc=paul.j.murphy@intel.com \
--cc=paul.kocialkowski@bootlin.com \
--cc=sakari.ailus@linux.intel.com \
--cc=shawnx.tu@intel.com \
--cc=slongerbeam@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox