diff mbox series

[v2,01/13] media: cadence: csi2rx: Support runtime PM

Message ID 20240627-multistream-v2-1-6ae96c54c1c3@ti.com (mailing list archive)
State New
Headers show
Series media: cadence,ti: CSI2RX Multistream Support | expand

Commit Message

Jai Luthra June 27, 2024, 1:09 p.m. UTC
From: Jayshri Pawar <jpawar@cadence.com>

Use runtime power management hooks to save power when CSI-RX is not in
use. Also stop/start any in-progress streams, which might happen during
a system suspend/resume cycle.

Signed-off-by: Jayshri Pawar <jpawar@cadence.com>
Co-developed-by: Jai Luthra <j-luthra@ti.com>
Signed-off-by: Jai Luthra <j-luthra@ti.com>
---
 drivers/media/platform/cadence/cdns-csi2rx.c | 43 +++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

Comments

Tomi Valkeinen June 28, 2024, 8:14 a.m. UTC | #1
Hi,

On 27/06/2024 16:09, Jai Luthra wrote:
> From: Jayshri Pawar <jpawar@cadence.com>
> 
> Use runtime power management hooks to save power when CSI-RX is not in
> use. Also stop/start any in-progress streams, which might happen during
> a system suspend/resume cycle.
> 
> Signed-off-by: Jayshri Pawar <jpawar@cadence.com>
> Co-developed-by: Jai Luthra <j-luthra@ti.com>
> Signed-off-by: Jai Luthra <j-luthra@ti.com>
> ---
>   drivers/media/platform/cadence/cdns-csi2rx.c | 43 +++++++++++++++++++++++++++-
>   1 file changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
> index 6f7d27a48eff..751eadbe61ef 100644
> --- a/drivers/media/platform/cadence/cdns-csi2rx.c
> +++ b/drivers/media/platform/cadence/cdns-csi2rx.c
> @@ -366,6 +366,12 @@ static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
>   	struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev);
>   	int ret = 0;
>   
> +	if (enable) {
> +		ret = pm_runtime_resume_and_get(csi2rx->dev);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
>   	mutex_lock(&csi2rx->lock);
>   
>   	if (enable) {
> @@ -375,8 +381,10 @@ static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
>   		 */
>   		if (!csi2rx->count) {
>   			ret = csi2rx_start(csi2rx);
> -			if (ret)
> +			if (ret) {
> +				pm_runtime_put(csi2rx->dev);
>   				goto out;
> +			}
>   		}
>   
>   		csi2rx->count++;
> @@ -388,6 +396,8 @@ static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
>   		 */
>   		if (!csi2rx->count)
>   			csi2rx_stop(csi2rx);
> +
> +		pm_runtime_put(csi2rx->dev);
>   	}
>   
>   out:
> @@ -661,6 +671,29 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
>   	return ret;
>   }
>   
> +static int csi2rx_suspend(struct device *dev)
> +{
> +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> +
> +	mutex_lock(&csi2rx->lock);
> +	if (csi2rx->count)
> +		csi2rx_stop(csi2rx);
> +	mutex_unlock(&csi2rx->lock);
> +
> +	return 0;
> +}
> +
> +static int csi2rx_resume(struct device *dev)
> +{
> +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> +
> +	mutex_lock(&csi2rx->lock);
> +	if (csi2rx->count)
> +		csi2rx_start(csi2rx);
> +	mutex_unlock(&csi2rx->lock);
> +	return 0;
> +}
> +

I don't think this looks correct. Afaik the runtime suspend/resume is 
not called on system suspend/resume. You could change the 
SET_RUNTIME_PM_OPS to use the same callbacks for runtime and system 
suspend, but I think that's a bad idea. Runtime suspend is not supposed 
to turn off the streaming. The driver is supposed to turn off the 
streaming, then call runtime_put, which would result in runtime suspend 
callback getting called.

  Tomi

>   static int csi2rx_probe(struct platform_device *pdev)
>   {
>   	struct csi2rx_priv *csi2rx;
> @@ -707,6 +740,7 @@ static int csi2rx_probe(struct platform_device *pdev)
>   	if (ret)
>   		goto err_cleanup;
>   
> +	pm_runtime_enable(csi2rx->dev);
>   	ret = v4l2_async_register_subdev(&csi2rx->subdev);
>   	if (ret < 0)
>   		goto err_free_state;
> @@ -721,6 +755,7 @@ static int csi2rx_probe(struct platform_device *pdev)
>   
>   err_free_state:
>   	v4l2_subdev_cleanup(&csi2rx->subdev);
> +	pm_runtime_disable(csi2rx->dev);
>   err_cleanup:
>   	v4l2_async_nf_unregister(&csi2rx->notifier);
>   	v4l2_async_nf_cleanup(&csi2rx->notifier);
> @@ -739,9 +774,14 @@ static void csi2rx_remove(struct platform_device *pdev)
>   	v4l2_async_unregister_subdev(&csi2rx->subdev);
>   	v4l2_subdev_cleanup(&csi2rx->subdev);
>   	media_entity_cleanup(&csi2rx->subdev.entity);
> +	pm_runtime_disable(csi2rx->dev);
>   	kfree(csi2rx);
>   }
>   
> +static const struct dev_pm_ops csi2rx_pm_ops = {
> +	SET_RUNTIME_PM_OPS(csi2rx_suspend, csi2rx_resume, NULL)
> +};
> +
>   static const struct of_device_id csi2rx_of_table[] = {
>   	{ .compatible = "starfive,jh7110-csi2rx" },
>   	{ .compatible = "cdns,csi2rx" },
> @@ -756,6 +796,7 @@ static struct platform_driver csi2rx_driver = {
>   	.driver	= {
>   		.name		= "cdns-csi2rx",
>   		.of_match_table	= csi2rx_of_table,
> +		.pm		= &csi2rx_pm_ops,
>   	},
>   };
>   module_platform_driver(csi2rx_driver);
>
Changhuang Liang June 28, 2024, 8:45 a.m. UTC | #2
Hi Tomi,

[...]
> > +static int csi2rx_suspend(struct device *dev) {
> > +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> > +
> > +	mutex_lock(&csi2rx->lock);
> > +	if (csi2rx->count)
> > +		csi2rx_stop(csi2rx);
> > +	mutex_unlock(&csi2rx->lock);
> > +
> > +	return 0;
> > +}
> > +
> > +static int csi2rx_resume(struct device *dev) {
> > +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> > +
> > +	mutex_lock(&csi2rx->lock);
> > +	if (csi2rx->count)
> > +		csi2rx_start(csi2rx);
> > +	mutex_unlock(&csi2rx->lock);
> > +	return 0;
> > +}
> > +
> 
> I don't think this looks correct. Afaik the runtime suspend/resume is not called
> on system suspend/resume. You could change the SET_RUNTIME_PM_OPS to
> use the same callbacks for runtime and system suspend, but I think that's a
> bad idea. Runtime suspend is not supposed to turn off the streaming. The
> driver is supposed to turn off the streaming, then call runtime_put, which
> would result in runtime suspend callback getting called.
> 

I implemented system suspend/resume based on this patch, I feel good about it.

https://lore.kernel.org/all/20240326031237.25331-1-changhuang.liang@starfivetech.com/

Regards,
Changhuang
Jai Luthra June 28, 2024, 9:38 a.m. UTC | #3
Hi Tomi,

On Jun 28, 2024 at 11:14:50 +0300, Tomi Valkeinen wrote:
> Hi,
> 
> On 27/06/2024 16:09, Jai Luthra wrote:
> > From: Jayshri Pawar <jpawar@cadence.com>
> > 
> > Use runtime power management hooks to save power when CSI-RX is not in
> > use. Also stop/start any in-progress streams, which might happen during
> > a system suspend/resume cycle.
> > 
> > Signed-off-by: Jayshri Pawar <jpawar@cadence.com>
> > Co-developed-by: Jai Luthra <j-luthra@ti.com>
> > Signed-off-by: Jai Luthra <j-luthra@ti.com>
> > ---
> >   drivers/media/platform/cadence/cdns-csi2rx.c | 43 +++++++++++++++++++++++++++-
> >   1 file changed, 42 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
> > index 6f7d27a48eff..751eadbe61ef 100644
> > --- a/drivers/media/platform/cadence/cdns-csi2rx.c
> > +++ b/drivers/media/platform/cadence/cdns-csi2rx.c
> > @@ -366,6 +366,12 @@ static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
> >   	struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev);
> >   	int ret = 0;
> > +	if (enable) {
> > +		ret = pm_runtime_resume_and_get(csi2rx->dev);
> > +		if (ret < 0)
> > +			return ret;
> > +	}
> > +
> >   	mutex_lock(&csi2rx->lock);
> >   	if (enable) {
> > @@ -375,8 +381,10 @@ static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
> >   		 */
> >   		if (!csi2rx->count) {
> >   			ret = csi2rx_start(csi2rx);
> > -			if (ret)
> > +			if (ret) {
> > +				pm_runtime_put(csi2rx->dev);
> >   				goto out;
> > +			}
> >   		}
> >   		csi2rx->count++;
> > @@ -388,6 +396,8 @@ static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
> >   		 */
> >   		if (!csi2rx->count)
> >   			csi2rx_stop(csi2rx);
> > +
> > +		pm_runtime_put(csi2rx->dev);
> >   	}
> >   out:
> > @@ -661,6 +671,29 @@ static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
> >   	return ret;
> >   }
> > +static int csi2rx_suspend(struct device *dev)
> > +{
> > +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> > +
> > +	mutex_lock(&csi2rx->lock);
> > +	if (csi2rx->count)
> > +		csi2rx_stop(csi2rx);
> > +	mutex_unlock(&csi2rx->lock);
> > +
> > +	return 0;
> > +}
> > +
> > +static int csi2rx_resume(struct device *dev)
> > +{
> > +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> > +
> > +	mutex_lock(&csi2rx->lock);
> > +	if (csi2rx->count)
> > +		csi2rx_start(csi2rx);
> > +	mutex_unlock(&csi2rx->lock);
> > +	return 0;
> > +}
> > +
> 
> I don't think this looks correct. Afaik the runtime suspend/resume is not
> called on system suspend/resume. You could change the SET_RUNTIME_PM_OPS to
> use the same callbacks for runtime and system suspend, but I think that's a
> bad idea. Runtime suspend is not supposed to turn off the streaming. The
> driver is supposed to turn off the streaming, then call runtime_put, which
> would result in runtime suspend callback getting called.

Agreed, runtime PM should only be called once streams are stopped and 
device is not in use.

These hooks look like system suspend/resume hooks to me.

I don't think this patch makes much sense in this series anyway, I was 
carrying it to bring the drivers at parity with the vendor kernel.

I will drop this from my series and let Changhuang carry it in his 
series for overall PM support for cdns-csi2rx.

> 
>  Tomi
> 
> >   static int csi2rx_probe(struct platform_device *pdev)
> >   {
> >   	struct csi2rx_priv *csi2rx;
> > @@ -707,6 +740,7 @@ static int csi2rx_probe(struct platform_device *pdev)
> >   	if (ret)
> >   		goto err_cleanup;
> > +	pm_runtime_enable(csi2rx->dev);
> >   	ret = v4l2_async_register_subdev(&csi2rx->subdev);
> >   	if (ret < 0)
> >   		goto err_free_state;
> > @@ -721,6 +755,7 @@ static int csi2rx_probe(struct platform_device *pdev)
> >   err_free_state:
> >   	v4l2_subdev_cleanup(&csi2rx->subdev);
> > +	pm_runtime_disable(csi2rx->dev);
> >   err_cleanup:
> >   	v4l2_async_nf_unregister(&csi2rx->notifier);
> >   	v4l2_async_nf_cleanup(&csi2rx->notifier);
> > @@ -739,9 +774,14 @@ static void csi2rx_remove(struct platform_device *pdev)
> >   	v4l2_async_unregister_subdev(&csi2rx->subdev);
> >   	v4l2_subdev_cleanup(&csi2rx->subdev);
> >   	media_entity_cleanup(&csi2rx->subdev.entity);
> > +	pm_runtime_disable(csi2rx->dev);
> >   	kfree(csi2rx);
> >   }
> > +static const struct dev_pm_ops csi2rx_pm_ops = {
> > +	SET_RUNTIME_PM_OPS(csi2rx_suspend, csi2rx_resume, NULL)
> > +};
> > +
> >   static const struct of_device_id csi2rx_of_table[] = {
> >   	{ .compatible = "starfive,jh7110-csi2rx" },
> >   	{ .compatible = "cdns,csi2rx" },
> > @@ -756,6 +796,7 @@ static struct platform_driver csi2rx_driver = {
> >   	.driver	= {
> >   		.name		= "cdns-csi2rx",
> >   		.of_match_table	= csi2rx_of_table,
> > +		.pm		= &csi2rx_pm_ops,
> >   	},
> >   };
> >   module_platform_driver(csi2rx_driver);
> > 
>
Jai Luthra June 28, 2024, 9:39 a.m. UTC | #4
Hi Changhuang,

On Jun 28, 2024 at 08:45:06 +0000, Changhuang Liang wrote:
> Hi Tomi,
> 
> [...]
> > > +static int csi2rx_suspend(struct device *dev) {
> > > +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> > > +
> > > +	mutex_lock(&csi2rx->lock);
> > > +	if (csi2rx->count)
> > > +		csi2rx_stop(csi2rx);
> > > +	mutex_unlock(&csi2rx->lock);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int csi2rx_resume(struct device *dev) {
> > > +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> > > +
> > > +	mutex_lock(&csi2rx->lock);
> > > +	if (csi2rx->count)
> > > +		csi2rx_start(csi2rx);
> > > +	mutex_unlock(&csi2rx->lock);
> > > +	return 0;
> > > +}
> > > +
> > 
> > I don't think this looks correct. Afaik the runtime suspend/resume is not called
> > on system suspend/resume. You could change the SET_RUNTIME_PM_OPS to
> > use the same callbacks for runtime and system suspend, but I think that's a
> > bad idea. Runtime suspend is not supposed to turn off the streaming. The
> > driver is supposed to turn off the streaming, then call runtime_put, which
> > would result in runtime suspend callback getting called.
> > 
> 
> I implemented system suspend/resume based on this patch, I feel good about it.
> 
> https://lore.kernel.org/all/20240326031237.25331-1-changhuang.liang@starfivetech.com/

Thanks for carrying this patch in your series.

I think Tomi's point still holds - only the system suspend hook should 
try to stop/start the CSI2RX device.

Runtime PM hooks are usually only called when there are no users, so no 
active streams.

> 
> Regards,
> Changhuang
Changhuang Liang June 28, 2024, 10:02 a.m. UTC | #5
Hi, Jai,

> Hi Changhuang,
> 
> On Jun 28, 2024 at 08:45:06 +0000, Changhuang Liang wrote:
> > Hi Tomi,
> >
> > [...]
> > > > +static int csi2rx_suspend(struct device *dev) {
> > > > +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> > > > +
> > > > +	mutex_lock(&csi2rx->lock);
> > > > +	if (csi2rx->count)
> > > > +		csi2rx_stop(csi2rx);
> > > > +	mutex_unlock(&csi2rx->lock);
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int csi2rx_resume(struct device *dev) {
> > > > +	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
> > > > +
> > > > +	mutex_lock(&csi2rx->lock);
> > > > +	if (csi2rx->count)
> > > > +		csi2rx_start(csi2rx);
> > > > +	mutex_unlock(&csi2rx->lock);
> > > > +	return 0;
> > > > +}
> > > > +
> > >
> > > I don't think this looks correct. Afaik the runtime suspend/resume
> > > is not called on system suspend/resume. You could change the
> > > SET_RUNTIME_PM_OPS to use the same callbacks for runtime and
> system
> > > suspend, but I think that's a bad idea. Runtime suspend is not
> > > supposed to turn off the streaming. The driver is supposed to turn
> > > off the streaming, then call runtime_put, which would result in runtime
> suspend callback getting called.
> > >
> >
> > I implemented system suspend/resume based on this patch, I feel good
> about it.
> >
> > https://lore.kernel.org/all/20240326031237.25331-1-changhuang.liang@st
> > arfivetech.com/
> 
> Thanks for carrying this patch in your series.
> 
> I think Tomi's point still holds - only the system suspend hook should try to
> stop/start the CSI2RX device.
> 
> Runtime PM hooks are usually only called when there are no users, so no
> active streams.
> 

OK, I will modify this in my series. 

Regards,
Changhuang
diff mbox series

Patch

diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index 6f7d27a48eff..751eadbe61ef 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -366,6 +366,12 @@  static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev);
 	int ret = 0;
 
+	if (enable) {
+		ret = pm_runtime_resume_and_get(csi2rx->dev);
+		if (ret < 0)
+			return ret;
+	}
+
 	mutex_lock(&csi2rx->lock);
 
 	if (enable) {
@@ -375,8 +381,10 @@  static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
 		 */
 		if (!csi2rx->count) {
 			ret = csi2rx_start(csi2rx);
-			if (ret)
+			if (ret) {
+				pm_runtime_put(csi2rx->dev);
 				goto out;
+			}
 		}
 
 		csi2rx->count++;
@@ -388,6 +396,8 @@  static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
 		 */
 		if (!csi2rx->count)
 			csi2rx_stop(csi2rx);
+
+		pm_runtime_put(csi2rx->dev);
 	}
 
 out:
@@ -661,6 +671,29 @@  static int csi2rx_parse_dt(struct csi2rx_priv *csi2rx)
 	return ret;
 }
 
+static int csi2rx_suspend(struct device *dev)
+{
+	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
+
+	mutex_lock(&csi2rx->lock);
+	if (csi2rx->count)
+		csi2rx_stop(csi2rx);
+	mutex_unlock(&csi2rx->lock);
+
+	return 0;
+}
+
+static int csi2rx_resume(struct device *dev)
+{
+	struct csi2rx_priv *csi2rx = dev_get_drvdata(dev);
+
+	mutex_lock(&csi2rx->lock);
+	if (csi2rx->count)
+		csi2rx_start(csi2rx);
+	mutex_unlock(&csi2rx->lock);
+	return 0;
+}
+
 static int csi2rx_probe(struct platform_device *pdev)
 {
 	struct csi2rx_priv *csi2rx;
@@ -707,6 +740,7 @@  static int csi2rx_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_cleanup;
 
+	pm_runtime_enable(csi2rx->dev);
 	ret = v4l2_async_register_subdev(&csi2rx->subdev);
 	if (ret < 0)
 		goto err_free_state;
@@ -721,6 +755,7 @@  static int csi2rx_probe(struct platform_device *pdev)
 
 err_free_state:
 	v4l2_subdev_cleanup(&csi2rx->subdev);
+	pm_runtime_disable(csi2rx->dev);
 err_cleanup:
 	v4l2_async_nf_unregister(&csi2rx->notifier);
 	v4l2_async_nf_cleanup(&csi2rx->notifier);
@@ -739,9 +774,14 @@  static void csi2rx_remove(struct platform_device *pdev)
 	v4l2_async_unregister_subdev(&csi2rx->subdev);
 	v4l2_subdev_cleanup(&csi2rx->subdev);
 	media_entity_cleanup(&csi2rx->subdev.entity);
+	pm_runtime_disable(csi2rx->dev);
 	kfree(csi2rx);
 }
 
+static const struct dev_pm_ops csi2rx_pm_ops = {
+	SET_RUNTIME_PM_OPS(csi2rx_suspend, csi2rx_resume, NULL)
+};
+
 static const struct of_device_id csi2rx_of_table[] = {
 	{ .compatible = "starfive,jh7110-csi2rx" },
 	{ .compatible = "cdns,csi2rx" },
@@ -756,6 +796,7 @@  static struct platform_driver csi2rx_driver = {
 	.driver	= {
 		.name		= "cdns-csi2rx",
 		.of_match_table	= csi2rx_of_table,
+		.pm		= &csi2rx_pm_ops,
 	},
 };
 module_platform_driver(csi2rx_driver);