* [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM
@ 2026-07-13 13:05 Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
` (17 more replies)
0 siblings, 18 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- in patch 1 introduced renesas_i3c_irqs_mask_and_clear_locked()
similar to what was present in v4 in patch
"i3c: renesas: Add runtime PM support" but without locking; use the
same function to mask all the interrupts and cleanup the status
flag in case interrupts are triggered after the transfer completion
timed out
- introduce patch "i3c: renesas: Fix out-of-bounds access for newdevs mask"
to avoid failures when there are no I3C devices connected on the
bus at probe
- patch "i3c: renesas: Perform Dynamic Address Assignment on resume"
was restored to the v1 variant; kept it simple to fix the
suspend/resume for the moment
Changes in v4:
- dropped patch "i3c: renesas: Do not attach devices if xfer failed"
- fixed the swap in renesas_i3c_group_devs_in_slots() for i3c->addr[]
renesas_i3c_irqs_mask_and_clear();
- in patch 16/16 renamed renesas_i3c_abort_xfer() from v3 to
Changes in v3:
- re-based on top of series [1] to be able to use
i3c_master_reattach_i3c_dev_locked()
- used i3c_master_reattach_i3c_dev_locked() on patch
"i3c: renesas: Perform Dynamic Address Assignment on resume" along with
grouping the I2C and I3C devices in the driver slot
- collected tags
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: Clean DATBAS register on detach
i3c: renesas: Fix out-of-bounds access for newdevs mask
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 | 375 +++++++++++++++++++++----------
1 file changed, 261 insertions(+), 114 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v5 01/17] i3c: renesas: Check that the transfer is valid before accessing it
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 16:51 ` Frank Li
2026-07-13 13:05 ` [PATCH v5 02/17] i3c: renesas: Restore STDBR and EXTBR registers on resume Claudiu Beznea
` (16 subsequent siblings)
17 siblings, 1 reply; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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. With it clear any status flags and disable all
the interrupts to avoid triggering the same interrupts again.
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 v5:
- introduced renesas_i3c_irqs_mask_and_clear_locked() that keeps
unified the IRQ mask and clean path
- updated the patch description
Changes in v4:
- disable also the interrupts
- dropped the Rb tag
Changes in v3:
- none
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 | 52 +++++++++++++++++++++++++++-----
1 file changed, 45 insertions(+), 7 deletions(-)
diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index f39c449922ca..38b8428f464c 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -433,6 +433,21 @@ static void renesas_i3c_enqueue_xfer(struct renesas_i3c *i3c, struct renesas_i3c
}
}
+static void renesas_i3c_irqs_mask_and_clear_locked(struct renesas_i3c *i3c)
+{
+ /* Disable all the interrupts. */
+ renesas_writel(i3c->regs, BIE, 0);
+ renesas_writel(i3c->regs, NTIE, 0);
+
+ /* Clear normal transfer status flags. */
+ renesas_writel(i3c->regs, NTST, 0);
+
+ /* Clear bus status flags. */
+ renesas_writel(i3c->regs, BST, 0);
+ /* Read back registers to confirm writes have fully propagated. */
+ renesas_readl(i3c->regs, BST);
+}
+
static void renesas_i3c_wait_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer)
{
unsigned long time_left;
@@ -1014,6 +1029,11 @@ static irqreturn_t renesas_i3c_tx_isr(int irq, void *data)
scoped_guard(spinlock, &i3c->xferqueue.lock) {
xfer = i3c->xferqueue.cur;
+ if (!xfer) {
+ renesas_i3c_irqs_mask_and_clear_locked(i3c);
+ return IRQ_HANDLED;
+ }
+
cmd = xfer->cmds;
if (xfer->is_i2c_xfer) {
@@ -1054,6 +1074,11 @@ static irqreturn_t renesas_i3c_resp_isr(int irq, void *data)
scoped_guard(spinlock, &i3c->xferqueue.lock) {
xfer = i3c->xferqueue.cur;
+ if (!xfer) {
+ renesas_i3c_irqs_mask_and_clear_locked(i3c);
+ return IRQ_HANDLED;
+ }
+
cmd = xfer->cmds;
/* Clear the Respone Queue Full status flag*/
@@ -1138,6 +1163,11 @@ static irqreturn_t renesas_i3c_tend_isr(int irq, void *data)
scoped_guard(spinlock, &i3c->xferqueue.lock) {
xfer = i3c->xferqueue.cur;
+ if (!xfer) {
+ renesas_i3c_irqs_mask_and_clear_locked(i3c);
+ return IRQ_HANDLED;
+ }
+
cmd = xfer->cmds;
if (xfer->is_i2c_xfer) {
@@ -1184,6 +1214,11 @@ static irqreturn_t renesas_i3c_rx_isr(int irq, void *data)
scoped_guard(spinlock, &i3c->xferqueue.lock) {
xfer = i3c->xferqueue.cur;
+ if (!xfer) {
+ renesas_i3c_irqs_mask_and_clear_locked(i3c);
+ return IRQ_HANDLED;
+ }
+
cmd = xfer->cmds;
if (xfer->is_i2c_xfer) {
@@ -1234,15 +1269,13 @@ static irqreturn_t renesas_i3c_stop_isr(int irq, void *data)
struct renesas_i3c_xfer *xfer;
scoped_guard(spinlock, &i3c->xferqueue.lock) {
- xfer = i3c->xferqueue.cur;
-
- /* read back registers to confirm writes have fully propagated */
- renesas_writel(i3c->regs, BST, 0);
- renesas_readl(i3c->regs, BST);
- renesas_writel(i3c->regs, BIE, 0);
- renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0 | NTST_RDBFF0);
+ renesas_i3c_irqs_mask_and_clear_locked(i3c);
renesas_clear_bit(i3c->regs, SCSTRCTL, SCSTRCTL_RWE);
+ xfer = i3c->xferqueue.cur;
+ if (!xfer)
+ return IRQ_HANDLED;
+
xfer->ret = 0;
complete(&xfer->comp);
}
@@ -1259,6 +1292,11 @@ static irqreturn_t renesas_i3c_start_isr(int irq, void *data)
scoped_guard(spinlock, &i3c->xferqueue.lock) {
xfer = i3c->xferqueue.cur;
+ if (!xfer) {
+ renesas_i3c_irqs_mask_and_clear_locked(i3c);
+ return IRQ_HANDLED;
+ }
+
cmd = xfer->cmds;
if (xfer->is_i2c_xfer) {
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 02/17] i3c: renesas: Restore STDBR and EXTBR registers on resume
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 03/17] i3c: renesas: Follow the reset deassert order used in probe Claudiu Beznea
` (15 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 38b8428f464c..cd9928649c7f 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;
@@ -622,10 +623,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 03/17] i3c: renesas: Follow the reset deassert order used in probe
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 02/17] i3c: renesas: Restore STDBR and EXTBR registers on resume Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach Claudiu Beznea
` (14 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 cd9928649c7f..ccf55afcdedc 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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (2 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 03/17] i3c: renesas: Follow the reset deassert order used in probe Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 05/17] i3c: renesas: Reset the controller on resume Claudiu Beznea
` (13 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
Changes in v5:
- none
Changes in v4:
- use "data->index > pos" condition
Changes in v3:
- collected tags
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 ccf55afcdedc..517ac2df9bd4 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -907,10 +907,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 05/17] i3c: renesas: Reset the controller on resume
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (3 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 06/17] i3c: renesas: Perform Dynamic Address Assignment " Claudiu Beznea
` (12 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- collected tags
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 517ac2df9bd4..6590da962592 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -495,8 +495,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 06/17] i3c: renesas: Perform Dynamic Address Assignment on resume
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (4 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 05/17] i3c: renesas: Reset the controller on resume Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 07/17] i3c: renesas: Clean DATBAS register on detach Claudiu Beznea
` (11 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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().
Along with this, struct renesas_i3c::DATBASn and its usage were removed,
as they are no longer needed.
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 v5:
- restore it to the level of v1; the other scenarios updated by
sashiko were already present w/ and w/o this patch and could be
addressed incrementally
- updated the patch description
Changes in v4:
- used directly i3c_dev instead of i3c_dev->dev->desc
- fixed the swap in renesas_i3c_group_devs_in_slots() for i3c->addr[]
Changes in v3:
- added renesas_i3c_group_devs_in_slots(); along with it, the
struct renesas_i3c_addr was updated with i3c_dev and i3c_dev
and the attach/detach/re-attach APIs were adjusted accordingly
- dropped DATBASn member of struct renesas_i3c
- used i3c_master_reattach_i3c_dev_locked() to re-attach devices
on a fully occupied bus
- in resume, moved i2c_mark_adapter_resumed() after i3c_master_do_daa_ext()
since it can update the internal driver data structure i2c specific
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 | 38 +++++++++++++-------------------
1 file changed, 15 insertions(+), 23 deletions(-)
diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 6590da962592..acc30ed615ab 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -265,7 +265,6 @@ struct renesas_i3c {
u8 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;
@@ -495,8 +494,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)
@@ -1419,12 +1418,6 @@ static int renesas_i3c_probe(struct platform_device *pdev)
i3c->maxdevs = RENESAS_I3C_MAX_DEVS;
i3c->free_pos = GENMASK(i3c->maxdevs - 1, 0);
- /* Allocate dynamic Device Address Table backup. */
- i3c->DATBASn = devm_kzalloc(&pdev->dev, sizeof(u32) * i3c->maxdevs,
- GFP_KERNEL);
- if (!i3c->DATBASn)
- return -ENOMEM;
-
return i3c_master_register(&i3c->base, &pdev->dev, &renesas_i3c_ops, false);
}
@@ -1435,17 +1428,13 @@ 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;
+ int ret;
i2c_mark_adapter_suspended(&i3c->base.i2c);
- /* Store Device Address Table values. */
- for (i = 0; i < i3c->maxdevs; i++)
- i3c->DATBASn[i] = renesas_readl(i3c->regs, DATBAS(i));
-
ret = reset_control_assert(i3c->presetn);
if (ret)
goto err_mark_resumed;
@@ -1466,10 +1455,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 +1484,19 @@ 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);
+ ret = i3c_master_do_daa_ext(&i3c->base, true);
+ if (ret)
+ dev_err(dev, "DAA failed on resume, ret=%d", ret);
+
i2c_mark_adapter_resumed(&i3c->base.i2c);
+ /*
+ * 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 +1509,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 07/17] i3c: renesas: Clean DATBAS register on detach
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (5 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 06/17] i3c: renesas: Perform Dynamic Address Assignment " Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 08/17] i3c: renesas: Fix out-of-bounds access for newdevs mask Claudiu Beznea
` (10 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 acc30ed615ab..b9784d238f61 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -935,6 +935,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] = 0;
i3c->free_pos |= BIT(data->index);
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 08/17] i3c: renesas: Fix out-of-bounds access for newdevs mask
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (6 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 07/17] i3c: renesas: Clean DATBAS register on detach Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 17:01 ` Frank Li
2026-07-13 13:05 ` [PATCH v5 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}() Claudiu Beznea
` (9 subsequent siblings)
17 siblings, 1 reply; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
Claudiu Beznea, stable
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
When software initiates DAA (Dynamic Address Assignment), the controller
reports the result via the NRSPQP (Normal Response Queue Port Register).
The data length field of the response descriptor, which is accessible
through the NRSPQP register, indicates the number of devices remaining
after DAA. Consequently, when the bus is empty, this field contains the
maximum number of devices supported by the controller (8 for the Renesas
I3C controller).
Adjust the condition that computes the newly discovered devices bitmask
to prevent an out-of-bounds when the I3C bus is empty.
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 v5:
- none; this patch is new
drivers/i3c/master/renesas-i3c.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index b9784d238f61..c459e40fd5ff 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -703,7 +703,11 @@ 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);
+ if (cmd->rx_count >= i3c->maxdevs)
+ newdevs = 0;
+ else
+ newdevs = GENMASK(i3c->maxdevs - cmd->rx_count - 1, 0);
+
newdevs &= ~olddevs;
for (pos = 0; pos < i3c->maxdevs; pos++) {
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}()
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (7 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 08/17] i3c: renesas: Fix out-of-bounds access for newdevs mask Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 17:02 ` Frank Li
2026-07-13 13:05 ` [PATCH v5 10/17] i3c: renesas: Return immediately if there is no transfer Claudiu Beznea
` (8 subsequent siblings)
17 siblings, 1 reply; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 c459e40fd5ff..915090d0ad37 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -1437,24 +1437,22 @@ 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 ret;
i2c_mark_adapter_suspended(&i3c->base.i2c);
- 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);
@@ -1464,19 +1462,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)
@@ -1507,10 +1505,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 10/17] i3c: renesas: Return immediately if there is no transfer
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (8 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}() Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 11/17] i3c: renesas: Follow a unified pattern for transfer and command initialization Claudiu Beznea
` (7 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 915090d0ad37..9a3613220034 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -957,13 +957,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 11/17] i3c: renesas: Follow a unified pattern for transfer and command initialization
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (9 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 10/17] i3c: renesas: Return immediately if there is no transfer Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 12/17] i3c: renesas: Drop the explicit memset() call Claudiu Beznea
` (6 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 9a3613220034..c1396c49f45e 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -663,6 +663,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);
@@ -684,10 +688,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;
-
ret = renesas_i3c_get_free_pos(i3c);
if (ret < 0)
return ret;
@@ -779,13 +779,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:
@@ -835,15 +835,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;
@@ -964,12 +964,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 12/17] i3c: renesas: Drop the explicit memset() call
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (10 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 11/17] i3c: renesas: Follow a unified pattern for transfer and command initialization Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 13/17] i3c: renesas: Update HW registers after SW computations are done Claudiu Beznea
` (5 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 c1396c49f45e..52f09d966651 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -639,7 +639,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 13/17] i3c: renesas: Update HW registers after SW computations are done
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (11 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 12/17] i3c: renesas: Drop the explicit memset() call Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 14/17] i3c: renesas: Organize structures to avoid unnecessary padding Claudiu Beznea
` (4 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 52f09d966651..2cff7c6ae369 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -565,10 +565,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);
@@ -619,27 +615,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 14/17] i3c: renesas: Organize structures to avoid unnecessary padding
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (12 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 13/17] i3c: renesas: Update HW registers after SW computations are done Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name Claudiu Beznea
` (3 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
Changes in v2:
- collected tags
drivers/i3c/master/renesas-i3c.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 2cff7c6ae369..a54c20ef5f6e 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 {
@@ -253,21 +253,22 @@ struct renesas_i3c_xferqueue {
};
struct renesas_i3c {
+ void __iomem *regs;
+ struct clk_bulk_data *clks;
+ struct reset_control *presetn;
+ struct reset_control *tresetn;
+ struct renesas_i3c_xferqueue xferqueue;
struct i3c_master_controller base;
+ u8 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;
- u8 addrs[RENESAS_I3C_MAX_DEVS];
- struct renesas_i3c_xferqueue xferqueue;
- void __iomem *regs;
- struct clk_bulk_data *clks;
- struct reset_control *presetn;
- struct reset_control *tresetn;
+ u16 maxdevs;
u8 num_clks;
u8 refclk_div;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (13 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 14/17] i3c: renesas: Organize structures to avoid unnecessary padding Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 16/17] i3c: renesas: Drop unnecessary tab Claudiu Beznea
` (2 subsequent siblings)
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 a54c20ef5f6e..f28e260dd166 100644
--- a/drivers/i3c/master/renesas-i3c.c
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -1409,12 +1409,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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 16/17] i3c: renesas: Drop unnecessary tab
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (14 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 17/17] i3c: renesas: Add runtime PM support Claudiu Beznea
2026-07-13 17:26 ` [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Tommaso Merciai
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- none
Changes in v4:
- none
Changes in v3:
- none
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 f28e260dd166..378baac71aef 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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v5 17/17] i3c: renesas: Add runtime PM support
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (15 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 16/17] i3c: renesas: Drop unnecessary tab Claudiu Beznea
@ 2026-07-13 13:05 ` Claudiu Beznea
2026-07-13 17:26 ` [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Tommaso Merciai
17 siblings, 0 replies; 22+ messages in thread
From: Claudiu Beznea @ 2026-07-13 13:05 UTC (permalink / raw)
To: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel
Cc: claudiu.beznea, linux-i3c, linux-kernel, linux-renesas-soc,
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 v5:
- updated renesas_i3c_irqs_mask_and_clear() to use the
renesas_i3c_irqs_mask_and_clear_locked() introduced in patch 1 from
this series
Changes in v4:
- renamed renesas_i3c_abort_xfer() from v3 to
renesas_i3c_irqs_mask_and_clear(); along with it renamed local varibles
abort_xfer to xfer_failed
Changes in v3:
- dropped the RPM resume/suspend in renesas_i3c_suspend() to read the
DATBASn registers as the DATBASn register are not used on suspend/resume
path anymore in this version
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 | 140 ++++++++++++++++++++++++-------
1 file changed, 112 insertions(+), 28 deletions(-)
diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
index 378baac71aef..1975c599ca43 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,
@@ -254,9 +253,10 @@ struct renesas_i3c_xferqueue {
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;
struct renesas_i3c_xferqueue xferqueue;
struct i3c_master_controller base;
u8 addrs[RENESAS_I3C_MAX_DEVS];
@@ -269,7 +269,6 @@ struct renesas_i3c {
u32 i3c_STDBR;
u32 extbr;
u16 maxdevs;
- u8 num_clks;
u8 refclk_div;
};
@@ -449,7 +448,14 @@ static void renesas_i3c_irqs_mask_and_clear_locked(struct renesas_i3c *i3c)
renesas_readl(i3c->regs, BST);
}
-static void renesas_i3c_wait_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer)
+static void renesas_i3c_irqs_mask_and_clear(struct renesas_i3c *i3c)
+{
+ guard(spinlock_irqsave)(&i3c->xferqueue.lock);
+
+ renesas_i3c_irqs_mask_and_clear_locked(i3c);
+}
+
+static unsigned long renesas_i3c_wait_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer)
{
unsigned long time_left;
@@ -458,6 +464,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)
@@ -491,6 +499,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);
@@ -562,7 +576,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;
@@ -633,6 +647,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));
@@ -655,6 +674,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;
u32 olddevs, newdevs;
u8 last_addr = 0, pos;
int ret;
@@ -667,6 +687,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);
@@ -701,7 +726,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_irqs_mask_and_clear(i3c);
if (cmd->rx_count >= i3c->maxdevs)
newdevs = 0;
@@ -767,6 +794,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) {
@@ -784,6 +812,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. */
@@ -818,7 +851,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_irqs_mask_and_clear(i3c);
ret = xfer->ret;
if (ret)
@@ -833,7 +868,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 xfer_failed = false;
+ int i, ret;
struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
if (!xfer)
@@ -841,6 +878,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);
@@ -872,9 +914,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)
+ xfer_failed = true;
}
+ if (xfer_failed)
+ renesas_i3c_irqs_mask_and_clear(i3c);
+
return 0;
}
@@ -883,12 +930,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;
@@ -910,7 +962,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);
@@ -938,8 +995,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] = 0;
@@ -955,7 +1016,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 xfer_failed = false;
+ int i, ret;
if (!i2c_nxfers)
return 0;
@@ -968,6 +1031,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)) {
@@ -994,7 +1062,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)
+ xfer_failed = true;
if (cmd->err)
break;
@@ -1003,6 +1073,10 @@ static int renesas_i3c_i2c_xfers(struct i2c_dev_desc *dev,
}
renesas_i3c_dequeue_xfer(i3c, xfer);
+
+ if (xfer_failed)
+ renesas_i3c_irqs_mask_and_clear(i3c);
+
return cmd->err;
}
@@ -1384,12 +1458,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))
@@ -1456,8 +1534,6 @@ static int renesas_i3c_suspend(struct device *dev)
if (ret)
goto err_mark_resumed;
- clk_bulk_disable(i3c->num_clks, i3c->clks);
-
return 0;
err_mark_resumed:
@@ -1479,13 +1555,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);
@@ -1504,15 +1580,23 @@ static int renesas_i3c_resume(struct device *dev)
i2c_mark_adapter_resumed(&i3c->base.i2c);
+ 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
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH v5 01/17] i3c: renesas: Check that the transfer is valid before accessing it
2026-07-13 13:05 ` [PATCH v5 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
@ 2026-07-13 16:51 ` Frank Li
0 siblings, 0 replies; 22+ messages in thread
From: Frank Li @ 2026-07-13 16:51 UTC (permalink / raw)
To: Claudiu Beznea
Cc: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel, linux-i3c, linux-kernel, linux-renesas-soc,
Claudiu Beznea, stable
On Mon, Jul 13, 2026 at 04:05:29PM +0300, Claudiu Beznea wrote:
> 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. With it clear any status flags and disable all
> the interrupts to avoid triggering the same interrupts again.
>
> 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 v5:
> - introduced renesas_i3c_irqs_mask_and_clear_locked() that keeps
> unified the IRQ mask and clean path
> - updated the patch description
>
> Changes in v4:
> - disable also the interrupts
> - dropped the Rb tag
>
> Changes in v3:
> - none
>
> 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 | 52 +++++++++++++++++++++++++++-----
> 1 file changed, 45 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
> index f39c449922ca..38b8428f464c 100644
> --- a/drivers/i3c/master/renesas-i3c.c
> +++ b/drivers/i3c/master/renesas-i3c.c
> @@ -433,6 +433,21 @@ static void renesas_i3c_enqueue_xfer(struct renesas_i3c *i3c, struct renesas_i3c
> }
> }
>
> +static void renesas_i3c_irqs_mask_and_clear_locked(struct renesas_i3c *i3c)
> +{
> + /* Disable all the interrupts. */
> + renesas_writel(i3c->regs, BIE, 0);
> + renesas_writel(i3c->regs, NTIE, 0);
> +
> + /* Clear normal transfer status flags. */
> + renesas_writel(i3c->regs, NTST, 0);
> +
> + /* Clear bus status flags. */
> + renesas_writel(i3c->regs, BST, 0);
> + /* Read back registers to confirm writes have fully propagated. */
> + renesas_readl(i3c->regs, BST);
> +}
> +
> static void renesas_i3c_wait_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer)
> {
> unsigned long time_left;
> @@ -1014,6 +1029,11 @@ static irqreturn_t renesas_i3c_tx_isr(int irq, void *data)
>
> scoped_guard(spinlock, &i3c->xferqueue.lock) {
> xfer = i3c->xferqueue.cur;
> + if (!xfer) {
> + renesas_i3c_irqs_mask_and_clear_locked(i3c);
> + return IRQ_HANDLED;
> + }
> +
> cmd = xfer->cmds;
>
> if (xfer->is_i2c_xfer) {
> @@ -1054,6 +1074,11 @@ static irqreturn_t renesas_i3c_resp_isr(int irq, void *data)
>
> scoped_guard(spinlock, &i3c->xferqueue.lock) {
> xfer = i3c->xferqueue.cur;
> + if (!xfer) {
> + renesas_i3c_irqs_mask_and_clear_locked(i3c);
> + return IRQ_HANDLED;
> + }
> +
> cmd = xfer->cmds;
>
> /* Clear the Respone Queue Full status flag*/
> @@ -1138,6 +1163,11 @@ static irqreturn_t renesas_i3c_tend_isr(int irq, void *data)
>
> scoped_guard(spinlock, &i3c->xferqueue.lock) {
> xfer = i3c->xferqueue.cur;
> + if (!xfer) {
> + renesas_i3c_irqs_mask_and_clear_locked(i3c);
> + return IRQ_HANDLED;
> + }
> +
> cmd = xfer->cmds;
>
> if (xfer->is_i2c_xfer) {
> @@ -1184,6 +1214,11 @@ static irqreturn_t renesas_i3c_rx_isr(int irq, void *data)
>
> scoped_guard(spinlock, &i3c->xferqueue.lock) {
> xfer = i3c->xferqueue.cur;
> + if (!xfer) {
> + renesas_i3c_irqs_mask_and_clear_locked(i3c);
> + return IRQ_HANDLED;
> + }
> +
> cmd = xfer->cmds;
>
> if (xfer->is_i2c_xfer) {
> @@ -1234,15 +1269,13 @@ static irqreturn_t renesas_i3c_stop_isr(int irq, void *data)
> struct renesas_i3c_xfer *xfer;
>
> scoped_guard(spinlock, &i3c->xferqueue.lock) {
> - xfer = i3c->xferqueue.cur;
> -
> - /* read back registers to confirm writes have fully propagated */
> - renesas_writel(i3c->regs, BST, 0);
> - renesas_readl(i3c->regs, BST);
> - renesas_writel(i3c->regs, BIE, 0);
> - renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0 | NTST_RDBFF0);
> + renesas_i3c_irqs_mask_and_clear_locked(i3c);
> renesas_clear_bit(i3c->regs, SCSTRCTL, SCSTRCTL_RWE);
>
> + xfer = i3c->xferqueue.cur;
> + if (!xfer)
> + return IRQ_HANDLED;
> +
> xfer->ret = 0;
> complete(&xfer->comp);
> }
> @@ -1259,6 +1292,11 @@ static irqreturn_t renesas_i3c_start_isr(int irq, void *data)
>
> scoped_guard(spinlock, &i3c->xferqueue.lock) {
> xfer = i3c->xferqueue.cur;
> + if (!xfer) {
> + renesas_i3c_irqs_mask_and_clear_locked(i3c);
> + return IRQ_HANDLED;
> + }
> +
> cmd = xfer->cmds;
>
> if (xfer->is_i2c_xfer) {
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v5 08/17] i3c: renesas: Fix out-of-bounds access for newdevs mask
2026-07-13 13:05 ` [PATCH v5 08/17] i3c: renesas: Fix out-of-bounds access for newdevs mask Claudiu Beznea
@ 2026-07-13 17:01 ` Frank Li
0 siblings, 0 replies; 22+ messages in thread
From: Frank Li @ 2026-07-13 17:01 UTC (permalink / raw)
To: Claudiu Beznea
Cc: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel, linux-i3c, linux-kernel, linux-renesas-soc,
Claudiu Beznea, stable
On Mon, Jul 13, 2026 at 04:05:36PM +0300, Claudiu Beznea wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> When software initiates DAA (Dynamic Address Assignment), the controller
> reports the result via the NRSPQP (Normal Response Queue Port Register).
> The data length field of the response descriptor, which is accessible
> through the NRSPQP register, indicates the number of devices remaining
> after DAA. Consequently, when the bus is empty, this field contains the
> maximum number of devices supported by the controller (8 for the Renesas
> I3C controller).
>
> Adjust the condition that computes the newly discovered devices bitmask
> to prevent an out-of-bounds when the I3C bus is empty.
>
> Fixes: e7218986319b ("i3c: renesas: Add suspend/resume support")
> 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 v5:
> - none; this patch is new
>
> drivers/i3c/master/renesas-i3c.c | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
> index b9784d238f61..c459e40fd5ff 100644
> --- a/drivers/i3c/master/renesas-i3c.c
> +++ b/drivers/i3c/master/renesas-i3c.c
> @@ -703,7 +703,11 @@ 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);
> + if (cmd->rx_count >= i3c->maxdevs)
> + newdevs = 0;
> + else
> + newdevs = GENMASK(i3c->maxdevs - cmd->rx_count - 1, 0);
> +
> newdevs &= ~olddevs;
>
> for (pos = 0; pos < i3c->maxdevs; pos++) {
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v5 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}()
2026-07-13 13:05 ` [PATCH v5 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}() Claudiu Beznea
@ 2026-07-13 17:02 ` Frank Li
0 siblings, 0 replies; 22+ messages in thread
From: Frank Li @ 2026-07-13 17:02 UTC (permalink / raw)
To: Claudiu Beznea
Cc: wsa+renesas, tommaso.merciai.xr, alexandre.belloni, Frank.Li,
p.zabel, linux-i3c, linux-kernel, linux-renesas-soc,
Claudiu Beznea
On Mon, Jul 13, 2026 at 04:05:37PM +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.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
>
> Changes in v5:
> - none
>
> Changes in v4:
> - none
>
> Changes in v3:
> - none
>
> 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 c459e40fd5ff..915090d0ad37 100644
> --- a/drivers/i3c/master/renesas-i3c.c
> +++ b/drivers/i3c/master/renesas-i3c.c
> @@ -1437,24 +1437,22 @@ 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 ret;
>
> i2c_mark_adapter_suspended(&i3c->base.i2c);
>
> - 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);
>
> @@ -1464,19 +1462,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)
> @@ -1507,10 +1505,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
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
` (16 preceding siblings ...)
2026-07-13 13:05 ` [PATCH v5 17/17] i3c: renesas: Add runtime PM support Claudiu Beznea
@ 2026-07-13 17:26 ` Tommaso Merciai
17 siblings, 0 replies; 22+ messages in thread
From: Tommaso Merciai @ 2026-07-13 17:26 UTC (permalink / raw)
To: Claudiu Beznea
Cc: wsa+renesas, alexandre.belloni, Frank.Li, p.zabel, linux-i3c,
linux-kernel, linux-renesas-soc, Claudiu Beznea
Hi Claudiu,
Thanks for your patch.
On Mon, Jul 13, 2026 at 04:05:28PM +0300, Claudiu Beznea wrote:
> 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 v5:
> - in patch 1 introduced renesas_i3c_irqs_mask_and_clear_locked()
> similar to what was present in v4 in patch
> "i3c: renesas: Add runtime PM support" but without locking; use the
> same function to mask all the interrupts and cleanup the status
> flag in case interrupts are triggered after the transfer completion
> timed out
> - introduce patch "i3c: renesas: Fix out-of-bounds access for newdevs mask"
> to avoid failures when there are no I3C devices connected on the
> bus at probe
> - patch "i3c: renesas: Perform Dynamic Address Assignment on resume"
> was restored to the v1 variant; kept it simple to fix the
> suspend/resume for the moment
Tested on RZ/G3E SMARC CARRIER II + RZ SMARC BREAKOUT board with one
P3T1085UK-ARD board connected.
Tested-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
Kind Regards,
Tommaso
>
> Changes in v4:
> - dropped patch "i3c: renesas: Do not attach devices if xfer failed"
> - fixed the swap in renesas_i3c_group_devs_in_slots() for i3c->addr[]
> renesas_i3c_irqs_mask_and_clear();
> - in patch 16/16 renamed renesas_i3c_abort_xfer() from v3 to
>
> Changes in v3:
> - re-based on top of series [1] to be able to use
> i3c_master_reattach_i3c_dev_locked()
> - used i3c_master_reattach_i3c_dev_locked() on patch
> "i3c: renesas: Perform Dynamic Address Assignment on resume" along with
> grouping the I2C and I3C devices in the driver slot
> - collected tags
>
> 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: Clean DATBAS register on detach
> i3c: renesas: Fix out-of-bounds access for newdevs mask
> 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 | 375 +++++++++++++++++++++----------
> 1 file changed, 261 insertions(+), 114 deletions(-)
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2026-07-13 17:26 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-13 13:05 [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
2026-07-13 16:51 ` Frank Li
2026-07-13 13:05 ` [PATCH v5 02/17] i3c: renesas: Restore STDBR and EXTBR registers on resume Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 03/17] i3c: renesas: Follow the reset deassert order used in probe Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 05/17] i3c: renesas: Reset the controller on resume Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 06/17] i3c: renesas: Perform Dynamic Address Assignment " Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 07/17] i3c: renesas: Clean DATBAS register on detach Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 08/17] i3c: renesas: Fix out-of-bounds access for newdevs mask Claudiu Beznea
2026-07-13 17:01 ` Frank Li
2026-07-13 13:05 ` [PATCH v5 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}() Claudiu Beznea
2026-07-13 17:02 ` Frank Li
2026-07-13 13:05 ` [PATCH v5 10/17] i3c: renesas: Return immediately if there is no transfer Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 11/17] i3c: renesas: Follow a unified pattern for transfer and command initialization Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 12/17] i3c: renesas: Drop the explicit memset() call Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 13/17] i3c: renesas: Update HW registers after SW computations are done Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 14/17] i3c: renesas: Organize structures to avoid unnecessary padding Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 16/17] i3c: renesas: Drop unnecessary tab Claudiu Beznea
2026-07-13 13:05 ` [PATCH v5 17/17] i3c: renesas: Add runtime PM support Claudiu Beznea
2026-07-13 17:26 ` [PATCH v5 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Tommaso Merciai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox