Linux-i3c Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM
@ 2026-06-02 13:28 Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
                   ` (16 more replies)
  0 siblings, 17 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Hi,

This series adjusts the suspend to RAM code to handle cases where power
to the connected devices is lost during suspend to RAM. The fixes
included in this series are required for that support.

Along with suspend to RAM support, runtime PM support is also added.
Cleanup patches were included to prepare for clean runtime PM support.

Thank you,
Claudiu

Changes in v2:
- dropped patch "i3c: renesas: Use the divider 128"
- adjusted the patches title and description where requested in the
  review process
- adjusted the DAA procedure after resume to still properly re-configure
  the controller in case the bus was full before a suspend
- added patch "i3c: renesas: Do not attach devices if xfer failed"
- collected tags

Claudiu Beznea (17):
  i3c: renesas: Check that the transfer is valid before accessing it
  i3c: renesas: Restore STDBR and EXTBR registers on resume
  i3c: renesas: Follow the reset deassert order used in probe
  i3c: renesas: Reconfigure the DATBAS register on re-attach
  i3c: renesas: Reset the controller on resume
  i3c: renesas: Perform Dynamic Address Assignment on resume
  i3c: renesas: Do not attach devices if xfer failed
  i3c: renesas: Clean DATBAS register on detach
  i3c: renesas: Use reset_control_bulk_{assert, deassert}()
  i3c: renesas: Return immediately if there is no transfer
  i3c: renesas: Follow a unified pattern for transfer and command
    initialization
  i3c: renesas: Drop the explicit memset() call
  i3c: renesas: Update HW registers after SW computations are done
  i3c: renesas: Organize structures to avoid unnecessary padding
  i3c: renesas: Use the "dev_name:irq_name" format for the interrupt
    name
  i3c: renesas: Drop unnecessary tab
  i3c: renesas: Add runtime PM support

 drivers/i3c/master/renesas-i3c.c | 444 +++++++++++++++++++++++--------
 1 file changed, 332 insertions(+), 112 deletions(-)

-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 01/17] i3c: renesas: Check that the transfer is valid before accessing it
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 02/17] i3c: renesas: Restore STDBR and EXTBR registers on resume Claudiu Beznea
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea, stable

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The Renesas I3C driver uses an asynchronous model to transfer data. It
prepares a struct renesas_i3c_xfer, enqueues it, and waits for completion.
The interrupt handler dequeues the transfer, updates/uses it, and signals
the waiting thread.

If the completion times out, the waiting thread dequeues the transfer and
free it. If an interrupt fires after that, the handler may access freed
memory, leading to crashes.

Check that the transfer is still valid before accessing it in the
interrupt handler. Along with it, clear any status flag to avoid
triggering the same interrupts again.

Fixes: d028219a9f14 ("i3c: master: Add basic driver for the Renesas I3C controller")
Cc: stable@vger.kernel.org
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- clean the IRQ status bits before returning IRQ_HANDLED and adjusted the
  patch description to reflect this change
- collected Frank's tag. Frank, please let me know if you consider
  I should drop your tag. Thanks!


 drivers/i3c/master/renesas-i3c.c | 44 +++++++++++++++++++++++++++++---
 1 file changed, 41 insertions(+), 3 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index f39c449922ca..6e7ece2e0b4e 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -1014,6 +1014,12 @@ static irqreturn_t renesas_i3c_tx_isr(int irq, void *data)
 
 	scoped_guard(spinlock, &i3c->xferqueue.lock) {
 		xfer = i3c->xferqueue.cur;
+		if (!xfer) {
+			/* Clear the Transmit Buffer Empty status flag. */
+			renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0);
+			return IRQ_HANDLED;
+		}
+
 		cmd = xfer->cmds;
 
 		if (xfer->is_i2c_xfer) {
@@ -1053,11 +1059,18 @@ static irqreturn_t renesas_i3c_resp_isr(int irq, void *data)
 	int ret = 0;
 
 	scoped_guard(spinlock, &i3c->xferqueue.lock) {
+		/* Clear the Respone Queue Full status flag */
+		renesas_clear_bit(i3c->regs, NTST, NTST_RSPQFF);
+
 		xfer = i3c->xferqueue.cur;
-		cmd = xfer->cmds;
+		if (!xfer) {
+			/* Clear any error flags. */
+			renesas_clear_bit(i3c->regs, BCTL, BCTL_ABT);
+			renesas_clear_bit(i3c->regs, NTST, NTST_TEF | NTST_TABTF);
+			return IRQ_HANDLED;
+		}
 
-		/* Clear the Respone Queue Full status flag*/
-		renesas_clear_bit(i3c->regs, NTST, NTST_RSPQFF);
+		cmd = xfer->cmds;
 
 		data_len = NRSPQP_DATA_LEN(resp_descriptor);
 
@@ -1138,6 +1151,12 @@ static irqreturn_t renesas_i3c_tend_isr(int irq, void *data)
 
 	scoped_guard(spinlock, &i3c->xferqueue.lock) {
 		xfer = i3c->xferqueue.cur;
+		if (!xfer) {
+			/* Clear any status flag. */
+			renesas_clear_bit(i3c->regs, BST, BST_NACKDF | BST_TENDF);
+			return IRQ_HANDLED;
+		}
+
 		cmd = xfer->cmds;
 
 		if (xfer->is_i2c_xfer) {
@@ -1184,6 +1203,14 @@ static irqreturn_t renesas_i3c_rx_isr(int irq, void *data)
 
 	scoped_guard(spinlock, &i3c->xferqueue.lock) {
 		xfer = i3c->xferqueue.cur;
+		if (!xfer) {
+			/* Clear any status registers. */
+			renesas_clear_bit(i3c->regs, BST, BST_SPCNDDF);
+			/* Clear the Read Buffer Full status flag. */
+			renesas_clear_bit(i3c->regs, NTST, NTST_RDBFF0);
+			return IRQ_HANDLED;
+		}
+
 		cmd = xfer->cmds;
 
 		if (xfer->is_i2c_xfer) {
@@ -1235,6 +1262,11 @@ static irqreturn_t renesas_i3c_stop_isr(int irq, void *data)
 
 	scoped_guard(spinlock, &i3c->xferqueue.lock) {
 		xfer = i3c->xferqueue.cur;
+		if (!xfer) {
+			/* Clear the RX/TX Data Buffer Full status flag. */
+			renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0 | NTST_RDBFF0);
+			return IRQ_HANDLED;
+		}
 
 		/* read back registers to confirm writes have fully propagated */
 		renesas_writel(i3c->regs, BST, 0);
@@ -1259,6 +1291,12 @@ static irqreturn_t renesas_i3c_start_isr(int irq, void *data)
 
 	scoped_guard(spinlock, &i3c->xferqueue.lock) {
 		xfer = i3c->xferqueue.cur;
+		if (!xfer) {
+			/* Clear any status registers. */
+			renesas_clear_bit(i3c->regs, BST, BST_STCNDDF);
+			return IRQ_HANDLED;
+		}
+
 		cmd = xfer->cmds;
 
 		if (xfer->is_i2c_xfer) {
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 02/17] i3c: renesas: Restore STDBR and EXTBR registers on resume
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 03/17] i3c: renesas: Follow the reset deassert order used in probe Claudiu Beznea
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea, stable

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The Renesas RZ/G3S supports a power saving state where power to the most
SoC componentes (including I3C) is lost.

The STDBR and EXTBR are configured in initialization phase though the
struct i3c_master_controller_ops::bus_init. Set them on resume function
as well to keep the same state of the controller after a suspend with
power loss and a similar initialization sequence as in bus_init.

Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
Cc: stable@vger.kernel.org
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- collected tags

 drivers/i3c/master/renesas-i3c.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 6e7ece2e0b4e..88a16efe096d 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -260,6 +260,7 @@ struct renesas_i3c {
 	u32 dyn_addr;
 	u32 i2c_STDBR;
 	u32 i3c_STDBR;
+	u32 extbr;
 	unsigned long rate;
 	u8 addrs[RENESAS_I3C_MAX_DEVS];
 	struct renesas_i3c_xferqueue xferqueue;
@@ -607,10 +608,9 @@ static int renesas_i3c_bus_init(struct i3c_master_controller *m)
 	renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
 
 	/* Extended Bit Rate setting */
-	renesas_writel(i3c->regs, EXTBR, EXTBR_EBRLO(od_low_ticks) |
-					   EXTBR_EBRHO(od_high_ticks) |
-					   EXTBR_EBRLP(pp_low_ticks) |
-					   EXTBR_EBRHP(pp_high_ticks));
+	i3c->extbr = EXTBR_EBRLO(od_low_ticks) | EXTBR_EBRHO(od_high_ticks) |
+		     EXTBR_EBRLP(pp_low_ticks) | EXTBR_EBRHP(pp_high_ticks);
+	renesas_writel(i3c->regs, EXTBR, i3c->extbr);
 
 	renesas_writel(i3c->regs, REFCKCTL, REFCKCTL_IREFCKS(cks));
 	i3c->refclk_div = cks;
@@ -1468,6 +1468,8 @@ static int renesas_i3c_resume_noirq(struct device *dev)
 		goto err_tresetn;
 
 	/* Re-store I3C registers value. */
+	renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
+	renesas_writel(i3c->regs, EXTBR, i3c->extbr);
 	renesas_writel(i3c->regs, REFCKCTL,
 		       REFCKCTL_IREFCKS(i3c->refclk_div));
 	renesas_writel(i3c->regs, MSDVAD, MSDVAD_MDYADV |
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 03/17] i3c: renesas: Follow the reset deassert order used in probe
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 02/17] i3c: renesas: Restore STDBR and EXTBR registers on resume Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach Claudiu Beznea
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea, stable

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Use the same reset deassert order in the resume and probe paths to avoid
potential failures due to ordering differences.

Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
Cc: stable@vger.kernel.org
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- collected tags

 drivers/i3c/master/renesas-i3c.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 88a16efe096d..4c86e7257804 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -1455,17 +1455,17 @@ static int renesas_i3c_resume_noirq(struct device *dev)
 	struct renesas_i3c *i3c = dev_get_drvdata(dev);
 	int i, ret;
 
-	ret = reset_control_deassert(i3c->presetn);
+	ret = reset_control_deassert(i3c->tresetn);
 	if (ret)
 		return ret;
 
-	ret = reset_control_deassert(i3c->tresetn);
+	ret = reset_control_deassert(i3c->presetn);
 	if (ret)
-		goto err_presetn;
+		goto err_tresetn;
 
 	ret = clk_bulk_enable(i3c->num_clks, i3c->clks);
 	if (ret)
-		goto err_tresetn;
+		goto err_presetn;
 
 	/* Re-store I3C registers value. */
 	renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
@@ -1486,10 +1486,10 @@ static int renesas_i3c_resume_noirq(struct device *dev)
 
 	return 0;
 
-err_tresetn:
-	reset_control_assert(i3c->tresetn);
 err_presetn:
 	reset_control_assert(i3c->presetn);
+err_tresetn:
+	reset_control_assert(i3c->tresetn);
 	return ret;
 }
 
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (2 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 03/17] i3c: renesas: Follow the reset deassert order used in probe Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 20:05   ` Frank Li
  2026-06-02 13:28 ` [PATCH v2 05/17] i3c: renesas: Reset the controller on resume Claudiu Beznea
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea, stable

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

During re-attach, the device may change its position in the i3c->addrs[]
array. As a result, it may use a different Device Address Table Basic
Register (DATBAS), which needs to be reconfigured.

Reconfigure the DATBAS register on re-attach. Along with it update
software caches.

Fixes: d028219a9f14 ("i3c: master: Add basic driver for the Renesas I3C controller")
Cc: stable@vger.kernel.org
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- dropped the "if (pos < 0)" check in renesas_i3c_reattach_i3c_dev() to allow
  re-attaching in case of a full bus; along with it the condition to update
  the DATBAS register and software caches was updated to
  if (data->index != pos && pos >= 0)
- adjusted the patch title

 drivers/i3c/master/renesas-i3c.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 4c86e7257804..76a4831098c9 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -892,10 +892,26 @@ static int renesas_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev,
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 	struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+	int pos;
+
+	pos = renesas_i3c_get_free_pos(i3c);
+
+	if (data->index != pos && pos >= 0) {
+		renesas_writel(i3c->regs, DATBAS(data->index), 0);
+		i3c->addrs[data->index] = 0;
+		i3c->free_pos |= BIT(data->index);
+
+		data->index = pos;
+		i3c->free_pos &= ~BIT(data->index);
+	}
 
 	i3c->addrs[data->index] = dev->info.dyn_addr ? dev->info.dyn_addr :
 							dev->info.static_addr;
 
+	renesas_writel(i3c->regs, DATBAS(data->index),
+		       DATBAS_DVSTAD(dev->info.static_addr) |
+		       datbas_dvdyad_with_parity(i3c->addrs[data->index]));
+
 	return 0;
 }
 
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 05/17] i3c: renesas: Reset the controller on resume
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (3 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment " Claudiu Beznea
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea, stable

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Reset the controller on resume after enabling the clocks to follow the
same sequence as in probe and avoid potential ordering related failures.

With it, renesas_i3c_reset() was updated to use read_poll_timeout_atomic(),
as the driver's resume callback is executed during the noirq phase of
resume, where interrupts are disabled.

Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
Cc: stable@vger.kernel.org
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- replaced the read_poll_timeout() in renesas_i3c_reset() with
  read_poll_timeout_atomic() as the renesas_i3c_reset() is called
  in noirq phase of the suspend/resume; updated the patch description
  to reflect that
- collected Frank's tag. Frank, please let me know if this should be
  dropped. Thanks!

 drivers/i3c/master/renesas-i3c.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 76a4831098c9..7ef317b2ba39 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -480,8 +480,8 @@ static int renesas_i3c_reset(struct renesas_i3c *i3c)
 	renesas_writel(i3c->regs, BCTL, 0);
 	renesas_set_bit(i3c->regs, RSTCTL, RSTCTL_RI3CRST);
 
-	return read_poll_timeout(renesas_readl, val, !(val & RSTCTL_RI3CRST),
-				 0, 1000, false, i3c->regs, RSTCTL);
+	return read_poll_timeout_atomic(renesas_readl, val, !(val & RSTCTL_RI3CRST),
+					0, 1000, false, i3c->regs, RSTCTL);
 }
 
 static void renesas_i3c_hw_init(struct renesas_i3c *i3c)
@@ -1483,6 +1483,10 @@ static int renesas_i3c_resume_noirq(struct device *dev)
 	if (ret)
 		goto err_presetn;
 
+	ret = renesas_i3c_reset(i3c);
+	if (ret)
+		goto err_clks_disable;
+
 	/* Re-store I3C registers value. */
 	renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
 	renesas_writel(i3c->regs, EXTBR, i3c->extbr);
@@ -1502,6 +1506,8 @@ static int renesas_i3c_resume_noirq(struct device *dev)
 
 	return 0;
 
+err_clks_disable:
+	clk_bulk_disable(i3c->num_clks, i3c->clks);
 err_presetn:
 	reset_control_assert(i3c->presetn);
 err_tresetn:
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment on resume
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (4 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 05/17] i3c: renesas: Reset the controller on resume Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 20:12   ` Frank Li
  2026-06-02 13:28 ` [PATCH v2 07/17] i3c: renesas: Do not attach devices if xfer failed Claudiu Beznea
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea, stable

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The Renesas RZ/G3S SoC supports a power saving mode where power to most
SoC components, including I3C, is turned off.

On systems where the I3C devices also loses power during suspend (e.g. NXP
P3T1085UK-ARD connected to the PMOD1_6A connector of the RZ SMARC Carrier
2 + Renesas RZ/G3S SMARC SOM), the devices becomes unreachable after
resume.

Running DAA in the controller resume path restores communication. However,
DAA relies on interrupts for TX/RX, which are not available in the noirq
suspend/resume phase (unless they are wakeup interrupts). For this, the
suspend/resume callbacks were moved out of the noirq phase. Currently,
there is no identified use case on either the Renesas RZ/G3S or Renesas
RZ/G3E SoCs that requires the controller suspend/resume hooks to be part of
the noirq suspend/resume phase.

Since renesas_i3c_reset() is not called anymore in atomic context
update it to use read_poll_timeout().

To cover the case where the controller had already attached all the
i3c->maxdevs devices before a suspend/resume cycle and i3c->free_pos is
zero, struct renesas_i3c::resuming flag was introduced.

The flag is set in renesas_i3c_resume() before calling
i3c_master_do_daa_ext() and checked in renesas_i3c_daa(). In case it is
set the previous saved DATBAS register values are used for the slots
already occupied before suspend. This allows keeping alive the connection
to the I3C devices when all the supported slots are occupied before
suspend.

When resuming from suspend, renesas_i3c_daa() re-runs DAA for al
slots except those used by I2C devices. I2C devices are attached during
probe, at bus initialization time, and always occupy the first positions in
i3c->free_pos. In addition, there are no DATBAS register settings
associated with them.

Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
Cc: stable@vger.kernel.org
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- adjusted the code to still work in case the full bus was occupied before
  a suspend/resume cycle; for that:
-- introduced struct renesas_i3c_addr
-- preserved i3c->DATBASn[] which is saved in suspend and used in resume,
   in renesas_i3c_daa()
- updated the patch description to reflect the new updates

 drivers/i3c/master/renesas-i3c.c | 103 ++++++++++++++++++++++---------
 1 file changed, 75 insertions(+), 28 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 7ef317b2ba39..695aae6ac263 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -252,6 +252,11 @@ struct renesas_i3c_xferqueue {
 	spinlock_t lock;
 };
 
+struct renesas_i3c_addr {
+	bool is_i2c;
+	u8 addr;
+};
+
 struct renesas_i3c {
 	struct i3c_master_controller base;
 	enum i3c_internal_state internal_state;
@@ -262,13 +267,14 @@ struct renesas_i3c {
 	u32 i3c_STDBR;
 	u32 extbr;
 	unsigned long rate;
-	u8 addrs[RENESAS_I3C_MAX_DEVS];
+	struct renesas_i3c_addr addrs[RENESAS_I3C_MAX_DEVS];
 	struct renesas_i3c_xferqueue xferqueue;
 	void __iomem *regs;
 	u32 *DATBASn;
 	struct clk_bulk_data *clks;
 	struct reset_control *presetn;
 	struct reset_control *tresetn;
+	bool resuming;
 	u8 num_clks;
 	u8 refclk_div;
 };
@@ -335,7 +341,7 @@ static int renesas_i3c_get_addr_pos(struct renesas_i3c *i3c, u8 addr)
 	int pos;
 
 	for (pos = 0; pos < i3c->maxdevs; pos++) {
-		if (addr == i3c->addrs[pos])
+		if (addr == i3c->addrs[pos].addr)
 			return pos;
 	}
 
@@ -480,8 +486,8 @@ static int renesas_i3c_reset(struct renesas_i3c *i3c)
 	renesas_writel(i3c->regs, BCTL, 0);
 	renesas_set_bit(i3c->regs, RSTCTL, RSTCTL_RI3CRST);
 
-	return read_poll_timeout_atomic(renesas_readl, val, !(val & RSTCTL_RI3CRST),
-					0, 1000, false, i3c->regs, RSTCTL);
+	return read_poll_timeout(renesas_readl, val, !(val & RSTCTL_RI3CRST),
+				 0, 1000, false, i3c->regs, RSTCTL);
 }
 
 static void renesas_i3c_hw_init(struct renesas_i3c *i3c)
@@ -641,8 +647,9 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 {
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 	struct renesas_i3c_cmd *cmd;
-	u32 olddevs, newdevs;
 	u8 last_addr = 0, pos;
+	int last_i2c_pos = -1;
+	u32 olddevs, newdevs;
 	int ret;
 
 	struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
@@ -657,14 +664,33 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 
 	/* Setting DATBASn registers for target devices. */
 	for (pos = 0; pos < i3c->maxdevs; pos++) {
-		if (olddevs & BIT(pos))
+		if (olddevs & BIT(pos)) {
+			/*
+			 * In case of resume, reassign DAs for all devices on the
+			 * bus to avoid failures when all i3c->maxdevs slots were
+			 * already occupied before suspend.
+			 *
+			 * Exclude I2C devices, as they are attached during probe,
+			 * at bus initialization time, and there are currently no
+			 * register updates associated with them.
+			 */
+			if (i3c->resuming) {
+				if (i3c->addrs[pos].is_i2c) {
+					last_i2c_pos = pos;
+				} else {
+					renesas_writel(i3c->regs, DATBAS(pos),
+						       i3c->DATBASn[pos]);
+				}
+			}
+
 			continue;
+		}
 
 		ret = i3c_master_get_free_addr(m, last_addr + 1);
 		if (ret < 0)
 			return -ENOSPC;
 
-		i3c->addrs[pos] = ret;
+		i3c->addrs[pos].addr = ret;
 		last_addr = ret;
 
 		renesas_writel(i3c->regs, DATBAS(pos), datbas_dvdyad_with_parity(ret));
@@ -674,9 +700,21 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 	cmd = xfer->cmds;
 	cmd->rx_count = 0;
 
-	ret = renesas_i3c_get_free_pos(i3c);
-	if (ret < 0)
-		return ret;
+	if (i3c->resuming) {
+		/* Nothing to do if all slots are ocupied by I2C devices. */
+		if (last_i2c_pos == i3c->maxdevs - 1)
+			return 0;
+
+		/*
+		 * Do DAA for all the devices on the bus, if resuming, except
+		 * the I2C ones.
+		 */
+		ret = last_i2c_pos < 0 ? 0 : last_i2c_pos + 1;
+	} else {
+		ret = renesas_i3c_get_free_pos(i3c);
+		if (ret < 0)
+			return ret;
+	}
 
 	/*
 	 * Setup the command descriptor to start the ENTDAA command
@@ -694,7 +732,7 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 
 	for (pos = 0; pos < i3c->maxdevs; pos++) {
 		if (newdevs & BIT(pos))
-			i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos]);
+			i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos].addr);
 	}
 
 	return 0;
@@ -876,11 +914,11 @@ static int renesas_i3c_attach_i3c_dev(struct i3c_dev_desc *dev)
 		return -ENOMEM;
 
 	data->index = pos;
-	i3c->addrs[pos] = dev->info.dyn_addr ? : dev->info.static_addr;
+	i3c->addrs[pos].addr = dev->info.dyn_addr ? : dev->info.static_addr;
 	i3c->free_pos &= ~BIT(pos);
 
 	renesas_writel(i3c->regs, DATBAS(pos), DATBAS_DVSTAD(dev->info.static_addr) |
-				    datbas_dvdyad_with_parity(i3c->addrs[pos]));
+				    datbas_dvdyad_with_parity(i3c->addrs[pos].addr));
 	i3c_dev_set_master_data(dev, data);
 
 	return 0;
@@ -898,19 +936,19 @@ static int renesas_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev,
 
 	if (data->index != pos && pos >= 0) {
 		renesas_writel(i3c->regs, DATBAS(data->index), 0);
-		i3c->addrs[data->index] = 0;
+		i3c->addrs[data->index].addr = 0;
 		i3c->free_pos |= BIT(data->index);
 
 		data->index = pos;
 		i3c->free_pos &= ~BIT(data->index);
 	}
 
-	i3c->addrs[data->index] = dev->info.dyn_addr ? dev->info.dyn_addr :
+	i3c->addrs[data->index].addr = dev->info.dyn_addr ? dev->info.dyn_addr :
 							dev->info.static_addr;
 
 	renesas_writel(i3c->regs, DATBAS(data->index),
 		       DATBAS_DVSTAD(dev->info.static_addr) |
-		       datbas_dvdyad_with_parity(i3c->addrs[data->index]));
+		       datbas_dvdyad_with_parity(i3c->addrs[data->index].addr));
 
 	return 0;
 }
@@ -922,7 +960,7 @@ static void renesas_i3c_detach_i3c_dev(struct i3c_dev_desc *dev)
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 
 	i3c_dev_set_master_data(dev, NULL);
-	i3c->addrs[data->index] = 0;
+	i3c->addrs[data->index].addr = 0;
 	i3c->free_pos |= BIT(data->index);
 	kfree(data);
 }
@@ -1002,7 +1040,8 @@ static int renesas_i3c_attach_i2c_dev(struct i2c_dev_desc *dev)
 		return -ENOMEM;
 
 	data->index = pos;
-	i3c->addrs[pos] = dev->addr;
+	i3c->addrs[pos].addr = dev->addr;
+	i3c->addrs[pos].is_i2c = true;
 	i3c->free_pos &= ~BIT(pos);
 	i2c_dev_set_master_data(dev, data);
 
@@ -1016,7 +1055,8 @@ static void renesas_i3c_detach_i2c_dev(struct i2c_dev_desc *dev)
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 
 	i2c_dev_set_master_data(dev, NULL);
-	i3c->addrs[data->index] = 0;
+	i3c->addrs[data->index].addr = 0;
+	i3c->addrs[data->index].is_i2c = false;
 	i3c->free_pos |= BIT(data->index);
 	kfree(data);
 }
@@ -1435,7 +1475,7 @@ static void renesas_i3c_remove(struct platform_device *pdev)
 	i3c_master_unregister(&i3c->base);
 }
 
-static int renesas_i3c_suspend_noirq(struct device *dev)
+static int renesas_i3c_suspend(struct device *dev)
 {
 	struct renesas_i3c *i3c = dev_get_drvdata(dev);
 	int i, ret;
@@ -1466,10 +1506,10 @@ static int renesas_i3c_suspend_noirq(struct device *dev)
 	return ret;
 }
 
-static int renesas_i3c_resume_noirq(struct device *dev)
+static int renesas_i3c_resume(struct device *dev)
 {
 	struct renesas_i3c *i3c = dev_get_drvdata(dev);
-	int i, ret;
+	int ret;
 
 	ret = reset_control_deassert(i3c->tresetn);
 	if (ret)
@@ -1495,15 +1535,23 @@ static int renesas_i3c_resume_noirq(struct device *dev)
 	renesas_writel(i3c->regs, MSDVAD, MSDVAD_MDYADV |
 		       MSDVAD_MDYAD(i3c->dyn_addr));
 
-	/* Restore Device Address Table values. */
-	for (i = 0; i < i3c->maxdevs; i++)
-		renesas_writel(i3c->regs, DATBAS(i), i3c->DATBASn[i]);
-
 	/* I3C hw init. */
 	renesas_i3c_hw_init(i3c);
 
 	i2c_mark_adapter_resumed(&i3c->base.i2c);
 
+	i3c->resuming = true;
+
+	ret = i3c_master_do_daa_ext(&i3c->base, true);
+	if (ret)
+		dev_err(dev, "DAA failed on resume, ret=%d", ret);
+
+	i3c->resuming = false;
+
+	/*
+	 * I3C devices may have retained their dynamic address anyway. Do not
+	 * fail the resume because of DAA error.
+	 */
 	return 0;
 
 err_clks_disable:
@@ -1516,8 +1564,7 @@ static int renesas_i3c_resume_noirq(struct device *dev)
 }
 
 static const struct dev_pm_ops renesas_i3c_pm_ops = {
-	NOIRQ_SYSTEM_SLEEP_PM_OPS(renesas_i3c_suspend_noirq,
-				  renesas_i3c_resume_noirq)
+	SYSTEM_SLEEP_PM_OPS(renesas_i3c_suspend, renesas_i3c_resume)
 };
 
 static const struct of_device_id renesas_i3c_of_ids[] = {
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 07/17] i3c: renesas: Do not attach devices if xfer failed
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (5 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment " Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 08/17] i3c: renesas: Clean DATBAS register on detach Claudiu Beznea
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea, stable

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The controller may return an NRSPQP_ERROR_* error code while still
providing a valid cmd->rx_count. It has been observed that when the
transfer fails with NRSPQP_ERROR_ADDRESS_NACK, calling
i3c_master_add_i3c_dev_locked() may lead to crashes. Set newdevs to zero
if the transfer failed.

Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
Cc: stable@vger.kernel.org
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- none, this patch is new

 drivers/i3c/master/renesas-i3c.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 695aae6ac263..de09f0cadb72 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -727,8 +727,13 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 
 	renesas_i3c_wait_xfer(i3c, xfer);
 
-	newdevs = GENMASK(i3c->maxdevs - cmd->rx_count - 1, 0);
-	newdevs &= ~olddevs;
+	/* Skip attaching if there are failures on the xfer. */
+	if (xfer->ret) {
+		newdevs = 0;
+	} else {
+		newdevs = GENMASK(i3c->maxdevs - cmd->rx_count - 1, 0);
+		newdevs &= ~olddevs;
+	}
 
 	for (pos = 0; pos < i3c->maxdevs; pos++) {
 		if (newdevs & BIT(pos))
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 08/17] i3c: renesas: Clean DATBAS register on detach
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (6 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 07/17] i3c: renesas: Do not attach devices if xfer failed Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}() Claudiu Beznea
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea, stable

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The controller uses DATBAS registers on TX/RX logic. Clean the DATBAS
register for the detached I3C device to avoid issues.

Fixes: d028219a9f14 ("i3c: master: Add basic driver for the Renesas I3C controller")
Cc: stable@vger.kernel.org
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- collected tags

 drivers/i3c/master/renesas-i3c.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index de09f0cadb72..7167ca12a328 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -964,6 +964,8 @@ static void renesas_i3c_detach_i3c_dev(struct i3c_dev_desc *dev)
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 
+	renesas_writel(i3c->regs, DATBAS(data->index), 0);
+
 	i3c_dev_set_master_data(dev, NULL);
 	i3c->addrs[data->index].addr = 0;
 	i3c->free_pos |= BIT(data->index);
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}()
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (7 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 08/17] i3c: renesas: Clean DATBAS register on detach Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 15:09   ` Philipp Zabel
  2026-06-02 13:28 ` [PATCH v2 10/17] i3c: renesas: Return immediately if there is no transfer Claudiu Beznea
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Use reset_control_bulk_assert() and reset_control_bulk_deassert() in the
suspend and resume paths to simplify the code.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- none

 drivers/i3c/master/renesas-i3c.c | 30 +++++++++++++-----------------
 1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 7167ca12a328..860c9f2f17de 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -1485,6 +1485,10 @@ static void renesas_i3c_remove(struct platform_device *pdev)
 static int renesas_i3c_suspend(struct device *dev)
 {
 	struct renesas_i3c *i3c = dev_get_drvdata(dev);
+	struct reset_control_bulk_data resets[] = {
+		{ .rstc = i3c->presetn },
+		{ .rstc = i3c->tresetn },
+	};
 	int i, ret;
 
 	i2c_mark_adapter_suspended(&i3c->base.i2c);
@@ -1493,20 +1497,14 @@ static int renesas_i3c_suspend(struct device *dev)
 	for (i = 0; i < i3c->maxdevs; i++)
 		i3c->DATBASn[i] = renesas_readl(i3c->regs, DATBAS(i));
 
-	ret = reset_control_assert(i3c->presetn);
+	ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
 	if (ret)
 		goto err_mark_resumed;
 
-	ret = reset_control_assert(i3c->tresetn);
-	if (ret)
-		goto err_presetn;
-
 	clk_bulk_disable(i3c->num_clks, i3c->clks);
 
 	return 0;
 
-err_presetn:
-	reset_control_deassert(i3c->presetn);
 err_mark_resumed:
 	i2c_mark_adapter_resumed(&i3c->base.i2c);
 
@@ -1516,19 +1514,19 @@ static int renesas_i3c_suspend(struct device *dev)
 static int renesas_i3c_resume(struct device *dev)
 {
 	struct renesas_i3c *i3c = dev_get_drvdata(dev);
+	struct reset_control_bulk_data resets[] = {
+		{ .rstc = i3c->presetn },
+		{ .rstc = i3c->tresetn },
+	};
 	int ret;
 
-	ret = reset_control_deassert(i3c->tresetn);
+	ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
 	if (ret)
 		return ret;
 
-	ret = reset_control_deassert(i3c->presetn);
-	if (ret)
-		goto err_tresetn;
-
 	ret = clk_bulk_enable(i3c->num_clks, i3c->clks);
 	if (ret)
-		goto err_presetn;
+		goto err_resets_asserted;
 
 	ret = renesas_i3c_reset(i3c);
 	if (ret)
@@ -1563,10 +1561,8 @@ static int renesas_i3c_resume(struct device *dev)
 
 err_clks_disable:
 	clk_bulk_disable(i3c->num_clks, i3c->clks);
-err_presetn:
-	reset_control_assert(i3c->presetn);
-err_tresetn:
-	reset_control_assert(i3c->tresetn);
+err_resets_asserted:
+	reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
 	return ret;
 }
 
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 10/17] i3c: renesas: Return immediately if there is no transfer
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (8 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}() Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 11/17] i3c: renesas: Follow a unified pattern for transfer and command initialization Claudiu Beznea
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

There is no need to allocate a transfer structure when i2c_nxfers is zero.
Return immediately instead of unnecessarily allocating memory.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- updated patch title

 drivers/i3c/master/renesas-i3c.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 860c9f2f17de..ed925b673b38 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -982,13 +982,13 @@ static int renesas_i3c_i2c_xfers(struct i2c_dev_desc *dev,
 	u8 start_bit = CNDCTL_STCND;
 	int i;
 
+	if (!i2c_nxfers)
+		return 0;
+
 	struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
 	if (!xfer)
 		return -ENOMEM;
 
-	if (!i2c_nxfers)
-		return 0;
-
 	renesas_i3c_bus_enable(m, false);
 
 	init_completion(&xfer->comp);
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 11/17] i3c: renesas: Follow a unified pattern for transfer and command initialization
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (9 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 10/17] i3c: renesas: Return immediately if there is no transfer Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 12/17] i3c: renesas: Drop the explicit memset() call Claudiu Beznea
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Follow a unified pattern for transfer and command initialization across
the driver. This keeps the code cleaner and easier to follow. Also, in
some cases the I3C device was enabled before the transfer data structure
was even allocated.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- collected tags

 drivers/i3c/master/renesas-i3c.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index ed925b673b38..601d879fce9d 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -656,6 +656,10 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 	if (!xfer)
 		return -ENOMEM;
 
+	init_completion(&xfer->comp);
+	cmd = xfer->cmds;
+	cmd->rx_count = 0;
+
 	/* Enable I3C bus. */
 	renesas_i3c_bus_enable(m, true);
 
@@ -696,10 +700,6 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 		renesas_writel(i3c->regs, DATBAS(pos), datbas_dvdyad_with_parity(ret));
 	}
 
-	init_completion(&xfer->comp);
-	cmd = xfer->cmds;
-	cmd->rx_count = 0;
-
 	if (i3c->resuming) {
 		/* Nothing to do if all slots are ocupied by I2C devices. */
 		if (last_i2c_pos == i3c->maxdevs - 1)
@@ -804,13 +804,13 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
 	if (!xfer)
 		return -ENOMEM;
 
-	renesas_i3c_bus_enable(m, true);
-
 	init_completion(&xfer->comp);
 	cmd = xfer->cmds;
 	cmd->rnw = ccc->rnw;
 	cmd->cmd0 = 0;
 
+	renesas_i3c_bus_enable(m, true);
+
 	/* Calculate the command descriptor. */
 	switch (ccc->id) {
 	case I3C_CCC_SETDASA:
@@ -860,15 +860,15 @@ static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_
 	struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
 	int i;
 
-	/* Enable I3C bus. */
-	renesas_i3c_bus_enable(m, true);
-
 	struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
 	if (!xfer)
 		return -ENOMEM;
 
 	init_completion(&xfer->comp);
 
+	/* Enable I3C bus. */
+	renesas_i3c_bus_enable(m, true);
+
 	for (i = 0; i < i3c_nxfers; i++) {
 		struct renesas_i3c_cmd *cmd = xfer->cmds;
 
@@ -989,12 +989,12 @@ static int renesas_i3c_i2c_xfers(struct i2c_dev_desc *dev,
 	if (!xfer)
 		return -ENOMEM;
 
-	renesas_i3c_bus_enable(m, false);
-
 	init_completion(&xfer->comp);
 	xfer->is_i2c_xfer = true;
 	cmd = xfer->cmds;
 
+	renesas_i3c_bus_enable(m, false);
+
 	if (!(renesas_readl(i3c->regs, BCST) & BCST_BFREF)) {
 		cmd->err = -EBUSY;
 		return cmd->err;
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 12/17] i3c: renesas: Drop the explicit memset() call
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (10 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 11/17] i3c: renesas: Follow a unified pattern for transfer and command initialization Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 13/17] i3c: renesas: Update HW registers after SW computations are done Claudiu Beznea
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Drop the explicit memset() call on struct i3c_device_info object, as it is
already initialized at declaration through compiler initialization.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- collected tags

 drivers/i3c/master/renesas-i3c.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 601d879fce9d..6725b7fe5392 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -631,7 +631,6 @@ static int renesas_i3c_bus_init(struct i3c_master_controller *m)
 	i3c->dyn_addr = ret;
 	renesas_writel(i3c->regs, MSDVAD, MSDVAD_MDYAD(ret) | MSDVAD_MDYADV);
 
-	memset(&info, 0, sizeof(info));
 	info.dyn_addr = ret;
 	return i3c_master_set_info(&i3c->base, &info);
 }
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 13/17] i3c: renesas: Update HW registers after SW computations are done
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (11 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 12/17] i3c: renesas: Drop the explicit memset() call Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 14/17] i3c: renesas: Organize structures to avoid unnecessary padding Claudiu Beznea
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

renesas_i3c_bus_init() performs a number of computations and software
cache updates, interleaving them with hardware register writes. While
this works today, it makes it harder to minimize the time the controller
must remain powered when runtime PM is introduced.

Perform all software computations and cache updates first, then update
the hardware registers. This prepares for future runtime PM support.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- collected tags

 drivers/i3c/master/renesas-i3c.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 6725b7fe5392..9ffb4a9d1e46 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -557,10 +557,6 @@ static int renesas_i3c_bus_init(struct i3c_master_controller *m)
 	if (!i3c->rate)
 		return -EINVAL;
 
-	ret = renesas_i3c_reset(i3c);
-	if (ret)
-		return ret;
-
 	i2c_total_ticks = DIV_ROUND_UP(i3c->rate, bus->scl_rate.i2c);
 	i3c_total_ticks = DIV_ROUND_UP(i3c->rate, bus->scl_rate.i3c);
 
@@ -611,27 +607,31 @@ static int renesas_i3c_bus_init(struct i3c_master_controller *m)
 			STDBR_SBRHO(double_SBR, od_high_ticks) |
 			STDBR_SBRLP(pp_low_ticks) |
 			STDBR_SBRHP(pp_high_ticks);
-	renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
 
 	/* Extended Bit Rate setting */
 	i3c->extbr = EXTBR_EBRLO(od_low_ticks) | EXTBR_EBRHO(od_high_ticks) |
 		     EXTBR_EBRLP(pp_low_ticks) | EXTBR_EBRHP(pp_high_ticks);
-	renesas_writel(i3c->regs, EXTBR, i3c->extbr);
-
-	renesas_writel(i3c->regs, REFCKCTL, REFCKCTL_IREFCKS(cks));
-	i3c->refclk_div = cks;
-
-	/* I3C hw init*/
-	renesas_i3c_hw_init(i3c);
 
 	ret = i3c_master_get_free_addr(m, 0);
 	if (ret < 0)
 		return ret;
 
+	info.dyn_addr = ret;
 	i3c->dyn_addr = ret;
-	renesas_writel(i3c->regs, MSDVAD, MSDVAD_MDYAD(ret) | MSDVAD_MDYADV);
+	i3c->refclk_div = cks;
+
+	ret = renesas_i3c_reset(i3c);
+	if (ret)
+		return ret;
+
+	renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
+	renesas_writel(i3c->regs, EXTBR, i3c->extbr);
+	renesas_writel(i3c->regs, REFCKCTL, REFCKCTL_IREFCKS(cks));
+	renesas_writel(i3c->regs, MSDVAD, MSDVAD_MDYAD(i3c->dyn_addr) | MSDVAD_MDYADV);
+
+	/* I3C hw init*/
+	renesas_i3c_hw_init(i3c);
 
-	info.dyn_addr = ret;
 	return i3c_master_set_info(&i3c->base, &info);
 }
 
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 14/17] i3c: renesas: Organize structures to avoid unnecessary padding
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (12 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 13/17] i3c: renesas: Update HW registers after SW computations are done Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name Claudiu Beznea
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Reorder structure members to reduce padding and improve memory layout.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- collected tags

 drivers/i3c/master/renesas-i3c.c | 34 ++++++++++++++++----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 9ffb4a9d1e46..e1aa445de933 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -221,19 +221,19 @@ enum renesas_i3c_event {
 };
 
 struct renesas_i3c_cmd {
+	const void *tx_buf;
+	void *rx_buf;
+	/* i2c xfer */
+	u8 *i2c_buf;
+	const struct i2c_msg *msg;
+	int i2c_bytes_left;
+	int i2c_is_last;
 	u32 cmd0;
 	u32 len;
-	const void *tx_buf;
 	u32 tx_count;
-	void *rx_buf;
 	u32 rx_count;
 	u32 err;
 	u8 rnw;
-	/* i2c xfer */
-	int i2c_bytes_left;
-	int i2c_is_last;
-	u8 *i2c_buf;
-	const struct i2c_msg *msg;
 };
 
 struct renesas_i3c_xfer {
@@ -258,23 +258,23 @@ struct renesas_i3c_addr {
 };
 
 struct renesas_i3c {
+	void __iomem *regs;
+	struct clk_bulk_data *clks;
+	struct reset_control *presetn;
+	struct reset_control *tresetn;
+	u32 *DATBASn;
+	struct renesas_i3c_xferqueue xferqueue;
 	struct i3c_master_controller base;
+	struct renesas_i3c_addr addrs[RENESAS_I3C_MAX_DEVS];
+	unsigned long rate;
 	enum i3c_internal_state internal_state;
-	u16 maxdevs;
+	bool resuming;
 	u32 free_pos;
 	u32 dyn_addr;
 	u32 i2c_STDBR;
 	u32 i3c_STDBR;
 	u32 extbr;
-	unsigned long rate;
-	struct renesas_i3c_addr addrs[RENESAS_I3C_MAX_DEVS];
-	struct renesas_i3c_xferqueue xferqueue;
-	void __iomem *regs;
-	u32 *DATBASn;
-	struct clk_bulk_data *clks;
-	struct reset_control *presetn;
-	struct reset_control *tresetn;
-	bool resuming;
+	u16 maxdevs;
 	u8 num_clks;
 	u8 refclk_div;
 };
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (13 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 14/17] i3c: renesas: Organize structures to avoid unnecessary padding Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 16/17] i3c: renesas: Drop unnecessary tab Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 17/17] i3c: renesas: Add runtime PM support Claudiu Beznea
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Use the "dev_name:irq_name" format for the interrupt names. This makes it
easier to identify interrupts in systems where multiple devices may request
interrupts with the same name.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- collected tags

 drivers/i3c/master/renesas-i3c.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index e1aa445de933..1ccd1c4ea27c 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -1450,12 +1450,19 @@ static int renesas_i3c_probe(struct platform_device *pdev)
 		return ret;
 
 	for (i = 0; i < ARRAY_SIZE(renesas_i3c_irqs); i++) {
+		const char *irqname;
+
 		ret = platform_get_irq_byname(pdev, renesas_i3c_irqs[i].name);
 		if (ret < 0)
 			return ret;
 
+		irqname = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s:%s", dev_name(&pdev->dev),
+					 renesas_i3c_irqs[i].desc);
+		if (!irqname)
+			return -ENOMEM;
+
 		ret = devm_request_irq(&pdev->dev, ret, renesas_i3c_irqs[i].isr,
-				       0, renesas_i3c_irqs[i].desc, i3c);
+				       0, irqname, i3c);
 		if (ret)
 			return ret;
 	}
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 16/17] i3c: renesas: Drop unnecessary tab
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (14 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  2026-06-02 13:28 ` [PATCH v2 17/17] i3c: renesas: Add runtime PM support Claudiu Beznea
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Remove an unnecessary tab to make the code cleaner.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- collected tags

 drivers/i3c/master/renesas-i3c.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 1ccd1c4ea27c..2a9bb035b8a2 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -109,7 +109,7 @@
 #define  NCMDQP_DATA_LENGTH(x)	FIELD_PREP(GENMASK(31, 16), x)
 
 #define NRSPQP			0x154 /* Normal Respone Queue */
-#define  NRSPQP_NO_ERROR			0
+#define  NRSPQP_NO_ERROR		0
 #define  NRSPQP_ERROR_CRC		1
 #define  NRSPQP_ERROR_PARITY		2
 #define  NRSPQP_ERROR_FRAME		3
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* [PATCH v2 17/17] i3c: renesas: Add runtime PM support
  2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
                   ` (15 preceding siblings ...)
  2026-06-02 13:28 ` [PATCH v2 16/17] i3c: renesas: Drop unnecessary tab Claudiu Beznea
@ 2026-06-02 13:28 ` Claudiu Beznea
  16 siblings, 0 replies; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-02 13:28 UTC (permalink / raw)
  To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
	p.zabel
  Cc: claudiu.beznea, claudiu.beznea, linux-i3c, linux-kernel,
	Claudiu Beznea

From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

On the SoCs where the Renesas I3C driver is enabled (RZ/G3S and RZ/G3E),
the clocks of the IP are managed through a clock PM domain. To keep the
I3C code simpler, the explicit clock handling was dropped along with the
addition of runtime PM support, in favor of the runtime PM APIs. Only the
code for getting tclk was preserved, as it is necessary to compute the
I3C clock rate.

All the APIs provided to the I3C subsystem through struct
i3c_master_controller_ops are guarded with runtime PM APIs to
enable/disable the controller at runtime.

As the Renesas I3C driver implements an asynchronous transmit model by
preparing a transfer and waiting for its completion through the ISR,
renesas_i3c_abort_xfer() was added to disable interrupts and clear any
pending IRQ status bits when there is no completion in the defined
timeout. Along with this, renesas_i3c_wait_xfer() return type was changed
to unsigned long.

Add runtime PM support for the Renesas I3C driver.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- dropped the runtime suspend/resume functions as for now, there will be
  no pinctrl sleep state described in DT
- do not synchronize the IRQs in renesas_i3c_abort_xfer() as some handlers
  may re-enable interrupts; instead just disable the interrupts and clean
  any status bits that the IRQ handlers are touching; with this the
  struct renesas_i3c::{irqs, num_irqs} and the associated code was removed
- dropped the renesas_i3c_dont_use_autosuspend() along with the
  devm_add_action_or_reset() call to set it since the same operation is
  done by the devres cleanup helper of devm_pm_runtime_enable()
- adjusted the renesas_i3c_suspend() with RPM calls to save the DATBAS
  registers
- use pm_runtime_resume_and_get() in renesas_i3c_resume() to avoid
  mixing gotos with cleanup helpers
- adjusted the patch description to reflect these changes

 drivers/i3c/master/renesas-i3c.c | 158 +++++++++++++++++++++++++------
 1 file changed, 130 insertions(+), 28 deletions(-)

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 2a9bb035b8a2..6684a0e75bb9 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
 #include "../internals.h"
@@ -199,8 +200,6 @@
 #define RENESAS_I3C_MAX_DEVS	8
 #define I2C_INIT_MSG		-1
 
-#define RENESAS_I3C_TCLK_IDX	1
-
 enum i3c_internal_state {
 	I3C_INTERNAL_STATE_DISABLED,
 	I3C_INTERNAL_STATE_CONTROLLER_IDLE,
@@ -259,9 +258,10 @@ struct renesas_i3c_addr {
 
 struct renesas_i3c {
 	void __iomem *regs;
-	struct clk_bulk_data *clks;
+	struct clk *tclk;
 	struct reset_control *presetn;
 	struct reset_control *tresetn;
+	struct device *dev;
 	u32 *DATBASn;
 	struct renesas_i3c_xferqueue xferqueue;
 	struct i3c_master_controller base;
@@ -275,7 +275,6 @@ struct renesas_i3c {
 	u32 i3c_STDBR;
 	u32 extbr;
 	u16 maxdevs;
-	u8 num_clks;
 	u8 refclk_div;
 };
 
@@ -440,7 +439,24 @@ static void renesas_i3c_enqueue_xfer(struct renesas_i3c *i3c, struct renesas_i3c
 	}
 }
 
-static void renesas_i3c_wait_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer)
+static void renesas_i3c_abort_xfer(struct renesas_i3c *i3c)
+{
+	guard(spinlock_irqsave)(&i3c->xferqueue.lock);
+
+	/* Disable all the interrupts */
+	renesas_writel(i3c->regs, BIE, 0);
+	renesas_writel(i3c->regs, NTIE, 0);
+
+	/* Clear normal transfer status flags. */
+	renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0 | NTST_RDBFF0 | NTST_RSPQFF |
+					   NTST_TEF | NTST_TABTF);
+	/* Clear bus status flags. */
+	renesas_clear_bit(i3c->regs, BST, BST_NACKDF | BST_TENDF | BST_SPCNDDF);
+	/* Clear error flags. */
+	renesas_clear_bit(i3c->regs, BCTL, BCTL_ABT);
+}
+
+static unsigned long renesas_i3c_wait_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer)
 {
 	unsigned long time_left;
 
@@ -449,6 +465,8 @@ static void renesas_i3c_wait_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xf
 	time_left = wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000));
 	if (!time_left)
 		renesas_i3c_dequeue_xfer(i3c, xfer);
+
+	return time_left;
 }
 
 static void renesas_i3c_set_prts(struct renesas_i3c *i3c, u32 val)
@@ -482,6 +500,12 @@ static void renesas_i3c_bus_enable(struct i3c_master_controller *m, bool i3c_mod
 static int renesas_i3c_reset(struct renesas_i3c *i3c)
 {
 	u32 val;
+	int ret;
+
+	PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(i3c->dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
 
 	renesas_writel(i3c->regs, BCTL, 0);
 	renesas_set_bit(i3c->regs, RSTCTL, RSTCTL_RI3CRST);
@@ -553,7 +577,7 @@ static int renesas_i3c_bus_init(struct i3c_master_controller *m)
 	int od_high_ticks, od_low_ticks, i2c_total_ticks;
 	int ret;
 
-	i3c->rate = clk_get_rate(i3c->clks[RENESAS_I3C_TCLK_IDX].clk);
+	i3c->rate = clk_get_rate(i3c->tclk);
 	if (!i3c->rate)
 		return -EINVAL;
 
@@ -624,6 +648,11 @@ static int renesas_i3c_bus_init(struct i3c_master_controller *m)
 	if (ret)
 		return ret;
 
+	PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(i3c->dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
 	renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
 	renesas_writel(i3c->regs, EXTBR, i3c->extbr);
 	renesas_writel(i3c->regs, REFCKCTL, REFCKCTL_IREFCKS(cks));
@@ -646,6 +675,7 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 {
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 	struct renesas_i3c_cmd *cmd;
+	unsigned long time_left;
 	u8 last_addr = 0, pos;
 	int last_i2c_pos = -1;
 	u32 olddevs, newdevs;
@@ -659,6 +689,11 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 	cmd = xfer->cmds;
 	cmd->rx_count = 0;
 
+	PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(i3c->dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
 	/* Enable I3C bus. */
 	renesas_i3c_bus_enable(m, true);
 
@@ -724,7 +759,9 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 		    NCMDQP_CMD(I3C_CCC_ENTDAA) | NCMDQP_DEV_INDEX(ret) |
 		    NCMDQP_DEV_COUNT(i3c->maxdevs - ret) | NCMDQP_TOC;
 
-	renesas_i3c_wait_xfer(i3c, xfer);
+	time_left = renesas_i3c_wait_xfer(i3c, xfer);
+	if (!time_left)
+		renesas_i3c_abort_xfer(i3c);
 
 	/* Skip attaching if there are failures on the xfer. */
 	if (xfer->ret) {
@@ -791,6 +828,7 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
 {
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 	struct renesas_i3c_cmd *cmd;
+	unsigned long time_left;
 	int ret, pos = 0;
 
 	if (ccc->id & I3C_CCC_DIRECT) {
@@ -808,6 +846,11 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
 	cmd->rnw = ccc->rnw;
 	cmd->cmd0 = 0;
 
+	PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(i3c->dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
 	renesas_i3c_bus_enable(m, true);
 
 	/* Calculate the command descriptor. */
@@ -842,7 +885,9 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
 		}
 	}
 
-	renesas_i3c_wait_xfer(i3c, xfer);
+	time_left = renesas_i3c_wait_xfer(i3c, xfer);
+	if (!time_left)
+		renesas_i3c_abort_xfer(i3c);
 
 	ret = xfer->ret;
 	if (ret)
@@ -857,7 +902,9 @@ static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 	struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
-	int i;
+	unsigned long time_left;
+	bool abort_xfer = false;
+	int i, ret;
 
 	struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
 	if (!xfer)
@@ -865,6 +912,11 @@ static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_
 
 	init_completion(&xfer->comp);
 
+	PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(i3c->dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
 	/* Enable I3C bus. */
 	renesas_i3c_bus_enable(m, true);
 
@@ -896,9 +948,14 @@ static int renesas_i3c_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *i3c_
 				renesas_set_bit(i3c->regs, NTIE, NTIE_TDBEIE0);
 		}
 
-		renesas_i3c_wait_xfer(i3c, xfer);
+		time_left = renesas_i3c_wait_xfer(i3c, xfer);
+		if (!time_left)
+			abort_xfer = true;
 	}
 
+	if (abort_xfer)
+		renesas_i3c_abort_xfer(i3c);
+
 	return 0;
 }
 
@@ -907,12 +964,17 @@ static int renesas_i3c_attach_i3c_dev(struct i3c_dev_desc *dev)
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 	struct renesas_i3c_i2c_dev_data *data;
-	int pos;
+	int pos, ret;
 
 	pos = renesas_i3c_get_free_pos(i3c);
 	if (pos < 0)
 		return pos;
 
+	PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(i3c->dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
 	data = kzalloc_obj(*data);
 	if (!data)
 		return -ENOMEM;
@@ -934,7 +996,12 @@ static int renesas_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev,
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 	struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
-	int pos;
+	int pos, ret;
+
+	PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(i3c->dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
 
 	pos = renesas_i3c_get_free_pos(i3c);
 
@@ -962,8 +1029,12 @@ static void renesas_i3c_detach_i3c_dev(struct i3c_dev_desc *dev)
 	struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
+	int ret;
 
-	renesas_writel(i3c->regs, DATBAS(data->index), 0);
+	PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(i3c->dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (!ret)
+		renesas_writel(i3c->regs, DATBAS(data->index), 0);
 
 	i3c_dev_set_master_data(dev, NULL);
 	i3c->addrs[data->index].addr = 0;
@@ -979,7 +1050,9 @@ static int renesas_i3c_i2c_xfers(struct i2c_dev_desc *dev,
 	struct renesas_i3c *i3c = to_renesas_i3c(m);
 	struct renesas_i3c_cmd *cmd;
 	u8 start_bit = CNDCTL_STCND;
-	int i;
+	unsigned long time_left;
+	bool abort_xfer = false;
+	int i, ret;
 
 	if (!i2c_nxfers)
 		return 0;
@@ -992,6 +1065,11 @@ static int renesas_i3c_i2c_xfers(struct i2c_dev_desc *dev,
 	xfer->is_i2c_xfer = true;
 	cmd = xfer->cmds;
 
+	PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(i3c->dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
 	renesas_i3c_bus_enable(m, false);
 
 	if (!(renesas_readl(i3c->regs, BCST) & BCST_BFREF)) {
@@ -1018,7 +1096,9 @@ static int renesas_i3c_i2c_xfers(struct i2c_dev_desc *dev,
 
 		renesas_set_bit(i3c->regs, NTSTE, NTSTE_TDBEE0);
 
-		wait_for_completion_timeout(&xfer->comp, m->i2c.timeout);
+		time_left = wait_for_completion_timeout(&xfer->comp, m->i2c.timeout);
+		if (!time_left)
+			abort_xfer = true;
 
 		if (cmd->err)
 			break;
@@ -1027,6 +1107,10 @@ static int renesas_i3c_i2c_xfers(struct i2c_dev_desc *dev,
 	}
 
 	renesas_i3c_dequeue_xfer(i3c, xfer);
+
+	if (abort_xfer)
+		renesas_i3c_abort_xfer(i3c);
+
 	return cmd->err;
 }
 
@@ -1425,12 +1509,16 @@ static int renesas_i3c_probe(struct platform_device *pdev)
 	if (IS_ERR(i3c->regs))
 		return PTR_ERR(i3c->regs);
 
-	ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &i3c->clks);
-	if (ret <= RENESAS_I3C_TCLK_IDX)
-		return dev_err_probe(&pdev->dev, ret < 0 ? ret : -EINVAL,
-				     "Failed to get clocks (need > %d, got %d)\n",
-				     RENESAS_I3C_TCLK_IDX, ret);
-	i3c->num_clks = ret;
+	i3c->tclk = devm_clk_get(&pdev->dev, "tclk");
+	if (IS_ERR(i3c->tclk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(i3c->tclk), "Failed to get tclk");
+
+	i3c->dev = &pdev->dev;
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 300);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	ret = devm_pm_runtime_enable(&pdev->dev);
+	if (ret)
+		return ret;
 
 	i3c->tresetn = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, "tresetn");
 	if (IS_ERR(i3c->tresetn))
@@ -1499,16 +1587,22 @@ static int renesas_i3c_suspend(struct device *dev)
 
 	i2c_mark_adapter_suspended(&i3c->base.i2c);
 
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		goto err_mark_resumed;
+
 	/* Store Device Address Table values. */
 	for (i = 0; i < i3c->maxdevs; i++)
 		i3c->DATBASn[i] = renesas_readl(i3c->regs, DATBAS(i));
 
+	ret = pm_runtime_put_sync(dev);
+	if (ret < 0)
+		goto err_mark_resumed;
+
 	ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
 	if (ret)
 		goto err_mark_resumed;
 
-	clk_bulk_disable(i3c->num_clks, i3c->clks);
-
 	return 0;
 
 err_mark_resumed:
@@ -1530,13 +1624,13 @@ static int renesas_i3c_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	ret = clk_bulk_enable(i3c->num_clks, i3c->clks);
+	ret = renesas_i3c_reset(i3c);
 	if (ret)
 		goto err_resets_asserted;
 
-	ret = renesas_i3c_reset(i3c);
+	ret = pm_runtime_resume_and_get(dev);
 	if (ret)
-		goto err_clks_disable;
+		goto err_resets_asserted;
 
 	/* Re-store I3C registers value. */
 	renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
@@ -1559,15 +1653,23 @@ static int renesas_i3c_resume(struct device *dev)
 
 	i3c->resuming = false;
 
+	pm_runtime_put_autosuspend(dev);
+
 	/*
 	 * I3C devices may have retained their dynamic address anyway. Do not
 	 * fail the resume because of DAA error.
 	 */
 	return 0;
 
-err_clks_disable:
-	clk_bulk_disable(i3c->num_clks, i3c->clks);
 err_resets_asserted:
+	/*
+	 * If this happens, there is no way to recover from this state without
+	 * reloading the driver. We want to avoid keeping the reset line
+	 * deasserted unnecessarily. The runtime paths will still work correctly
+	 * even if the IP registers are accessed while reset is asserted (e.g.
+	 * if a runtime path is triggered after a failed resume). Checked on
+	 * RZ/G3S.
+	 */
 	reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
 	return ret;
 }
-- 
2.43.0


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* Re: [PATCH v2 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}()
  2026-06-02 13:28 ` [PATCH v2 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}() Claudiu Beznea
@ 2026-06-02 15:09   ` Philipp Zabel
  0 siblings, 0 replies; 25+ messages in thread
From: Philipp Zabel @ 2026-06-02 15:09 UTC (permalink / raw)
  To: Claudiu Beznea, wsa+renesas, tommaso.merciai.xr,
	alexandre.belloni, Frank.Li
  Cc: claudiu.beznea, linux-i3c, linux-kernel, Claudiu Beznea

On Di, 2026-06-02 at 16:28 +0300, Claudiu Beznea wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> Use reset_control_bulk_assert() and reset_control_bulk_deassert() in the
> suspend and resume paths to simplify the code.

This looks like we are missing
devm_reset_control_bulk_get_optional_exclusive_deasserted().

regards
Philipp

-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* Re: [PATCH v2 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach
  2026-06-02 13:28 ` [PATCH v2 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach Claudiu Beznea
@ 2026-06-02 20:05   ` Frank Li
  0 siblings, 0 replies; 25+ messages in thread
From: Frank Li @ 2026-06-02 20:05 UTC (permalink / raw)
  To: Claudiu Beznea
  Cc: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, p.zabel,
	claudiu.beznea, linux-i3c, linux-kernel, Claudiu Beznea, stable

On Tue, Jun 02, 2026 at 04:28:11PM +0300, Claudiu Beznea wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> During re-attach, the device may change its position in the i3c->addrs[]
> array. As a result, it may use a different Device Address Table Basic
> Register (DATBAS), which needs to be reconfigured.
>
> Reconfigure the DATBAS register on re-attach. Along with it update
> software caches.
>
> Fixes: d028219a9f14 ("i3c: master: Add basic driver for the Renesas I3C controller")
> Cc: stable@vger.kernel.org
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>
> Changes in v2:
> - dropped the "if (pos < 0)" check in renesas_i3c_reattach_i3c_dev() to allow
>   re-attaching in case of a full bus; along with it the condition to update
>   the DATBAS register and software caches was updated to
>   if (data->index != pos && pos >= 0)
> - adjusted the patch title
>
>  drivers/i3c/master/renesas-i3c.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
> index 4c86e7257804..76a4831098c9 100644
> --- a/drivers/i3c/master/renesas-i3c.c
> +++ b/drivers/i3c/master/renesas-i3c.c
> @@ -892,10 +892,26 @@ static int renesas_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev,
>  	struct i3c_master_controller *m = i3c_dev_get_master(dev);
>  	struct renesas_i3c *i3c = to_renesas_i3c(m);
>  	struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
> +	int pos;
> +
> +	pos = renesas_i3c_get_free_pos(i3c);
> +
> +	if (data->index != pos && pos >= 0) {
> +		renesas_writel(i3c->regs, DATBAS(data->index), 0);
> +		i3c->addrs[data->index] = 0;
> +		i3c->free_pos |= BIT(data->index);
> +
> +		data->index = pos;
> +		i3c->free_pos &= ~BIT(data->index);
> +	}
>
>  	i3c->addrs[data->index] = dev->info.dyn_addr ? dev->info.dyn_addr :
>  							dev->info.static_addr;
>
> +	renesas_writel(i3c->regs, DATBAS(data->index),
> +		       DATBAS_DVSTAD(dev->info.static_addr) |
> +		       datbas_dvdyad_with_parity(i3c->addrs[data->index]));
> +
>  	return 0;
>  }
>
> --
> 2.43.0
>

-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* Re: [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment on resume
  2026-06-02 13:28 ` [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment " Claudiu Beznea
@ 2026-06-02 20:12   ` Frank Li
  2026-06-03 14:23     ` Claudiu Beznea
  0 siblings, 1 reply; 25+ messages in thread
From: Frank Li @ 2026-06-02 20:12 UTC (permalink / raw)
  To: Claudiu Beznea
  Cc: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, p.zabel,
	claudiu.beznea, linux-i3c, linux-kernel, Claudiu Beznea, stable

On Tue, Jun 02, 2026 at 04:28:13PM +0300, Claudiu Beznea wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> The Renesas RZ/G3S SoC supports a power saving mode where power to most
> SoC components, including I3C, is turned off.
>
> On systems where the I3C devices also loses power during suspend (e.g. NXP
> P3T1085UK-ARD connected to the PMOD1_6A connector of the RZ SMARC Carrier
> 2 + Renesas RZ/G3S SMARC SOM), the devices becomes unreachable after
> resume.
>
> Running DAA in the controller resume path restores communication. However,
> DAA relies on interrupts for TX/RX, which are not available in the noirq
> suspend/resume phase (unless they are wakeup interrupts). For this, the
> suspend/resume callbacks were moved out of the noirq phase. Currently,
> there is no identified use case on either the Renesas RZ/G3S or Renesas
> RZ/G3E SoCs that requires the controller suspend/resume hooks to be part of
> the noirq suspend/resume phase.
>
> Since renesas_i3c_reset() is not called anymore in atomic context
> update it to use read_poll_timeout().
>
> To cover the case where the controller had already attached all the
> i3c->maxdevs devices before a suspend/resume cycle and i3c->free_pos is
> zero, struct renesas_i3c::resuming flag was introduced.
>
> The flag is set in renesas_i3c_resume() before calling
> i3c_master_do_daa_ext() and checked in renesas_i3c_daa(). In case it is
> set the previous saved DATBAS register values are used for the slots
> already occupied before suspend. This allows keeping alive the connection
> to the I3C devices when all the supported slots are occupied before
> suspend.
>
> When resuming from suspend, renesas_i3c_daa() re-runs DAA for al
> slots except those used by I2C devices. I2C devices are attached during
> probe, at bus initialization time, and always occupy the first positions in
> i3c->free_pos. In addition, there are no DATBAS register settings
> associated with them.
>
> Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
> Cc: stable@vger.kernel.org
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---

Please check sashiko review result

https://sashiko.dev/#/patchset/20260602132824.3541151-1-claudiu.beznea%40kernel.org

Frank

>

-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* Re: [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment on resume
  2026-06-02 20:12   ` Frank Li
@ 2026-06-03 14:23     ` Claudiu Beznea
  2026-06-03 19:26       ` Frank Li
  0 siblings, 1 reply; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-03 14:23 UTC (permalink / raw)
  To: Frank Li
  Cc: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, p.zabel,
	claudiu.beznea, linux-i3c, linux-kernel, Claudiu Beznea, stable

Hi, Frank, I3C maintainers,

I've inlined the sashiko comments here to discuss them:

On 6/2/26 23:12, Frank Li wrote:
> On Tue, Jun 02, 2026 at 04:28:13PM +0300, Claudiu Beznea wrote:
>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>
>> The Renesas RZ/G3S SoC supports a power saving mode where power to most
>> SoC components, including I3C, is turned off.
>>
>> On systems where the I3C devices also loses power during suspend (e.g. NXP
>> P3T1085UK-ARD connected to the PMOD1_6A connector of the RZ SMARC Carrier
>> 2 + Renesas RZ/G3S SMARC SOM), the devices becomes unreachable after
>> resume.
>>
>> Running DAA in the controller resume path restores communication. However,
>> DAA relies on interrupts for TX/RX, which are not available in the noirq
>> suspend/resume phase (unless they are wakeup interrupts). For this, the
>> suspend/resume callbacks were moved out of the noirq phase. Currently,
>> there is no identified use case on either the Renesas RZ/G3S or Renesas
>> RZ/G3E SoCs that requires the controller suspend/resume hooks to be part of
>> the noirq suspend/resume phase.
>>
>> Since renesas_i3c_reset() is not called anymore in atomic context
>> update it to use read_poll_timeout().
>>
>> To cover the case where the controller had already attached all the
>> i3c->maxdevs devices before a suspend/resume cycle and i3c->free_pos is
>> zero, struct renesas_i3c::resuming flag was introduced.
>>
>> The flag is set in renesas_i3c_resume() before calling
>> i3c_master_do_daa_ext() and checked in renesas_i3c_daa(). In case it is
>> set the previous saved DATBAS register values are used for the slots
>> already occupied before suspend. This allows keeping alive the connection
>> to the I3C devices when all the supported slots are occupied before
>> suspend.
>>
>> When resuming from suspend, renesas_i3c_daa() re-runs DAA for al
>> slots except those used by I2C devices. I2C devices are attached during
>> probe, at bus initialization time, and always occupy the first positions in
>> i3c->free_pos. In addition, there are no DATBAS register settings
>> associated with them.
>>
>> Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>> ---
> 
> Please check sashiko review result
> 
> https://sashiko.dev/#/patchset/20260602132824.3541151-1-claudiu.beznea%40kernel.org
> 
 >commit 6783acf82418dd115df661f4dc9d5758f653b084
 >Author: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
 >Date:   Tue Jun 2 13:28:13 2026 +0000
 >    i3c: renesas: Perform Dynamic Address Assignment on resume
 >    The Renesas RZ/G3S SoC supports a power saving mode where power to most
 >    SoC components, including I3C, is turned off.
 >
 >    On systems where the I3C devices also loses power during suspend (e.g. NXP
 >    P3T1085UK-ARD connected to the PMOD1_6A connector of the RZ SMARC Carrier
 >    2 + Renesas RZ/G3S SMARC SOM), the devices becomes unreachable after
 >    resume.
 >
 >    Running DAA in the controller resume path restores communication. However,
 >    DAA relies on interrupts for TX/RX, which are not available in the noirq
 >    suspend/resume phase (unless they are wakeup interrupts). For this, the
 >    suspend/resume callbacks were moved out of the noirq phase. Currently,
 >    there is no identified use case on either the Renesas RZ/G3S or Renesas
 >    RZ/G3E SoCs that requires the controller suspend/resume hooks to be part of
 >    the noirq suspend/resume phase.
 >    Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
 >    Cc: stable@vger.kernel.org
 >> --- a/drivers/i3c/master/renesas-i3c.c
 >> +++ b/drivers/i3c/master/renesas-i3c.c
 >[ ... ]
 >> @@ -657,14 +664,33 @@ static int renesas_i3c_daa(struct 
i3c_master_controller *m)
 >>
 >>      /* Setting DATBASn registers for target devices. */
 >>      for (pos = 0; pos < i3c->maxdevs; pos++) {
 >> -            if (olddevs & BIT(pos))
 >> +            if (olddevs & BIT(pos)) {
 >> +                    /*
 >> +                     * In case of resume, reassign DAs for all devices on the
 >> +                     * bus to avoid failures when all i3c->maxdevs slots were
 >> +                     * already occupied before suspend.
 >> +                     *
 >> +                     * Exclude I2C devices, as they are attached during probe,
 >> +                     * at bus initialization time, and there are currently no
 >> +                     * register updates associated with them.
 >> +                     */
 >> +                    if (i3c->resuming) {
 >> +                            if (i3c->addrs[pos].is_i2c) {
 >> +                                    last_i2c_pos = pos;
 >> +                            } else {
 >> +                                    renesas_writel(i3c->regs, DATBAS(pos),
 >> +                                                   i3c->DATBASn[pos]);
 >> +                            }
 >> +                    }
 >Does restoring these blindly from the saved state cement addresses for future
 >ENTDAA, bypassing normal device assignment?
 >If a device is removed, hot-plugged, or wakes up slowly, couldn't a different
 >device win arbitration and be assigned an address from an unrelated DATBASn
 >slot?

Currently, the driver don't support hot-plug.

I presumed the remove in suspend is not actually a valid use-case, but with this 
scenario, if that happens, the device still remains attached in the software 
data structures. After this sequence:
1/ suspend
2/ disconnect an I3C device
3/ resume
4/ suspend
5/ re-connect the I3C devices
6/ resume

the reconnected I3C device works again after step 6 (according to my testing).

Waking up may happen slowly, indeed. So, I presume this is a valid use case.

Now, I have few question (if my I3C understanding is right):

I noticed none of the I3C drivers are taking care of the use case where the bus 
is fully populated after resume (and we are after a resume with power lost, for 
both the controller and the devices). That looks a bit tricky scenario to cover, 
to be honest, as all the drivers check for a free slot in ->attach_i3c_dev(), 
and, for a fully populated bus, that will not update the newly assigned 
addresses in the subsystem data structure.

If the ->attach_i3c_dev() called though the i3c_master_add_i3c_dev_locked() 
fails then nothing is continued so, the device address changes are not 
propagated in all the software data structures.

In case we re-use the DATBAS() register values as proposed in this patch, we 
have the changes that the driver software data caches (i3c->addrs[].addr) and 
the subsystem I3C devices addresses to match. But, that may not be true all the 
time.

If we re-assign new addresses to i3c->addrs[].addr in the DAA API, then write 
those values to DATBAS() registers, but the bus is fully populated, or no new 
devices are discovered as the indices remains the same, then, since we execute 
i3c_master_add_i3c_dev_locked() only for the newly attached devices, then the 
subsystem and the driver addresses don't match anymore. I couldn't found a 
global API similar to i3c_master_add_i3c_dev_locked() to work for removing 
devices and re-attaching at resume, for such scenario. I'm not sure that's good 
to do, though. If we call i3c_master_add_i3c_dev_locked() unconditionally, then 
it will still not work on a full previously occupied bus.

If I'm not wrong with all these, could you please let me know how would you 
consider covering this scenario? This is what I've tried to address with the 
approach in this patch. I currently don't have a testing setup for this, I only 
simulated it by setting i3c->free_pos = 0 before calling i3c_master_do_daa_ext().

Would the usage of i3c_device_do_setdasa() being called from a master driver be 
something acceptable? Though, I currently haven't played around with it.

As I don't have a real setup to test this, would it be OK to restore the 
approach in this patch as proposed in v1?

Please let me know. Thank you!

 >> +
 >>                      continue;
 >> +            }
 >>
 >>              ret = i3c_master_get_free_addr(m, last_addr + 1);
 >[ ... ]
 >> @@ -674,9 +700,21 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 >>      cmd = xfer->cmds;
 >>      cmd->rx_count = 0;
 >>
 >> -    ret = renesas_i3c_get_free_pos(i3c);
 >> -    if (ret < 0)
 >> -            return ret;
 >> +    if (i3c->resuming) {
 >> +            /* Nothing to do if all slots are ocupied by I2C devices. */
 >> +            if (last_i2c_pos == i3c->maxdevs - 1)
 >> +                    return 0;
 >> +
 >> +            /*
 >> +             * Do DAA for all the devices on the bus, if resuming, except
 >> +             * the I2C ones.
 >> +             */
 >> +            ret = last_i2c_pos < 0 ? 0 : last_i2c_pos + 1;
 >Does this incorrectly assume that all I2C devices occupy contiguous slots at
 >the beginning of the device array?

I wasn't aware of the notifier used to add I2C devices to the bus.

 >If an I2C device is attached dynamically at a higher slot while lower slots
 >are occupied by I3C devices, will DAA start at a higher index, skipping the
 >lower I3C devices? The hardware would assign new addresses from the higher
 >offset, duplicating devices and breaking communication.
 >> +    } else {
 >> +            ret = renesas_i3c_get_free_pos(i3c);
 >> +            if (ret < 0)
 >> +                    return ret;
 >> +    }
 >>
 >>      /*
 >>       * Setup the command descriptor to start the ENTDAA command
 >> @@ -694,7 +732,7 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
 >>
 >>      for (pos = 0; pos < i3c->maxdevs; pos++) {
 >>              if (newdevs & BIT(pos))
 >> -                    i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos]);
 >> +                    i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos].addr);
 >>      }
 >Since olddevs are masked out from newdevs prior to this loop in renesas_i3c_daa
 >(newdevs &= ~olddevs), is the I3C framework prevented from being notified of
 >shifted dynamic addresses landing in previously occupied slots?
 >Because i3c_master_add_i3c_dev_locked() is never called for these, the
 >framework could remain unaware of identity shifts and continue communicating
 >with devices using mismatched PIDs, risking data corruption.

That is a previously existing problem that may happen. However, I am not sure 
how we should deal with the case when this is called after resume, on a fully 
populated bus.

Frank, I3C maintainers, should we cover this case for now? Do you have some 
hints on how to go forward with it?

 >[ ... ]
 >> @@ -1435,7 +1475,7 @@ static void renesas_i3c_remove(struct platform_device 
*pdev)
 >>      i3c_master_unregister(&i3c->base);
 >>  }
 >>
 >> -static int renesas_i3c_suspend_noirq(struct device *dev)
 >> +static int renesas_i3c_suspend(struct device *dev)
 >>  {
 >>      struct renesas_i3c *i3c = dev_get_drvdata(dev);
 >>      int i, ret;
 >[ ... ]
 >> +    ret = reset_control_assert(i3c->tresetn);
 >> +    if (ret)
 >> +            goto err_presetn;
 >> +
 >> +    clk_bulk_disable(i3c->num_clks, i3c->clks);
 >> +
 >> +    return 0;
 >Since this callback is being moved out of the noirq phase where interrupts are
 >still enabled, is it safe to disable clocks and assert hardware resets without
 >first disabling the device interrupts (e.g., via disable_irq())?
 >If an interrupt fires during this time, the ISR might access unclocked MMIO
 >registers belonging to a reset IP, which could trigger a synchronous external
 >abort.

That may have happen even previously if the interrupts were configured as wakeup 
sources. However, at this point, all the clients should be suspended and thus, 
they shouldn't generate interrupts.


-- 
Thank you,
Claudiu


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* Re: [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment on resume
  2026-06-03 14:23     ` Claudiu Beznea
@ 2026-06-03 19:26       ` Frank Li
  2026-06-04 13:04         ` Claudiu Beznea
  0 siblings, 1 reply; 25+ messages in thread
From: Frank Li @ 2026-06-03 19:26 UTC (permalink / raw)
  To: Claudiu Beznea
  Cc: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, p.zabel,
	claudiu.beznea, linux-i3c, linux-kernel, Claudiu Beznea, stable

On Wed, Jun 03, 2026 at 05:23:06PM +0300, Claudiu Beznea wrote:
> Hi, Frank, I3C maintainers,
>
> I've inlined the sashiko comments here to discuss them:
>
> On 6/2/26 23:12, Frank Li wrote:
> > On Tue, Jun 02, 2026 at 04:28:13PM +0300, Claudiu Beznea wrote:
> > > From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > >
> > > The Renesas RZ/G3S SoC supports a power saving mode where power to most
> > > SoC components, including I3C, is turned off.
> > >
> > > On systems where the I3C devices also loses power during suspend (e.g. NXP
> > > P3T1085UK-ARD connected to the PMOD1_6A connector of the RZ SMARC Carrier
> > > 2 + Renesas RZ/G3S SMARC SOM), the devices becomes unreachable after
> > > resume.
> > >
> > > Running DAA in the controller resume path restores communication. However,
> > > DAA relies on interrupts for TX/RX, which are not available in the noirq
> > > suspend/resume phase (unless they are wakeup interrupts). For this, the
> > > suspend/resume callbacks were moved out of the noirq phase. Currently,
> > > there is no identified use case on either the Renesas RZ/G3S or Renesas
> > > RZ/G3E SoCs that requires the controller suspend/resume hooks to be part of
> > > the noirq suspend/resume phase.
> > >
> > > Since renesas_i3c_reset() is not called anymore in atomic context
> > > update it to use read_poll_timeout().
> > >
> > > To cover the case where the controller had already attached all the
> > > i3c->maxdevs devices before a suspend/resume cycle and i3c->free_pos is
> > > zero, struct renesas_i3c::resuming flag was introduced.
> > >
> > > The flag is set in renesas_i3c_resume() before calling
> > > i3c_master_do_daa_ext() and checked in renesas_i3c_daa(). In case it is
> > > set the previous saved DATBAS register values are used for the slots
> > > already occupied before suspend. This allows keeping alive the connection
> > > to the I3C devices when all the supported slots are occupied before
> > > suspend.
> > >
> > > When resuming from suspend, renesas_i3c_daa() re-runs DAA for al
> > > slots except those used by I2C devices. I2C devices are attached during
> > > probe, at bus initialization time, and always occupy the first positions in
> > > i3c->free_pos. In addition, there are no DATBAS register settings
> > > associated with them.
> > >
> > > Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
> > > Cc: stable@vger.kernel.org
> > > Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > > ---
> >
> > Please check sashiko review result
> >
> > https://sashiko.dev/#/patchset/20260602132824.3541151-1-claudiu.beznea%40kernel.org
> >
> >commit 6783acf82418dd115df661f4dc9d5758f653b084
> >Author: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >Date:   Tue Jun 2 13:28:13 2026 +0000
> >    i3c: renesas: Perform Dynamic Address Assignment on resume
> >    The Renesas RZ/G3S SoC supports a power saving mode where power to most
> >    SoC components, including I3C, is turned off.
> >
> >    On systems where the I3C devices also loses power during suspend (e.g. NXP
> >    P3T1085UK-ARD connected to the PMOD1_6A connector of the RZ SMARC Carrier
> >    2 + Renesas RZ/G3S SMARC SOM), the devices becomes unreachable after
> >    resume.
> >
> >    Running DAA in the controller resume path restores communication. However,
> >    DAA relies on interrupts for TX/RX, which are not available in the noirq
> >    suspend/resume phase (unless they are wakeup interrupts). For this, the
> >    suspend/resume callbacks were moved out of the noirq phase. Currently,
> >    there is no identified use case on either the Renesas RZ/G3S or Renesas
> >    RZ/G3E SoCs that requires the controller suspend/resume hooks to be part of
> >    the noirq suspend/resume phase.
> >    Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
> >    Cc: stable@vger.kernel.org
> >> --- a/drivers/i3c/master/renesas-i3c.c
> >> +++ b/drivers/i3c/master/renesas-i3c.c
> >[ ... ]
> >> @@ -657,14 +664,33 @@ static int renesas_i3c_daa(struct
> i3c_master_controller *m)
> >>
> >>      /* Setting DATBASn registers for target devices. */
> >>      for (pos = 0; pos < i3c->maxdevs; pos++) {
> >> -            if (olddevs & BIT(pos))
> >> +            if (olddevs & BIT(pos)) {
> >> +                    /*
> >> +                     * In case of resume, reassign DAs for all devices on the
> >> +                     * bus to avoid failures when all i3c->maxdevs slots were
> >> +                     * already occupied before suspend.
> >> +                     *
> >> +                     * Exclude I2C devices, as they are attached during probe,
> >> +                     * at bus initialization time, and there are currently no
> >> +                     * register updates associated with them.
> >> +                     */
> >> +                    if (i3c->resuming) {
> >> +                            if (i3c->addrs[pos].is_i2c) {
> >> +                                    last_i2c_pos = pos;
> >> +                            } else {
> >> +                                    renesas_writel(i3c->regs, DATBAS(pos),
> >> +                                                   i3c->DATBASn[pos]);
> >> +                            }
> >> +                    }
> >Does restoring these blindly from the saved state cement addresses for future
> >ENTDAA, bypassing normal device assignment?
> >If a device is removed, hot-plugged, or wakes up slowly, couldn't a different
> >device win arbitration and be assigned an address from an unrelated DATBASn
> >slot?
>
> Currently, the driver don't support hot-plug.
>
> I presumed the remove in suspend is not actually a valid use-case, but with
> this scenario, if that happens, the device still remains attached in the
> software data structures. After this sequence:
> 1/ suspend
> 2/ disconnect an I3C device
> 3/ resume
> 4/ suspend
> 5/ re-connect the I3C devices
> 6/ resume
>
> the reconnected I3C device works again after step 6 (according to my testing).
>
> Waking up may happen slowly, indeed. So, I presume this is a valid use case.
>
> Now, I have few question (if my I3C understanding is right):
>
> I noticed none of the I3C drivers are taking care of the use case where the
> bus is fully populated after resume (and we are after a resume with power
> lost, for both the controller and the devices). That looks a bit tricky
> scenario to cover, to be honest, as all the drivers check for a free slot in
> ->attach_i3c_dev(), and, for a fully populated bus, that will not update the
> newly assigned addresses in the subsystem data structure.
>
> If the ->attach_i3c_dev() called though the i3c_master_add_i3c_dev_locked()
> fails then nothing is continued so, the device address changes are not
> propagated in all the software data structures.
>
> In case we re-use the DATBAS() register values as proposed in this patch, we
> have the changes that the driver software data caches (i3c->addrs[].addr)
> and the subsystem I3C devices addresses to match. But, that may not be true
> all the time.
>
> If we re-assign new addresses to i3c->addrs[].addr in the DAA API, then
> write those values to DATBAS() registers, but the bus is fully populated, or
> no new devices are discovered as the indices remains the same, then, since
> we execute i3c_master_add_i3c_dev_locked() only for the newly attached
> devices, then the subsystem and the driver addresses don't match anymore. I
> couldn't found a global API similar to i3c_master_add_i3c_dev_locked() to
> work for removing devices and re-attaching at resume, for such scenario. I'm
> not sure that's good to do, though. If we call
> i3c_master_add_i3c_dev_locked() unconditionally, then it will still not work
> on a full previously occupied bus.
>
> If I'm not wrong with all these, could you please let me know how would you
> consider covering this scenario? This is what I've tried to address with the
> approach in this patch. I currently don't have a testing setup for this, I
> only simulated it by setting i3c->free_pos = 0 before calling
> i3c_master_do_daa_ext().
>
> Would the usage of i3c_device_do_setdasa() being called from a master driver
> be something acceptable? Though, I currently haven't played around with it.
>
> As I don't have a real setup to test this, would it be OK to restore the
> approach in this patch as proposed in v1?

This case is quite complex, and many people try to resolve simialar
problems, you may want to reattach device because controller lost state.

hub have similar requirement, which need reattach devices.

https://lore.kernel.org/linux-i3c/20260525064209.2263045-1-lakshay.piplani@nxp.com/T/#ma99fa92cb3aac770995350e0fc22c144b974a038

controller lost state, but may i3c devices still alive and they dynamtic
address during suspend. Does reattach to the old address help your case?

Frank


>
> Please let me know. Thank you!
>
> >> +
> >>                      continue;
> >> +            }
> >>
> >>              ret = i3c_master_get_free_addr(m, last_addr + 1);
> >[ ... ]
> >> @@ -674,9 +700,21 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
> >>      cmd = xfer->cmds;
> >>      cmd->rx_count = 0;
> >>
> >> -    ret = renesas_i3c_get_free_pos(i3c);
> >> -    if (ret < 0)
> >> -            return ret;
> >> +    if (i3c->resuming) {
> >> +            /* Nothing to do if all slots are ocupied by I2C devices. */
> >> +            if (last_i2c_pos == i3c->maxdevs - 1)
> >> +                    return 0;
> >> +
> >> +            /*
> >> +             * Do DAA for all the devices on the bus, if resuming, except
> >> +             * the I2C ones.
> >> +             */
> >> +            ret = last_i2c_pos < 0 ? 0 : last_i2c_pos + 1;
> >Does this incorrectly assume that all I2C devices occupy contiguous slots at
> >the beginning of the device array?
>
> I wasn't aware of the notifier used to add I2C devices to the bus.
>
> >If an I2C device is attached dynamically at a higher slot while lower slots
> >are occupied by I3C devices, will DAA start at a higher index, skipping the
> >lower I3C devices? The hardware would assign new addresses from the higher
> >offset, duplicating devices and breaking communication.
> >> +    } else {
> >> +            ret = renesas_i3c_get_free_pos(i3c);
> >> +            if (ret < 0)
> >> +                    return ret;
> >> +    }
> >>
> >>      /*
> >>       * Setup the command descriptor to start the ENTDAA command
> >> @@ -694,7 +732,7 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
> >>
> >>      for (pos = 0; pos < i3c->maxdevs; pos++) {
> >>              if (newdevs & BIT(pos))
> >> -                    i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos]);
> >> +                    i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos].addr);
> >>      }
> >Since olddevs are masked out from newdevs prior to this loop in renesas_i3c_daa
> >(newdevs &= ~olddevs), is the I3C framework prevented from being notified of
> >shifted dynamic addresses landing in previously occupied slots?
> >Because i3c_master_add_i3c_dev_locked() is never called for these, the
> >framework could remain unaware of identity shifts and continue communicating
> >with devices using mismatched PIDs, risking data corruption.
>
> That is a previously existing problem that may happen. However, I am not
> sure how we should deal with the case when this is called after resume, on a
> fully populated bus.
>
> Frank, I3C maintainers, should we cover this case for now? Do you have some
> hints on how to go forward with it?
>
> >[ ... ]
> >> @@ -1435,7 +1475,7 @@ static void renesas_i3c_remove(struct
> platform_device *pdev)
> >>      i3c_master_unregister(&i3c->base);
> >>  }
> >>
> >> -static int renesas_i3c_suspend_noirq(struct device *dev)
> >> +static int renesas_i3c_suspend(struct device *dev)
> >>  {
> >>      struct renesas_i3c *i3c = dev_get_drvdata(dev);
> >>      int i, ret;
> >[ ... ]
> >> +    ret = reset_control_assert(i3c->tresetn);
> >> +    if (ret)
> >> +            goto err_presetn;
> >> +
> >> +    clk_bulk_disable(i3c->num_clks, i3c->clks);
> >> +
> >> +    return 0;
> >Since this callback is being moved out of the noirq phase where interrupts are
> >still enabled, is it safe to disable clocks and assert hardware resets without
> >first disabling the device interrupts (e.g., via disable_irq())?
> >If an interrupt fires during this time, the ISR might access unclocked MMIO
> >registers belonging to a reset IP, which could trigger a synchronous external
> >abort.
>
> That may have happen even previously if the interrupts were configured as
> wakeup sources. However, at this point, all the clients should be suspended
> and thus, they shouldn't generate interrupts.
>
>
> --
> Thank you,
> Claudiu
>

-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* Re: [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment on resume
  2026-06-03 19:26       ` Frank Li
@ 2026-06-04 13:04         ` Claudiu Beznea
  2026-06-04 18:49           ` Frank Li
  0 siblings, 1 reply; 25+ messages in thread
From: Claudiu Beznea @ 2026-06-04 13:04 UTC (permalink / raw)
  To: Frank Li
  Cc: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, p.zabel,
	claudiu.beznea, linux-i3c, linux-kernel, Claudiu Beznea, stable

Hi, Frank,

On 6/3/26 22:26, Frank Li wrote:
> On Wed, Jun 03, 2026 at 05:23:06PM +0300, Claudiu Beznea wrote:
>> Hi, Frank, I3C maintainers,
>>
>> I've inlined the sashiko comments here to discuss them:
>>
>> On 6/2/26 23:12, Frank Li wrote:
>>> On Tue, Jun 02, 2026 at 04:28:13PM +0300, Claudiu Beznea wrote:
>>>> From: Claudiu Beznea<claudiu.beznea.uj@bp.renesas.com>
>>>>
>>>> The Renesas RZ/G3S SoC supports a power saving mode where power to most
>>>> SoC components, including I3C, is turned off.
>>>>
>>>> On systems where the I3C devices also loses power during suspend (e.g. NXP
>>>> P3T1085UK-ARD connected to the PMOD1_6A connector of the RZ SMARC Carrier
>>>> 2 + Renesas RZ/G3S SMARC SOM), the devices becomes unreachable after
>>>> resume.
>>>>
>>>> Running DAA in the controller resume path restores communication. However,
>>>> DAA relies on interrupts for TX/RX, which are not available in the noirq
>>>> suspend/resume phase (unless they are wakeup interrupts). For this, the
>>>> suspend/resume callbacks were moved out of the noirq phase. Currently,
>>>> there is no identified use case on either the Renesas RZ/G3S or Renesas
>>>> RZ/G3E SoCs that requires the controller suspend/resume hooks to be part of
>>>> the noirq suspend/resume phase.
>>>>
>>>> Since renesas_i3c_reset() is not called anymore in atomic context
>>>> update it to use read_poll_timeout().
>>>>
>>>> To cover the case where the controller had already attached all the
>>>> i3c->maxdevs devices before a suspend/resume cycle and i3c->free_pos is
>>>> zero, struct renesas_i3c::resuming flag was introduced.
>>>>
>>>> The flag is set in renesas_i3c_resume() before calling
>>>> i3c_master_do_daa_ext() and checked in renesas_i3c_daa(). In case it is
>>>> set the previous saved DATBAS register values are used for the slots
>>>> already occupied before suspend. This allows keeping alive the connection
>>>> to the I3C devices when all the supported slots are occupied before
>>>> suspend.
>>>>
>>>> When resuming from suspend, renesas_i3c_daa() re-runs DAA for al
>>>> slots except those used by I2C devices. I2C devices are attached during
>>>> probe, at bus initialization time, and always occupy the first positions in
>>>> i3c->free_pos. In addition, there are no DATBAS register settings
>>>> associated with them.
>>>>
>>>> Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
>>>> Cc:stable@vger.kernel.org
>>>> Signed-off-by: Claudiu Beznea<claudiu.beznea.uj@bp.renesas.com>
>>>> ---
>>> Please check sashiko review result
>>>
>>> https://sashiko.dev/#/patchset/20260602132824.3541151-1- 
>>> claudiu.beznea%40kernel.org
>>>
>>> commit 6783acf82418dd115df661f4dc9d5758f653b084
>>> Author: Claudiu Beznea<claudiu.beznea.uj@bp.renesas.com>
>>> Date:   Tue Jun 2 13:28:13 2026 +0000
>>>     i3c: renesas: Perform Dynamic Address Assignment on resume
>>>     The Renesas RZ/G3S SoC supports a power saving mode where power to most
>>>     SoC components, including I3C, is turned off.
>>>
>>>     On systems where the I3C devices also loses power during suspend (e.g. NXP
>>>     P3T1085UK-ARD connected to the PMOD1_6A connector of the RZ SMARC Carrier
>>>     2 + Renesas RZ/G3S SMARC SOM), the devices becomes unreachable after
>>>     resume.
>>>
>>>     Running DAA in the controller resume path restores communication. However,
>>>     DAA relies on interrupts for TX/RX, which are not available in the noirq
>>>     suspend/resume phase (unless they are wakeup interrupts). For this, the
>>>     suspend/resume callbacks were moved out of the noirq phase. Currently,
>>>     there is no identified use case on either the Renesas RZ/G3S or Renesas
>>>     RZ/G3E SoCs that requires the controller suspend/resume hooks to be part of
>>>     the noirq suspend/resume phase.
>>>     Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
>>>     Cc:stable@vger.kernel.org
>>>> --- a/drivers/i3c/master/renesas-i3c.c
>>>> +++ b/drivers/i3c/master/renesas-i3c.c
>>> [ ... ]
>>>> @@ -657,14 +664,33 @@ static int renesas_i3c_daa(struct
>> i3c_master_controller *m)
>>>>       /* Setting DATBASn registers for target devices. */
>>>>       for (pos = 0; pos < i3c->maxdevs; pos++) {
>>>> -            if (olddevs & BIT(pos))
>>>> +            if (olddevs & BIT(pos)) {
>>>> +                    /*
>>>> +                     * In case of resume, reassign DAs for all devices on the
>>>> +                     * bus to avoid failures when all i3c->maxdevs slots were
>>>> +                     * already occupied before suspend.
>>>> +                     *
>>>> +                     * Exclude I2C devices, as they are attached during probe,
>>>> +                     * at bus initialization time, and there are currently no
>>>> +                     * register updates associated with them.
>>>> +                     */
>>>> +                    if (i3c->resuming) {
>>>> +                            if (i3c->addrs[pos].is_i2c) {
>>>> +                                    last_i2c_pos = pos;
>>>> +                            } else {
>>>> +                                    renesas_writel(i3c->regs, DATBAS(pos),
>>>> +                                                   i3c->DATBASn[pos]);
>>>> +                            }
>>>> +                    }
>>> Does restoring these blindly from the saved state cement addresses for future
>>> ENTDAA, bypassing normal device assignment?
>>> If a device is removed, hot-plugged, or wakes up slowly, couldn't a different
>>> device win arbitration and be assigned an address from an unrelated DATBASn
>>> slot?
>> Currently, the driver don't support hot-plug.
>>
>> I presumed the remove in suspend is not actually a valid use-case, but with
>> this scenario, if that happens, the device still remains attached in the
>> software data structures. After this sequence:
>> 1/ suspend
>> 2/ disconnect an I3C device
>> 3/ resume
>> 4/ suspend
>> 5/ re-connect the I3C devices
>> 6/ resume
>>
>> the reconnected I3C device works again after step 6 (according to my testing).
>>
>> Waking up may happen slowly, indeed. So, I presume this is a valid use case.
>>
>> Now, I have few question (if my I3C understanding is right):
>>
>> I noticed none of the I3C drivers are taking care of the use case where the
>> bus is fully populated after resume (and we are after a resume with power
>> lost, for both the controller and the devices). That looks a bit tricky
>> scenario to cover, to be honest, as all the drivers check for a free slot in
>> ->attach_i3c_dev(), and, for a fully populated bus, that will not update the
>> newly assigned addresses in the subsystem data structure.
>>
>> If the ->attach_i3c_dev() called though the i3c_master_add_i3c_dev_locked()
>> fails then nothing is continued so, the device address changes are not
>> propagated in all the software data structures.
>>
>> In case we re-use the DATBAS() register values as proposed in this patch, we
>> have the changes that the driver software data caches (i3c->addrs[].addr)
>> and the subsystem I3C devices addresses to match. But, that may not be true
>> all the time.
>>
>> If we re-assign new addresses to i3c->addrs[].addr in the DAA API, then
>> write those values to DATBAS() registers, but the bus is fully populated, or
>> no new devices are discovered as the indices remains the same, then, since
>> we execute i3c_master_add_i3c_dev_locked() only for the newly attached
>> devices, then the subsystem and the driver addresses don't match anymore. I
>> couldn't found a global API similar to i3c_master_add_i3c_dev_locked() to
>> work for removing devices and re-attaching at resume, for such scenario. I'm
>> not sure that's good to do, though. If we call
>> i3c_master_add_i3c_dev_locked() unconditionally, then it will still not work
>> on a full previously occupied bus.
>>
>> If I'm not wrong with all these, could you please let me know how would you
>> consider covering this scenario? This is what I've tried to address with the
>> approach in this patch. I currently don't have a testing setup for this, I
>> only simulated it by setting i3c->free_pos = 0 before calling
>> i3c_master_do_daa_ext().
>>
>> Would the usage of i3c_device_do_setdasa() being called from a master driver
>> be something acceptable? Though, I currently haven't played around with it.
>>
>> As I don't have a real setup to test this, would it be OK to restore the
>> approach in this patch as proposed in v1?
> This case is quite complex, and many people try to resolve simialar
> problems, you may want to reattach device because controller lost state.
> 
> hub have similar requirement, which need reattach devices.
> 
> https://lore.kernel.org/linux-i3c/20260525064209.2263045-1- 
> lakshay.piplani@nxp.com/T/#ma99fa92cb3aac770995350e0fc22c144b974a038
> 
> controller lost state, but may i3c devices still alive and they dynamtic
> address during suspend. Does reattach to the old address help your case?
Yes, re-attaching works and I also need to update the subsystem data structures. 
Something like the following works for me:

diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index cd7f33250b7c..494703a87a18 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -252,6 +252,7 @@ struct renesas_i3c_xferqueue {
  };

  struct renesas_i3c_addr {
+       struct i3c_dev_desc *dev_desc;
         bool is_i2c;
         u8 addr;
  };
@@ -771,15 +772,27 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
                 newdevs = 0;
         } else {
                 newdevs = GENMASK(i3c->maxdevs - cmd->rx_count - 1, 0);
-               newdevs &= ~olddevs;
+               if (!i3c->resuming)
+                       newdevs &= ~olddevs;
         }

         for (pos = 0; pos < i3c->maxdevs; pos++) {
-               if (newdevs & BIT(pos))
-                       i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos].addr);
+               if (newdevs & BIT(pos)) {
+                       if (i3c->resuming && i3c->addrs[pos].dev_desc) {
+                               struct i3c_dev_desc *dev = 
i3c->addrs[pos].dev_desc->dev->desc;
+                               u8 old_dyn_addr;
+
+                               old_dyn_addr = dev->info.dyn_addr;
+                               dev->info.dyn_addr = i3c->addrs[pos].addr;
+
+                               i3c_master_reattach_i3c_dev_locked(dev, 
old_dyn_addr);
+                       } else
+                               i3c_master_add_i3c_dev_locked(m, 
i3c->addrs[pos].addr);
+               }
         }

         return 0;
@@ -997,6 +1010,7 @@ static int renesas_i3c_attach_i3c_dev(struct i3c_dev_desc *dev)

         data->index = pos;
         i3c->addrs[pos].addr = dev->info.dyn_addr ? : dev->info.static_addr;
+       i3c->addrs[pos].dev_desc = dev;
         i3c->free_pos &= ~BIT(pos);

         renesas_writel(i3c->regs, DATBAS(pos), 
DATBAS_DVSTAD(dev->info.static_addr) |
@@ -1060,6 +1074,7 @@ static void renesas_i3c_detach_i3c_dev(struct i3c_dev_desc 
*dev)

         i3c_dev_set_master_data(dev, NULL);
         i3c->addrs[data->index].addr = 0;
+       i3c->addrs[data->index].dev_desc = NULL;
         i3c->free_pos |= BIT(data->index);
         kfree(data);

To me, this looks OK but I don't think it is yet completed. If I'm not wrong, 
even with this adjustment the problem may still persist when running DAA on a 
full ocupied bus at runtime (e.g. after devices are removed/inserted). This 
driver don't support hotplug but I noticed the ones that supports it do DAA on 
hotplug events.

Could you please let me know what's the procedure to go forward with this 
series? The approach proposed in the above diff depends on the series exporting 
i3c_master_reattach_i3c_dev_locked(), which is in progress.

If all good with the rest of the patches in this series, as I don't have a real 
setup to test this, would it be OK to switch this patch as it was in v1 and 
return with the adjustments in the above diff once the 
i3c_master_reattach_i3c_dev_locked() is integrated?

-- 
Thank you,
Claudiu

-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

* Re: [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment on resume
  2026-06-04 13:04         ` Claudiu Beznea
@ 2026-06-04 18:49           ` Frank Li
  0 siblings, 0 replies; 25+ messages in thread
From: Frank Li @ 2026-06-04 18:49 UTC (permalink / raw)
  To: Claudiu Beznea, alexandre.belloni
  Cc: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, p.zabel,
	claudiu.beznea, linux-i3c, linux-kernel, Claudiu Beznea, stable

On Thu, Jun 04, 2026 at 04:04:52PM +0300, Claudiu Beznea wrote:
> Hi, Frank,
>
> On 6/3/26 22:26, Frank Li wrote:
> > On Wed, Jun 03, 2026 at 05:23:06PM +0300, Claudiu Beznea wrote:
> > > Hi, Frank, I3C maintainers,
> > >
...
> > >
> > > As I don't have a real setup to test this, would it be OK to restore the
> > > approach in this patch as proposed in v1?
> > This case is quite complex, and many people try to resolve simialar
> > problems, you may want to reattach device because controller lost state.
> >
> > hub have similar requirement, which need reattach devices.
> >
> > https://lore.kernel.org/linux-i3c/20260525064209.2263045-1-
> > lakshay.piplani@nxp.com/T/#ma99fa92cb3aac770995350e0fc22c144b974a038
> >
> > controller lost state, but may i3c devices still alive and they dynamtic
> > address during suspend. Does reattach to the old address help your case?
> Yes, re-attaching works and I also need to update the subsystem data
> structures. Something like the following works for me:
>
...
> +                               old_dyn_addr = dev->info.dyn_addr;
> +                               dev->info.dyn_addr = i3c->addrs[pos].addr;
> +
> +                               i3c_master_reattach_i3c_dev_locked(dev,
> old_dyn_addr);
...
>
> To me, this looks OK but I don't think it is yet completed. If I'm not
> wrong, even with this adjustment the problem may still persist when running
> DAA on a full ocupied bus at runtime (e.g. after devices are
> removed/inserted). This driver don't support hotplug but I noticed the ones
> that supports it do DAA on hotplug events.
>
> Could you please let me know what's the procedure to go forward with this
> series? The approach proposed in the above diff depends on the series
> exporting i3c_master_reattach_i3c_dev_locked(), which is in progress.

Two patch already was acked by me. I supposed alex will pick my acked before
your patch, you can send out update and cover later said depend on first two
patches of hubs.

Recently there are more people involve i3c work and create some cross
dependency.

Alex:
	Do you expect me to temp land these patches to one branch in
git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git? so you can double
check before send pull-request to linus?

Frank

>
> If all good with the rest of the patches in this series, as I don't have a
> real setup to test this, would it be OK to switch this patch as it was in v1
> and return with the adjustments in the above diff once the
> i3c_master_reattach_i3c_dev_locked() is integrated?
>
> --
> Thank you,
> Claudiu

-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

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

end of thread, other threads:[~2026-06-04 18:49 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-02 13:28 [PATCH v2 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 02/17] i3c: renesas: Restore STDBR and EXTBR registers on resume Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 03/17] i3c: renesas: Follow the reset deassert order used in probe Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach Claudiu Beznea
2026-06-02 20:05   ` Frank Li
2026-06-02 13:28 ` [PATCH v2 05/17] i3c: renesas: Reset the controller on resume Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 06/17] i3c: renesas: Perform Dynamic Address Assignment " Claudiu Beznea
2026-06-02 20:12   ` Frank Li
2026-06-03 14:23     ` Claudiu Beznea
2026-06-03 19:26       ` Frank Li
2026-06-04 13:04         ` Claudiu Beznea
2026-06-04 18:49           ` Frank Li
2026-06-02 13:28 ` [PATCH v2 07/17] i3c: renesas: Do not attach devices if xfer failed Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 08/17] i3c: renesas: Clean DATBAS register on detach Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}() Claudiu Beznea
2026-06-02 15:09   ` Philipp Zabel
2026-06-02 13:28 ` [PATCH v2 10/17] i3c: renesas: Return immediately if there is no transfer Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 11/17] i3c: renesas: Follow a unified pattern for transfer and command initialization Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 12/17] i3c: renesas: Drop the explicit memset() call Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 13/17] i3c: renesas: Update HW registers after SW computations are done Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 14/17] i3c: renesas: Organize structures to avoid unnecessary padding Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 16/17] i3c: renesas: Drop unnecessary tab Claudiu Beznea
2026-06-02 13:28 ` [PATCH v2 17/17] i3c: renesas: Add runtime PM support Claudiu Beznea

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