mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
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.
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: e721898631 ("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>
Tested-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
Link: https://patch.msgid.link/20260713130545.568657-7-claudiu.beznea+renesas@tuxon.dev
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
parent
27cf0ad162
commit
fbf26154c4
|
|
@ -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)
|
||||
|
|
@ -1427,12 +1426,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);
|
||||
}
|
||||
|
||||
|
|
@ -1443,17 +1436,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;
|
||||
|
|
@ -1474,10 +1463,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)
|
||||
|
|
@ -1503,15 +1492,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:
|
||||
|
|
@ -1524,8 +1517,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[] = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user