The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support
@ 2026-06-16 17:05 Tommaso Merciai
  2026-06-16 17:05 ` [PATCH 1/9] media: rzg2l-cru: Add device_link from CRU to CSI-2 Tommaso Merciai
                   ` (9 more replies)
  0 siblings, 10 replies; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Dear All,

This patch series adds suspend/resume support to the CRU/CSI-2 driver.
The series has been tested using ov5645 camera sensor connected to
the RZ/G3E via CSI-2 connector of the RZ SMARC Carrier II board.

Thanks & Regards,
Tommaso

Tommaso Merciai (9):
  media: rzg2l-cru: Add device_link from CRU to CSI-2
  media: rzg2l-cru: csi2: Add device_link from CSI-2 to sensor
  media: rzg2l-cru: Use bulk reset API in rzg2l_cru_start_streaming_vq()
  media: rzg2l-cru: Drop stop streaming function
  media: rzg2l-cru: Move active_slot reset into rzg2l_cru_set_stream()
  media: rzg2l-cru: Add suspend/resume support
  media: rzg2l-cru: csi2: Add system sleep PM support
  media: i2c: ov5645: Switch to RUNTIME_PM_OPS() and pm_ptr()
  media: i2c: ov5645: Add suspend/resume support

 drivers/media/i2c/ov5645.c                    |  5 +-
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 74 +++++++++++++++++++
 .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  5 ++
 .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 25 +++++--
 .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 55 ++++++++------
 5 files changed, 135 insertions(+), 29 deletions(-)

-- 
2.54.0


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1/9] media: rzg2l-cru: Add device_link from CRU to CSI-2
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
@ 2026-06-16 17:05 ` Tommaso Merciai
  2026-07-27  9:45   ` Jacopo Mondi
  2026-07-27  9:50   ` Jacopo Mondi
  2026-06-16 17:05 ` [PATCH 2/9] media: rzg2l-cru: csi2: Add device_link from CSI-2 to sensor Tommaso Merciai
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

The CRU device depends on CSI-2 to operate. Without an explicit
device_link the PM core has no knowledge of this dependency and may
suspend CSI-2 while CRU is still active, or resume CRU before CSI-2
is ready.

Add a DL_FLAG_STATELESS device_link from the CRU to CSI-2 when the
CSI-2 subdev binds. This instructs the PM core to suspend CRU before
CSI-2 and to resume CSI-2 before CRU. The link is deleted on unbind.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 3c5fbd857371..1b12d91eaec9 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -101,6 +101,7 @@ static void rzg2l_cru_group_notify_unbind(struct v4l2_async_notifier *notifier,
 	mutex_lock(&cru->mdev_lock);
 
 	if (cru->csi.asd == asd) {
+		device_link_remove(cru->dev, subdev->dev);
 		cru->csi.subdev = NULL;
 		dev_dbg(cru->dev, "Unbind CSI-2 %s\n", subdev->name);
 	}
@@ -118,6 +119,12 @@ static int rzg2l_cru_group_notify_bound(struct v4l2_async_notifier *notifier,
 
 	if (cru->csi.asd == asd) {
 		cru->csi.subdev = subdev;
+		if (!device_link_add(cru->dev, subdev->dev, DL_FLAG_STATELESS)) {
+			dev_err(cru->dev, "Failed to create device link to CSI-2 %s\n",
+				subdev->name);
+			mutex_unlock(&cru->mdev_lock);
+			return -EINVAL;
+		}
 		dev_dbg(cru->dev, "Bound CSI-2 %s\n", subdev->name);
 	}
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 2/9] media: rzg2l-cru: csi2: Add device_link from CSI-2 to sensor
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
  2026-06-16 17:05 ` [PATCH 1/9] media: rzg2l-cru: Add device_link from CRU to CSI-2 Tommaso Merciai
@ 2026-06-16 17:05 ` Tommaso Merciai
  2026-07-27  9:48   ` Jacopo Mondi
  2026-06-16 17:05 ` [PATCH 3/9] media: rzg2l-cru: Use bulk reset API in rzg2l_cru_start_streaming_vq() Tommaso Merciai
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

The CSI-2 receiver depends on its remote sensor being powered and
configured before it can receive data. Without an explicit device_link
the PM core has no knowledge of this dependency and may suspend the
sensor while CSI-2 is still active, or resume CSI-2 before the sensor
is ready.

Add a DL_FLAG_STATELESS device_link from the CSI-2 device to the sensor
device when the sensor subdev binds. This instructs the PM core to
suspend CSI-2 before the sensor and to resume the sensor before CSI-2.
The link is deleted on unbind.

Move csi2->remote_source assignment to the end of the function.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 24 +++++++++++++++----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 6dc4b53607b4..3a4bc4ef72fc 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -773,15 +773,28 @@ static int rzg2l_csi2_notify_bound(struct v4l2_async_notifier *notifier,
 				   struct v4l2_async_connection *asd)
 {
 	struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier);
+	int ret;
 
-	csi2->remote_source = subdev;
+	if (!device_link_add(csi2->dev, subdev->dev, DL_FLAG_STATELESS)) {
+		dev_err(csi2->dev, "Failed to create device link to sensor %s\n",
+			subdev->name);
+		return -EINVAL;
+	}
 
 	dev_dbg(csi2->dev, "Bound subdev: %s pad\n", subdev->name);
 
-	return media_create_pad_link(&subdev->entity, RZG2L_CSI2_SINK,
-				     &csi2->subdev.entity, 0,
-				     MEDIA_LNK_FL_ENABLED |
-				     MEDIA_LNK_FL_IMMUTABLE);
+	ret = media_create_pad_link(&subdev->entity, RZG2L_CSI2_SINK,
+				    &csi2->subdev.entity, 0,
+				    MEDIA_LNK_FL_ENABLED |
+				    MEDIA_LNK_FL_IMMUTABLE);
+	if (ret) {
+		device_link_remove(csi2->dev, subdev->dev);
+		return ret;
+	}
+
+	csi2->remote_source = subdev;
+
+	return 0;
 }
 
 static void rzg2l_csi2_notify_unbind(struct v4l2_async_notifier *notifier,
@@ -790,6 +803,7 @@ static void rzg2l_csi2_notify_unbind(struct v4l2_async_notifier *notifier,
 {
 	struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier);
 
+	device_link_remove(csi2->dev, subdev->dev);
 	csi2->remote_source = NULL;
 
 	dev_dbg(csi2->dev, "Unbind subdev %s\n", subdev->name);
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 3/9] media: rzg2l-cru: Use bulk reset API in rzg2l_cru_start_streaming_vq()
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
  2026-06-16 17:05 ` [PATCH 1/9] media: rzg2l-cru: Add device_link from CRU to CSI-2 Tommaso Merciai
  2026-06-16 17:05 ` [PATCH 2/9] media: rzg2l-cru: csi2: Add device_link from CSI-2 to sensor Tommaso Merciai
@ 2026-06-16 17:05 ` Tommaso Merciai
  2026-07-27  9:55   ` Jacopo Mondi
  2026-06-16 17:05 ` [PATCH 4/9] media: rzg2l-cru: Drop stop streaming function Tommaso Merciai
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Replace individual reset_control_deassert() calls for aresetn and presetn
with reset_control_bulk_deassert(), and consolidate the error path labels
into a single err_assert_resets using reset_control_bulk_assert().

No functional changes intended.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 23 ++++++++-----------
 1 file changed, 9 insertions(+), 14 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 5185a547461d..bf61a74f8f74 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -672,6 +672,10 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
 static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
 {
 	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
+	struct reset_control_bulk_data resets[] = {
+		{ .rstc = cru->aresetn },
+		{ .rstc = cru->presetn },
+	};
 	int ret;
 
 	ret = pm_runtime_resume_and_get(cru->dev);
@@ -683,19 +687,12 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
 		goto err_pm_put;
 
 	/* Release reset state */
-	ret = reset_control_deassert(cru->aresetn);
+	ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
 	if (ret) {
-		dev_err(cru->dev, "failed to deassert aresetn\n");
+		dev_err(cru->dev, "failed to deassert resets\n");
 		goto err_vclk_disable;
 	}
 
-	ret = reset_control_deassert(cru->presetn);
-	if (ret) {
-		reset_control_assert(cru->aresetn);
-		dev_err(cru->dev, "failed to deassert presetn\n");
-		goto assert_aresetn;
-	}
-
 	/* Allocate scratch buffer */
 	cru->scratch = dma_alloc_coherent(cru->dev, cru->format.sizeimage,
 					  &cru->scratch_phys, GFP_KERNEL);
@@ -703,7 +700,7 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
 		rzg2l_cru_return_buffers(cru, VB2_BUF_STATE_QUEUED);
 		dev_err(cru->dev, "Failed to allocate scratch buffer\n");
 		ret = -ENOMEM;
-		goto assert_presetn;
+		goto err_assert_resets;
 	}
 
 	cru->active_slot = 0;
@@ -722,11 +719,9 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
 	if (ret)
 		dma_free_coherent(cru->dev, cru->format.sizeimage, cru->scratch,
 				  cru->scratch_phys);
-assert_presetn:
-	reset_control_assert(cru->presetn);
 
-assert_aresetn:
-	reset_control_assert(cru->aresetn);
+err_assert_resets:
+	reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
 
 err_vclk_disable:
 	clk_disable_unprepare(cru->vclk);
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 4/9] media: rzg2l-cru: Drop stop streaming function
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
                   ` (2 preceding siblings ...)
  2026-06-16 17:05 ` [PATCH 3/9] media: rzg2l-cru: Use bulk reset API in rzg2l_cru_start_streaming_vq() Tommaso Merciai
@ 2026-06-16 17:05 ` Tommaso Merciai
  2026-07-27  9:55   ` Jacopo Mondi
  2026-06-16 17:05 ` [PATCH 5/9] media: rzg2l-cru: Move active_slot reset into rzg2l_cru_set_stream() Tommaso Merciai
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Drop rzg2l_cru_stop_streaming() function and replace that with the
direct call to rzg2l_cru_set_stream(cru, 0).

This is a refactoring with no functional changes.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index bf61a74f8f74..e283d9b69342 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -583,11 +583,6 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
 	return ret;
 }
 
-static void rzg2l_cru_stop_streaming(struct rzg2l_cru_dev *cru)
-{
-	rzg2l_cru_set_stream(cru, 0);
-}
-
 irqreturn_t rzg2l_cru_irq(int irq, void *data)
 {
 	struct rzg2l_cru_dev *cru = data;
@@ -736,7 +731,7 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq)
 {
 	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
 
-	rzg2l_cru_stop_streaming(cru);
+	rzg2l_cru_set_stream(cru, 0);
 
 	/* Free scratch buffer */
 	dma_free_coherent(cru->dev, cru->format.sizeimage,
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 5/9] media: rzg2l-cru: Move active_slot reset into rzg2l_cru_set_stream()
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
                   ` (3 preceding siblings ...)
  2026-06-16 17:05 ` [PATCH 4/9] media: rzg2l-cru: Drop stop streaming function Tommaso Merciai
@ 2026-06-16 17:05 ` Tommaso Merciai
  2026-07-27 10:11   ` Jacopo Mondi
  2026-06-16 17:05 ` [PATCH 6/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

active_slot tracks the current DMA slot index and must always be reset
to zero before starting a new stream. Previously callers were responsible
for this reset before each rzg2l_cru_set_stream(cru, 1) invocation.

Move the reset inside rzg2l_cru_set_stream() so the invariant is
enforced in a single place and future callers cannot accidentally omit
it.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index e283d9b69342..71d9c671f739 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -559,6 +559,7 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
 		return stream_off_ret;
 	}
 
+	cru->active_slot = 0;
 	pipe = media_entity_pipeline(&sd->entity) ? : &cru->vdev.pipe;
 	ret = video_device_pipeline_start(&cru->vdev, pipe);
 	if (ret)
@@ -698,7 +699,6 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
 		goto err_assert_resets;
 	}
 
-	cru->active_slot = 0;
 	cru->sequence = 0;
 
 	ret = rzg2l_cru_set_stream(cru, 1);
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 6/9] media: rzg2l-cru: Add suspend/resume support
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
                   ` (4 preceding siblings ...)
  2026-06-16 17:05 ` [PATCH 5/9] media: rzg2l-cru: Move active_slot reset into rzg2l_cru_set_stream() Tommaso Merciai
@ 2026-06-16 17:05 ` Tommaso Merciai
  2026-07-27 10:20   ` Jacopo Mondi
  2026-06-16 17:05 ` [PATCH 7/9] media: rzg2l-cru: csi2: Add system sleep PM support Tommaso Merciai
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

The CRU has no system sleep hooks, leaving the device in an undefined
state across suspend/resume.

On suspend, stop the pipeline, requeue any buffers held by the hardware
back to the software queue, and assert the resets. On resume, deassert
the resets and restart streaming.

Add a bool running field to track pipeline state. stop_streaming uses it
to skip rzg2l_cru_set_stream() when the pipeline was already stopped by
a failed resume, avoiding a double-stop. Export rzg2l_cru_set_stream()
and add rzg2l_cru_requeue_active_buffers() for use by the PM callbacks.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 67 +++++++++++++++++++
 .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  5 ++
 .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 25 ++++++-
 3 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 1b12d91eaec9..2840f40e4c01 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -246,6 +246,72 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru)
 	return 0;
 }
 
+static int rzg2l_cru_pm_suspend(struct device *dev)
+{
+	struct rzg2l_cru_dev *cru = dev_get_drvdata(dev);
+	struct reset_control_bulk_data resets[] = {
+		{ .rstc = cru->aresetn },
+		{ .rstc = cru->presetn },
+	};
+	int ret;
+
+	if (!cru->running)
+		return 0;
+
+	ret = rzg2l_cru_set_stream(cru, 0);
+	if (ret)
+		return ret;
+
+	rzg2l_cru_requeue_active_buffers(cru);
+
+	ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
+	if (ret) {
+		if (rzg2l_cru_set_stream(cru, 1))
+			vb2_queue_error(&cru->queue);
+
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rzg2l_cru_pm_resume(struct device *dev)
+{
+	struct rzg2l_cru_dev *cru = dev_get_drvdata(dev);
+	struct reset_control_bulk_data resets[] = {
+		{ .rstc = cru->aresetn },
+		{ .rstc = cru->presetn },
+	};
+	int ret;
+
+	if (!cru->running)
+		return 0;
+
+	ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
+	if (ret)
+		goto err_running;
+
+	ret = rzg2l_cru_set_stream(cru, 1);
+	if (ret) {
+		dev_err(cru->dev, "Failed to restart streaming: %d\n", ret);
+		goto err_reset_assert;
+	}
+
+	return 0;
+
+err_reset_assert:
+	reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
+err_running:
+	cru->running = false;
+	vb2_queue_error(&cru->queue);
+
+	return ret;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rzg2l_cru_pm_ops,
+				rzg2l_cru_pm_suspend,
+				rzg2l_cru_pm_resume);
+
 static int rzg2l_cru_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -437,6 +503,7 @@ static struct platform_driver rzg2l_cru_driver = {
 	.driver = {
 		.name = "rzg2l-cru",
 		.of_match_table = rzg2l_cru_of_id_table,
+		.pm = pm_sleep_ptr(&rzg2l_cru_pm_ops),
 	},
 	.probe = rzg2l_cru_probe,
 	.remove = rzg2l_cru_remove,
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 5bf334e173d2..c079cad41266 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -161,12 +161,17 @@ struct rzg2l_cru_dev {
 	struct list_head buf_list;
 	unsigned int sequence;
 
+	bool running;
+
 	struct v4l2_pix_format format;
 };
 
 int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru);
 void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru);
 
+int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on);
+void rzg2l_cru_requeue_active_buffers(struct rzg2l_cru_dev *cru);
+
 int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru);
 void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
 
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 71d9c671f739..46a0823e1300 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -155,6 +155,23 @@ static void rzg2l_cru_return_buffers(struct rzg2l_cru_dev *cru,
 	}
 }
 
+void rzg2l_cru_requeue_active_buffers(struct rzg2l_cru_dev *cru)
+{
+	unsigned int i;
+
+	scoped_guard(spinlock_irqsave, &cru->hw_lock) {
+		for (i = 0; i < cru->num_buf; i++) {
+			if (!cru->queue_buf[i])
+				continue;
+			scoped_guard(spinlock_irqsave, &cru->qlock) {
+				list_add_tail(to_buf_list(cru->queue_buf[i]),
+					      &cru->buf_list);
+			}
+			cru->queue_buf[i] = NULL;
+		}
+	}
+}
+
 static int rzg2l_cru_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
 				 unsigned int *nplanes, unsigned int sizes[],
 				 struct device *alloc_devs[])
@@ -528,7 +545,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
 	return 0;
 }
 
-static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
+int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
 {
 	struct media_pipeline *pipe;
 	struct v4l2_subdev *sd;
@@ -707,6 +724,7 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
 		goto out;
 	}
 
+	cru->running = true;
 	dev_dbg(cru->dev, "Starting to capture\n");
 	return 0;
 
@@ -731,7 +749,10 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq)
 {
 	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
 
-	rzg2l_cru_set_stream(cru, 0);
+	if (cru->running) {
+		rzg2l_cru_set_stream(cru, 0);
+		cru->running = false;
+	}
 
 	/* Free scratch buffer */
 	dma_free_coherent(cru->dev, cru->format.sizeimage,
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 7/9] media: rzg2l-cru: csi2: Add system sleep PM support
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
                   ` (5 preceding siblings ...)
  2026-06-16 17:05 ` [PATCH 6/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
@ 2026-06-16 17:05 ` Tommaso Merciai
  2026-06-16 17:05 ` [PATCH 8/9] media: i2c: ov5645: Switch to RUNTIME_PM_OPS() and pm_ptr() Tommaso Merciai
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

The rzg2l-csi2 driver has runtime PM callbacks but no system sleep
hooks,leaving the device in an undefined state across system
suspend/resume.

Wire up SYSTEM_SLEEP_PM_OPS with pm_runtime_force_suspend/resume to
reuse the existing runtime PM callbacks for system sleep.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index 3a4bc4ef72fc..ae1a1816b90a 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -1042,6 +1042,7 @@ static int rzg2l_csi2_pm_runtime_resume(struct device *dev)
 static const struct dev_pm_ops rzg2l_csi2_pm_ops = {
 	RUNTIME_PM_OPS(rzg2l_csi2_pm_runtime_suspend,
 		       rzg2l_csi2_pm_runtime_resume, NULL)
+	SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
 };
 
 static const struct of_device_id rzg2l_csi2_of_table[] = {
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 8/9] media: i2c: ov5645: Switch to RUNTIME_PM_OPS() and pm_ptr()
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
                   ` (6 preceding siblings ...)
  2026-06-16 17:05 ` [PATCH 7/9] media: rzg2l-cru: csi2: Add system sleep PM support Tommaso Merciai
@ 2026-06-16 17:05 ` Tommaso Merciai
  2026-06-16 17:05 ` [PATCH 9/9] media: i2c: ov5645: Add suspend/resume support Tommaso Merciai
  2026-07-15  8:47 ` [PATCH 0/9] media: rzg2l-cru: " Tommaso Merciai
  9 siblings, 0 replies; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Replace SET_RUNTIME_PM_OPS() with RUNTIME_PM_OPS() and use pm_ptr()
for the power management operations. This brings the driver in line
with current kernel power management APIs and prepares for future
deprecations.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/media/i2c/ov5645.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c
index c772ef6e51d2..14692d128571 100644
--- a/drivers/media/i2c/ov5645.c
+++ b/drivers/media/i2c/ov5645.c
@@ -1231,14 +1231,14 @@ static const struct of_device_id ov5645_of_match[] = {
 MODULE_DEVICE_TABLE(of, ov5645_of_match);
 
 static const struct dev_pm_ops ov5645_pm_ops = {
-	SET_RUNTIME_PM_OPS(ov5645_set_power_off, ov5645_set_power_on, NULL)
+	RUNTIME_PM_OPS(ov5645_set_power_off, ov5645_set_power_on, NULL)
 };
 
 static struct i2c_driver ov5645_i2c_driver = {
 	.driver = {
 		.of_match_table = ov5645_of_match,
 		.name  = "ov5645",
-		.pm = &ov5645_pm_ops,
+		.pm = pm_ptr(&ov5645_pm_ops),
 	},
 	.probe = ov5645_probe,
 	.remove = ov5645_remove,
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 9/9] media: i2c: ov5645: Add suspend/resume support
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
                   ` (7 preceding siblings ...)
  2026-06-16 17:05 ` [PATCH 8/9] media: i2c: ov5645: Switch to RUNTIME_PM_OPS() and pm_ptr() Tommaso Merciai
@ 2026-06-16 17:05 ` Tommaso Merciai
  2026-07-15  8:47 ` [PATCH 0/9] media: rzg2l-cru: " Tommaso Merciai
  9 siblings, 0 replies; 18+ messages in thread
From: Tommaso Merciai @ 2026-06-16 17:05 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Tommaso Merciai, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Add suspend/resume support to the ov5645 driver.

Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
---
 drivers/media/i2c/ov5645.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c
index 14692d128571..ac64936bef09 100644
--- a/drivers/media/i2c/ov5645.c
+++ b/drivers/media/i2c/ov5645.c
@@ -1232,6 +1232,7 @@ MODULE_DEVICE_TABLE(of, ov5645_of_match);
 
 static const struct dev_pm_ops ov5645_pm_ops = {
 	RUNTIME_PM_OPS(ov5645_set_power_off, ov5645_set_power_on, NULL)
+	SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
 };
 
 static struct i2c_driver ov5645_i2c_driver = {
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support
  2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
                   ` (8 preceding siblings ...)
  2026-06-16 17:05 ` [PATCH 9/9] media: i2c: ov5645: Add suspend/resume support Tommaso Merciai
@ 2026-07-15  8:47 ` Tommaso Merciai
  9 siblings, 0 replies; 18+ messages in thread
From: Tommaso Merciai @ 2026-07-15  8:47 UTC (permalink / raw)
  To: tomm.merciai
  Cc: linux-renesas-soc, biju.das.jz, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Dear All,

On Tue, Jun 16, 2026 at 07:05:30PM +0200, Tommaso Merciai wrote:
> Dear All,
> 
> This patch series adds suspend/resume support to the CRU/CSI-2 driver.
> The series has been tested using ov5645 camera sensor connected to
> the RZ/G3E via CSI-2 connector of the RZ SMARC Carrier II board.
> 
> Thanks & Regards,
> Tommaso
> 
> Tommaso Merciai (9):
>   media: rzg2l-cru: Add device_link from CRU to CSI-2
>   media: rzg2l-cru: csi2: Add device_link from CSI-2 to sensor
>   media: rzg2l-cru: Use bulk reset API in rzg2l_cru_start_streaming_vq()
>   media: rzg2l-cru: Drop stop streaming function
>   media: rzg2l-cru: Move active_slot reset into rzg2l_cru_set_stream()
>   media: rzg2l-cru: Add suspend/resume support
>   media: rzg2l-cru: csi2: Add system sleep PM support
>   media: i2c: ov5645: Switch to RUNTIME_PM_OPS() and pm_ptr()
>   media: i2c: ov5645: Add suspend/resume support

A gentle ping on this series.

Kind Regards,
Tommaso

> 
>  drivers/media/i2c/ov5645.c                    |  5 +-
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 74 +++++++++++++++++++
>  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  5 ++
>  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 25 +++++--
>  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 55 ++++++++------
>  5 files changed, 135 insertions(+), 29 deletions(-)
> 
> -- 
> 2.54.0
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/9] media: rzg2l-cru: Add device_link from CRU to CSI-2
  2026-06-16 17:05 ` [PATCH 1/9] media: rzg2l-cru: Add device_link from CRU to CSI-2 Tommaso Merciai
@ 2026-07-27  9:45   ` Jacopo Mondi
  2026-07-27  9:50   ` Jacopo Mondi
  1 sibling, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-07-27  9:45 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, biju.das.jz, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Hi Tommaso

On Tue, Jun 16, 2026 at 07:05:31PM +0200, Tommaso Merciai wrote:
> The CRU device depends on CSI-2 to operate. Without an explicit
> device_link the PM core has no knowledge of this dependency and may
> suspend CSI-2 while CRU is still active, or resume CRU before CSI-2
> is ready.
>
> Add a DL_FLAG_STATELESS device_link from the CRU to CSI-2 when the
> CSI-2 subdev binds. This instructs the PM core to suspend CRU before
> CSI-2 and to resume CSI-2 before CRU. The link is deleted on unbind.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 3c5fbd857371..1b12d91eaec9 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -101,6 +101,7 @@ static void rzg2l_cru_group_notify_unbind(struct v4l2_async_notifier *notifier,
>  	mutex_lock(&cru->mdev_lock);
>
>  	if (cru->csi.asd == asd) {
> +		device_link_remove(cru->dev, subdev->dev);
>  		cru->csi.subdev = NULL;
>  		dev_dbg(cru->dev, "Unbind CSI-2 %s\n", subdev->name);
>  	}
> @@ -118,6 +119,12 @@ static int rzg2l_cru_group_notify_bound(struct v4l2_async_notifier *notifier,
>
>  	if (cru->csi.asd == asd) {
>  		cru->csi.subdev = subdev;
> +		if (!device_link_add(cru->dev, subdev->dev, DL_FLAG_STATELESS)) {

So, cru-core and cru-csi2 are two different drivers, guarded by two
different config symbols, both live in drivers/media/platforms/renesas/rzg2l-cru/

I guess it doesn't make much sense to have one without the other, but
the build system allows that. That might be the reason why you used
STATELESS here, but since this call happens at _bound() time, doesn't
it mean we're sure the supplier driver is there and has probed
correctly already ?

I guess you don't want DL_FLAG_PM_RUNTIME as this series is for system
suspend/resume, right ?

> +			dev_err(cru->dev, "Failed to create device link to CSI-2 %s\n",
> +				subdev->name);
> +			mutex_unlock(&cru->mdev_lock);
> +			return -EINVAL;
> +		}
>  		dev_dbg(cru->dev, "Bound CSI-2 %s\n", subdev->name);
>  	}
>
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/9] media: rzg2l-cru: csi2: Add device_link from CSI-2 to sensor
  2026-06-16 17:05 ` [PATCH 2/9] media: rzg2l-cru: csi2: Add device_link from CSI-2 to sensor Tommaso Merciai
@ 2026-07-27  9:48   ` Jacopo Mondi
  0 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-07-27  9:48 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, biju.das.jz, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Hi Tommaso

On Tue, Jun 16, 2026 at 07:05:32PM +0200, Tommaso Merciai wrote:
> The CSI-2 receiver depends on its remote sensor being powered and
> configured before it can receive data. Without an explicit device_link
> the PM core has no knowledge of this dependency and may suspend the
> sensor while CSI-2 is still active, or resume CSI-2 before the sensor
> is ready.
>
> Add a DL_FLAG_STATELESS device_link from the CSI-2 device to the sensor
> device when the sensor subdev binds. This instructs the PM core to
> suspend CSI-2 before the sensor and to resume the sensor before CSI-2.
> The link is deleted on unbind.
>
> Move csi2->remote_source assignment to the end of the function.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../platform/renesas/rzg2l-cru/rzg2l-csi2.c   | 24 +++++++++++++++----
>  1 file changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> index 6dc4b53607b4..3a4bc4ef72fc 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
> @@ -773,15 +773,28 @@ static int rzg2l_csi2_notify_bound(struct v4l2_async_notifier *notifier,
>  				   struct v4l2_async_connection *asd)
>  {
>  	struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier);
> +	int ret;
>
> -	csi2->remote_source = subdev;
> +	if (!device_link_add(csi2->dev, subdev->dev, DL_FLAG_STATELESS)) {

As cru-csi2 supports runtime suspend/resume, should you also add
DL_FLAG_PM_RUNTIME ?

> +		dev_err(csi2->dev, "Failed to create device link to sensor %s\n",
> +			subdev->name);
> +		return -EINVAL;
> +	}
>
>  	dev_dbg(csi2->dev, "Bound subdev: %s pad\n", subdev->name);
>
> -	return media_create_pad_link(&subdev->entity, RZG2L_CSI2_SINK,
> -				     &csi2->subdev.entity, 0,
> -				     MEDIA_LNK_FL_ENABLED |
> -				     MEDIA_LNK_FL_IMMUTABLE);
> +	ret = media_create_pad_link(&subdev->entity, RZG2L_CSI2_SINK,
> +				    &csi2->subdev.entity, 0,
> +				    MEDIA_LNK_FL_ENABLED |
> +				    MEDIA_LNK_FL_IMMUTABLE);
> +	if (ret) {
> +		device_link_remove(csi2->dev, subdev->dev);
> +		return ret;
> +	}
> +
> +	csi2->remote_source = subdev;
> +
> +	return 0;
>  }
>
>  static void rzg2l_csi2_notify_unbind(struct v4l2_async_notifier *notifier,
> @@ -790,6 +803,7 @@ static void rzg2l_csi2_notify_unbind(struct v4l2_async_notifier *notifier,
>  {
>  	struct rzg2l_csi2 *csi2 = notifier_to_csi2(notifier);
>
> +	device_link_remove(csi2->dev, subdev->dev);
>  	csi2->remote_source = NULL;
>
>  	dev_dbg(csi2->dev, "Unbind subdev %s\n", subdev->name);
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/9] media: rzg2l-cru: Add device_link from CRU to CSI-2
  2026-06-16 17:05 ` [PATCH 1/9] media: rzg2l-cru: Add device_link from CRU to CSI-2 Tommaso Merciai
  2026-07-27  9:45   ` Jacopo Mondi
@ 2026-07-27  9:50   ` Jacopo Mondi
  1 sibling, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-07-27  9:50 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, biju.das.jz, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Hi Tommaso
 one more thing

On Tue, Jun 16, 2026 at 07:05:31PM +0200, Tommaso Merciai wrote:
> The CRU device depends on CSI-2 to operate. Without an explicit
> device_link the PM core has no knowledge of this dependency and may
> suspend CSI-2 while CRU is still active, or resume CRU before CSI-2
> is ready.
>
> Add a DL_FLAG_STATELESS device_link from the CRU to CSI-2 when the
> CSI-2 subdev binds. This instructs the PM core to suspend CRU before
> CSI-2 and to resume CSI-2 before CRU. The link is deleted on unbind.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 3c5fbd857371..1b12d91eaec9 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -101,6 +101,7 @@ static void rzg2l_cru_group_notify_unbind(struct v4l2_async_notifier *notifier,
>  	mutex_lock(&cru->mdev_lock);

What is the mutex protecting here ?

(yes, unrelated to this patch, I know, just wondering if you should
take the occasion to remove the guards from bind/unbind)

>
>  	if (cru->csi.asd == asd) {
> +		device_link_remove(cru->dev, subdev->dev);
>  		cru->csi.subdev = NULL;
>  		dev_dbg(cru->dev, "Unbind CSI-2 %s\n", subdev->name);
>  	}
> @@ -118,6 +119,12 @@ static int rzg2l_cru_group_notify_bound(struct v4l2_async_notifier *notifier,
>
>  	if (cru->csi.asd == asd) {
>  		cru->csi.subdev = subdev;
> +		if (!device_link_add(cru->dev, subdev->dev, DL_FLAG_STATELESS)) {
> +			dev_err(cru->dev, "Failed to create device link to CSI-2 %s\n",
> +				subdev->name);
> +			mutex_unlock(&cru->mdev_lock);
> +			return -EINVAL;
> +		}
>  		dev_dbg(cru->dev, "Bound CSI-2 %s\n", subdev->name);
>  	}
>
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 3/9] media: rzg2l-cru: Use bulk reset API in rzg2l_cru_start_streaming_vq()
  2026-06-16 17:05 ` [PATCH 3/9] media: rzg2l-cru: Use bulk reset API in rzg2l_cru_start_streaming_vq() Tommaso Merciai
@ 2026-07-27  9:55   ` Jacopo Mondi
  0 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-07-27  9:55 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, biju.das.jz, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Hi Tommaso

On Tue, Jun 16, 2026 at 07:05:33PM +0200, Tommaso Merciai wrote:
> Replace individual reset_control_deassert() calls for aresetn and presetn
> with reset_control_bulk_deassert(), and consolidate the error path labels
> into a single err_assert_resets using reset_control_bulk_assert().
>
> No functional changes intended.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 23 ++++++++-----------
>  1 file changed, 9 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index 5185a547461d..bf61a74f8f74 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -672,6 +672,10 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
>  static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count)
>  {
>  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
> +	struct reset_control_bulk_data resets[] = {
> +		{ .rstc = cru->aresetn },
> +		{ .rstc = cru->presetn },
> +	};
>  	int ret;
>
>  	ret = pm_runtime_resume_and_get(cru->dev);
> @@ -683,19 +687,12 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
>  		goto err_pm_put;
>
>  	/* Release reset state */
> -	ret = reset_control_deassert(cru->aresetn);
> +	ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
>  	if (ret) {
> -		dev_err(cru->dev, "failed to deassert aresetn\n");
> +		dev_err(cru->dev, "failed to deassert resets\n");
>  		goto err_vclk_disable;
>  	}
>
> -	ret = reset_control_deassert(cru->presetn);
> -	if (ret) {
> -		reset_control_assert(cru->aresetn);
> -		dev_err(cru->dev, "failed to deassert presetn\n");
> -		goto assert_aresetn;
> -	}
> -

Is there any ordering requirement in the reset signal de-assertion ?

>  	/* Allocate scratch buffer */
>  	cru->scratch = dma_alloc_coherent(cru->dev, cru->format.sizeimage,
>  					  &cru->scratch_phys, GFP_KERNEL);
> @@ -703,7 +700,7 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
>  		rzg2l_cru_return_buffers(cru, VB2_BUF_STATE_QUEUED);
>  		dev_err(cru->dev, "Failed to allocate scratch buffer\n");
>  		ret = -ENOMEM;
> -		goto assert_presetn;
> +		goto err_assert_resets;
>  	}
>
>  	cru->active_slot = 0;
> @@ -722,11 +719,9 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
>  	if (ret)
>  		dma_free_coherent(cru->dev, cru->format.sizeimage, cru->scratch,
>  				  cru->scratch_phys);
> -assert_presetn:
> -	reset_control_assert(cru->presetn);
>
> -assert_aresetn:
> -	reset_control_assert(cru->aresetn);
> +err_assert_resets:
> +	reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
>

Do you happen to know why rzg2l_cru_stop_streaming_vq() only assert
'presetn' and not 'aresetn' ?

>  err_vclk_disable:
>  	clk_disable_unprepare(cru->vclk);
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 4/9] media: rzg2l-cru: Drop stop streaming function
  2026-06-16 17:05 ` [PATCH 4/9] media: rzg2l-cru: Drop stop streaming function Tommaso Merciai
@ 2026-07-27  9:55   ` Jacopo Mondi
  0 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-07-27  9:55 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, biju.das.jz, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Hi Tommaso

On Tue, Jun 16, 2026 at 07:05:34PM +0200, Tommaso Merciai wrote:
> Drop rzg2l_cru_stop_streaming() function and replace that with the
> direct call to rzg2l_cru_set_stream(cru, 0).
>
> This is a refactoring with no functional changes.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>

Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

Thanks
  j

> ---
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 7 +------
>  1 file changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index bf61a74f8f74..e283d9b69342 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -583,11 +583,6 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
>  	return ret;
>  }
>
> -static void rzg2l_cru_stop_streaming(struct rzg2l_cru_dev *cru)
> -{
> -	rzg2l_cru_set_stream(cru, 0);
> -}
> -
>  irqreturn_t rzg2l_cru_irq(int irq, void *data)
>  {
>  	struct rzg2l_cru_dev *cru = data;
> @@ -736,7 +731,7 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq)
>  {
>  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
>
> -	rzg2l_cru_stop_streaming(cru);
> +	rzg2l_cru_set_stream(cru, 0);
>
>  	/* Free scratch buffer */
>  	dma_free_coherent(cru->dev, cru->format.sizeimage,
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 5/9] media: rzg2l-cru: Move active_slot reset into rzg2l_cru_set_stream()
  2026-06-16 17:05 ` [PATCH 5/9] media: rzg2l-cru: Move active_slot reset into rzg2l_cru_set_stream() Tommaso Merciai
@ 2026-07-27 10:11   ` Jacopo Mondi
  0 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-07-27 10:11 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, biju.das.jz, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Hi Tommaso

On Tue, Jun 16, 2026 at 07:05:35PM +0200, Tommaso Merciai wrote:
> active_slot tracks the current DMA slot index and must always be reset
> to zero before starting a new stream. Previously callers were responsible
> for this reset before each rzg2l_cru_set_stream(cru, 1) invocation.
>
> Move the reset inside rzg2l_cru_set_stream() so the invariant is
> enforced in a single place and future callers cannot accidentally omit
> it.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index e283d9b69342..71d9c671f739 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -559,6 +559,7 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
>  		return stream_off_ret;
>  	}
>
> +	cru->active_slot = 0;

Maybe one emtpy line here ?

>  	pipe = media_entity_pipeline(&sd->entity) ? : &cru->vdev.pipe;
>  	ret = video_device_pipeline_start(&cru->vdev, pipe);
>  	if (ret)
> @@ -698,7 +699,6 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
>  		goto err_assert_resets;
>  	}
>
> -	cru->active_slot = 0;
>  	cru->sequence = 0;

I think it's fine de-coupling the two. The end result shouldn't be any
different after this change.

Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

>
>  	ret = rzg2l_cru_set_stream(cru, 1);
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 6/9] media: rzg2l-cru: Add suspend/resume support
  2026-06-16 17:05 ` [PATCH 6/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
@ 2026-07-27 10:20   ` Jacopo Mondi
  0 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-07-27 10:20 UTC (permalink / raw)
  To: Tommaso Merciai
  Cc: tomm.merciai, linux-renesas-soc, biju.das.jz, Sakari Ailus,
	Mauro Carvalho Chehab, Lad Prabhakar, Jacopo Mondi, Philipp Zabel,
	linux-media, linux-kernel

Hi Tommaso

On Tue, Jun 16, 2026 at 07:05:36PM +0200, Tommaso Merciai wrote:
> The CRU has no system sleep hooks, leaving the device in an undefined
> state across suspend/resume.
>
> On suspend, stop the pipeline, requeue any buffers held by the hardware
> back to the software queue, and assert the resets. On resume, deassert
> the resets and restart streaming.
>
> Add a bool running field to track pipeline state. stop_streaming uses it
> to skip rzg2l_cru_set_stream() when the pipeline was already stopped by
> a failed resume, avoiding a double-stop. Export rzg2l_cru_set_stream()
> and add rzg2l_cru_requeue_active_buffers() for use by the PM callbacks.
>
> Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
> ---
>  .../platform/renesas/rzg2l-cru/rzg2l-core.c   | 67 +++++++++++++++++++
>  .../platform/renesas/rzg2l-cru/rzg2l-cru.h    |  5 ++
>  .../platform/renesas/rzg2l-cru/rzg2l-video.c  | 25 ++++++-
>  3 files changed, 95 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> index 1b12d91eaec9..2840f40e4c01 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
> @@ -246,6 +246,72 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru)
>  	return 0;
>  }
>
> +static int rzg2l_cru_pm_suspend(struct device *dev)
> +{
> +	struct rzg2l_cru_dev *cru = dev_get_drvdata(dev);
> +	struct reset_control_bulk_data resets[] = {
> +		{ .rstc = cru->aresetn },
> +		{ .rstc = cru->presetn },
> +	};

You're re-creating this struct in a few places. Isn't it worth to move
struct reset_control_bulk_data resets[] to struct rzg2l_cru_dev and
populate it at probe time ?

> +	int ret;
> +
> +	if (!cru->running)
> +		return 0;
> +
> +	ret = rzg2l_cru_set_stream(cru, 0);
> +	if (ret)
> +		return ret;
> +
> +	rzg2l_cru_requeue_active_buffers(cru);
> +
> +	ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
> +	if (ret) {
> +		if (rzg2l_cru_set_stream(cru, 1))
> +			vb2_queue_error(&cru->queue);
> +
> +		return ret;
> +	}

Do you need to prepare_enble/disable_unprepare clocks as well or only
resets ?

If you need clocks as well, then this section will become very similar
to what follows pm_runtime_resume_and_get()/precedes
pm_runtime_suspend in rzg2l_cru_start_streaming_vq() and
rzg2l_cru_stop_streaming_vq() respectively.

At this point you could break out the clock/reset handling to
dedicated functions and also install runtime_pm handlers, and re-use
the same routines here and in the below resume ?

> +
> +	return 0;
> +}
> +
> +static int rzg2l_cru_pm_resume(struct device *dev)
> +{
> +	struct rzg2l_cru_dev *cru = dev_get_drvdata(dev);
> +	struct reset_control_bulk_data resets[] = {
> +		{ .rstc = cru->aresetn },
> +		{ .rstc = cru->presetn },
> +	};
> +	int ret;
> +
> +	if (!cru->running)
> +		return 0;
> +
> +	ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
> +	if (ret)
> +		goto err_running;
> +
> +	ret = rzg2l_cru_set_stream(cru, 1);
> +	if (ret) {
> +		dev_err(cru->dev, "Failed to restart streaming: %d\n", ret);
> +		goto err_reset_assert;
> +	}
> +
> +	return 0;
> +
> +err_reset_assert:
> +	reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
> +err_running:
> +	cru->running = false;
> +	vb2_queue_error(&cru->queue);
> +
> +	return ret;
> +}
> +
> +static DEFINE_SIMPLE_DEV_PM_OPS(rzg2l_cru_pm_ops,
> +				rzg2l_cru_pm_suspend,
> +				rzg2l_cru_pm_resume);
> +
>  static int rzg2l_cru_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> @@ -437,6 +503,7 @@ static struct platform_driver rzg2l_cru_driver = {
>  	.driver = {
>  		.name = "rzg2l-cru",
>  		.of_match_table = rzg2l_cru_of_id_table,
> +		.pm = pm_sleep_ptr(&rzg2l_cru_pm_ops),
>  	},
>  	.probe = rzg2l_cru_probe,
>  	.remove = rzg2l_cru_remove,
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> index 5bf334e173d2..c079cad41266 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
> @@ -161,12 +161,17 @@ struct rzg2l_cru_dev {
>  	struct list_head buf_list;
>  	unsigned int sequence;
>
> +	bool running;
> +
>  	struct v4l2_pix_format format;
>  };
>
>  int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru);
>  void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru);
>
> +int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on);
> +void rzg2l_cru_requeue_active_buffers(struct rzg2l_cru_dev *cru);
> +
>  int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru);
>  void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
>
> diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> index 71d9c671f739..46a0823e1300 100644
> --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
> @@ -155,6 +155,23 @@ static void rzg2l_cru_return_buffers(struct rzg2l_cru_dev *cru,
>  	}
>  }
>
> +void rzg2l_cru_requeue_active_buffers(struct rzg2l_cru_dev *cru)
> +{
> +	unsigned int i;
> +
> +	scoped_guard(spinlock_irqsave, &cru->hw_lock) {

As the functions is fully covered by the lock this could be

        guard(spinlock_irqsave)(&cru->hw_lock);

Can this be called from irq context ? Do you need irqsave ?

> +		for (i = 0; i < cru->num_buf; i++) {

You can declare i inside the for loop

> +			if (!cru->queue_buf[i])
> +				continue;
> +			scoped_guard(spinlock_irqsave, &cru->qlock) {
> +				list_add_tail(to_buf_list(cru->queue_buf[i]),
> +					      &cru->buf_list);
> +			}
> +			cru->queue_buf[i] = NULL;
> +		}
> +	}
> +}
> +
>  static int rzg2l_cru_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
>  				 unsigned int *nplanes, unsigned int sizes[],
>  				 struct device *alloc_devs[])
> @@ -528,7 +545,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
>  	return 0;
>  }
>
> -static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
> +int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
>  {
>  	struct media_pipeline *pipe;
>  	struct v4l2_subdev *sd;
> @@ -707,6 +724,7 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
>  		goto out;
>  	}
>
> +	cru->running = true;

Is it necessary to protect access to cru->running for concurrent
suspend/start|stop_streaming sequences ?

Thanks
   j

>  	dev_dbg(cru->dev, "Starting to capture\n");
>  	return 0;
>
> @@ -731,7 +749,10 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq)
>  {
>  	struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq);
>
> -	rzg2l_cru_set_stream(cru, 0);
> +	if (cru->running) {
> +		rzg2l_cru_set_stream(cru, 0);
> +		cru->running = false;
> +	}
>
>  	/* Free scratch buffer */
>  	dma_free_coherent(cru->dev, cru->format.sizeimage,
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2026-07-27 10:20 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-16 17:05 [PATCH 0/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
2026-06-16 17:05 ` [PATCH 1/9] media: rzg2l-cru: Add device_link from CRU to CSI-2 Tommaso Merciai
2026-07-27  9:45   ` Jacopo Mondi
2026-07-27  9:50   ` Jacopo Mondi
2026-06-16 17:05 ` [PATCH 2/9] media: rzg2l-cru: csi2: Add device_link from CSI-2 to sensor Tommaso Merciai
2026-07-27  9:48   ` Jacopo Mondi
2026-06-16 17:05 ` [PATCH 3/9] media: rzg2l-cru: Use bulk reset API in rzg2l_cru_start_streaming_vq() Tommaso Merciai
2026-07-27  9:55   ` Jacopo Mondi
2026-06-16 17:05 ` [PATCH 4/9] media: rzg2l-cru: Drop stop streaming function Tommaso Merciai
2026-07-27  9:55   ` Jacopo Mondi
2026-06-16 17:05 ` [PATCH 5/9] media: rzg2l-cru: Move active_slot reset into rzg2l_cru_set_stream() Tommaso Merciai
2026-07-27 10:11   ` Jacopo Mondi
2026-06-16 17:05 ` [PATCH 6/9] media: rzg2l-cru: Add suspend/resume support Tommaso Merciai
2026-07-27 10:20   ` Jacopo Mondi
2026-06-16 17:05 ` [PATCH 7/9] media: rzg2l-cru: csi2: Add system sleep PM support Tommaso Merciai
2026-06-16 17:05 ` [PATCH 8/9] media: i2c: ov5645: Switch to RUNTIME_PM_OPS() and pm_ptr() Tommaso Merciai
2026-06-16 17:05 ` [PATCH 9/9] media: i2c: ov5645: Add suspend/resume support Tommaso Merciai
2026-07-15  8:47 ` [PATCH 0/9] media: rzg2l-cru: " Tommaso Merciai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox