Skip to content

Commit 05be23e

Browse files
wangxiaoningnxpalexandrebelloni
authored andcommitted
i3c: master: svc: add runtime pm support
Add runtime pm support to dynamically manage the clock. Signed-off-by: Clark Wang <[email protected]> Reviewed-by: Miquel Raynal <[email protected]> Reviewed-by: Jun Li <[email protected]> Signed-off-by: Alexandre Belloni <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 173fcb2 commit 05be23e

File tree

1 file changed

+156
-40
lines changed

1 file changed

+156
-40
lines changed

drivers/i3c/master/svc-i3c-master.c

Lines changed: 156 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include <linux/list.h>
1818
#include <linux/module.h>
1919
#include <linux/of.h>
20+
#include <linux/pinctrl/consumer.h>
2021
#include <linux/platform_device.h>
22+
#include <linux/pm_runtime.h>
2123

2224
/* Master Mode Registers */
2325
#define SVC_I3C_MCONFIG 0x000
@@ -119,6 +121,7 @@
119121
#define SVC_MDYNADDR_ADDR(x) FIELD_PREP(GENMASK(7, 1), (x))
120122

121123
#define SVC_I3C_MAX_DEVS 32
124+
#define SVC_I3C_PM_TIMEOUT_MS 1000
122125

123126
/* This parameter depends on the implementation and may be tuned */
124127
#define SVC_I3C_FIFO_SIZE 16
@@ -480,10 +483,20 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
480483
u32 ppbaud, pplow, odhpp, odbaud, odstop, i2cbaud, reg;
481484
int ret;
482485

486+
ret = pm_runtime_resume_and_get(master->dev);
487+
if (ret < 0) {
488+
dev_err(master->dev,
489+
"<%s> cannot resume i3c bus master, err: %d\n",
490+
__func__, ret);
491+
return ret;
492+
}
493+
483494
/* Timings derivation */
484495
fclk_rate = clk_get_rate(master->fclk);
485-
if (!fclk_rate)
486-
return -EINVAL;
496+
if (!fclk_rate) {
497+
ret = -EINVAL;
498+
goto rpm_out;
499+
}
487500

488501
fclk_period_ns = DIV_ROUND_UP(1000000000, fclk_rate);
489502

@@ -527,7 +540,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
527540
odstop = 1;
528541
break;
529542
default:
530-
return -EINVAL;
543+
goto rpm_out;
531544
}
532545

533546
reg = SVC_I3C_MCONFIG_MASTER_EN |
@@ -545,7 +558,7 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
545558
/* Master core's registration */
546559
ret = i3c_master_get_free_addr(m, 0);
547560
if (ret < 0)
548-
return ret;
561+
goto rpm_out;
549562

550563
info.dyn_addr = ret;
551564

@@ -554,21 +567,35 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
554567

555568
ret = i3c_master_set_info(&master->base, &info);
556569
if (ret)
557-
return ret;
570+
goto rpm_out;
558571

559572
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
560573

561-
return 0;
574+
rpm_out:
575+
pm_runtime_mark_last_busy(master->dev);
576+
pm_runtime_put_autosuspend(master->dev);
577+
578+
return ret;
562579
}
563580

564581
static void svc_i3c_master_bus_cleanup(struct i3c_master_controller *m)
565582
{
566583
struct svc_i3c_master *master = to_svc_i3c_master(m);
584+
int ret;
585+
586+
ret = pm_runtime_resume_and_get(master->dev);
587+
if (ret < 0) {
588+
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
589+
return;
590+
}
567591

568592
svc_i3c_master_disable_interrupts(master);
569593

570594
/* Disable master */
571595
writel(0, master->regs + SVC_I3C_MCONFIG);
596+
597+
pm_runtime_mark_last_busy(master->dev);
598+
pm_runtime_put_autosuspend(master->dev);
572599
}
573600

574601
static int svc_i3c_master_reserve_slot(struct svc_i3c_master *master)
@@ -867,31 +894,36 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
867894
unsigned int dev_nb;
868895
int ret, i;
869896

897+
ret = pm_runtime_resume_and_get(master->dev);
898+
if (ret < 0) {
899+
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
900+
return ret;
901+
}
902+
870903
spin_lock_irqsave(&master->xferqueue.lock, flags);
871904
ret = svc_i3c_master_do_daa_locked(master, addrs, &dev_nb);
872905
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
873-
if (ret)
874-
goto emit_stop;
906+
if (ret) {
907+
svc_i3c_master_emit_stop(master);
908+
svc_i3c_master_clear_merrwarn(master);
909+
goto rpm_out;
910+
}
875911

876912
/* Register all devices who participated to the core */
877913
for (i = 0; i < dev_nb; i++) {
878914
ret = i3c_master_add_i3c_dev_locked(m, addrs[i]);
879915
if (ret)
880-
return ret;
916+
goto rpm_out;
881917
}
882918

883919
/* Configure IBI auto-rules */
884920
ret = svc_i3c_update_ibirules(master);
885-
if (ret) {
921+
if (ret)
886922
dev_err(master->dev, "Cannot handle such a list of devices");
887-
return ret;
888-
}
889-
890-
return 0;
891923

892-
emit_stop:
893-
svc_i3c_master_emit_stop(master);
894-
svc_i3c_master_clear_merrwarn(master);
924+
rpm_out:
925+
pm_runtime_mark_last_busy(master->dev);
926+
pm_runtime_put_autosuspend(master->dev);
895927

896928
return ret;
897929
}
@@ -1060,6 +1092,12 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
10601092
if (!xfer)
10611093
return;
10621094

1095+
ret = pm_runtime_resume_and_get(master->dev);
1096+
if (ret < 0) {
1097+
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
1098+
return;
1099+
}
1100+
10631101
svc_i3c_master_clear_merrwarn(master);
10641102
svc_i3c_master_flush_fifo(master);
10651103

@@ -1074,6 +1112,9 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
10741112
break;
10751113
}
10761114

1115+
pm_runtime_mark_last_busy(master->dev);
1116+
pm_runtime_put_autosuspend(master->dev);
1117+
10771118
xfer->ret = ret;
10781119
complete(&xfer->comp);
10791120

@@ -1350,15 +1391,30 @@ static void svc_i3c_master_free_ibi(struct i3c_dev_desc *dev)
13501391
static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
13511392
{
13521393
struct i3c_master_controller *m = i3c_dev_get_master(dev);
1394+
struct svc_i3c_master *master = to_svc_i3c_master(m);
1395+
int ret;
1396+
1397+
ret = pm_runtime_resume_and_get(master->dev);
1398+
if (ret < 0) {
1399+
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
1400+
return ret;
1401+
}
13531402

13541403
return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
13551404
}
13561405

13571406
static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
13581407
{
13591408
struct i3c_master_controller *m = i3c_dev_get_master(dev);
1409+
struct svc_i3c_master *master = to_svc_i3c_master(m);
1410+
int ret;
1411+
1412+
ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
13601413

1361-
return i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
1414+
pm_runtime_mark_last_busy(master->dev);
1415+
pm_runtime_put_autosuspend(master->dev);
1416+
1417+
return ret;
13621418
}
13631419

13641420
static void svc_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
@@ -1389,6 +1445,37 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
13891445
.disable_ibi = svc_i3c_master_disable_ibi,
13901446
};
13911447

1448+
static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master)
1449+
{
1450+
int ret = 0;
1451+
1452+
ret = clk_prepare_enable(master->pclk);
1453+
if (ret)
1454+
return ret;
1455+
1456+
ret = clk_prepare_enable(master->fclk);
1457+
if (ret) {
1458+
clk_disable_unprepare(master->pclk);
1459+
return ret;
1460+
}
1461+
1462+
ret = clk_prepare_enable(master->sclk);
1463+
if (ret) {
1464+
clk_disable_unprepare(master->pclk);
1465+
clk_disable_unprepare(master->fclk);
1466+
return ret;
1467+
}
1468+
1469+
return 0;
1470+
}
1471+
1472+
static void svc_i3c_master_unprepare_clks(struct svc_i3c_master *master)
1473+
{
1474+
clk_disable_unprepare(master->pclk);
1475+
clk_disable_unprepare(master->fclk);
1476+
clk_disable_unprepare(master->sclk);
1477+
}
1478+
13921479
static int svc_i3c_master_probe(struct platform_device *pdev)
13931480
{
13941481
struct device *dev = &pdev->dev;
@@ -1421,24 +1508,16 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
14211508

14221509
master->dev = dev;
14231510

1424-
ret = clk_prepare_enable(master->pclk);
1511+
ret = svc_i3c_master_prepare_clks(master);
14251512
if (ret)
14261513
return ret;
14271514

1428-
ret = clk_prepare_enable(master->fclk);
1429-
if (ret)
1430-
goto err_disable_pclk;
1431-
1432-
ret = clk_prepare_enable(master->sclk);
1433-
if (ret)
1434-
goto err_disable_fclk;
1435-
14361515
INIT_WORK(&master->hj_work, svc_i3c_master_hj_work);
14371516
INIT_WORK(&master->ibi_work, svc_i3c_master_ibi_work);
14381517
ret = devm_request_irq(dev, master->irq, svc_i3c_master_irq_handler,
14391518
IRQF_NO_SUSPEND, "svc-i3c-irq", master);
14401519
if (ret)
1441-
goto err_disable_sclk;
1520+
goto err_disable_clks;
14421521

14431522
master->free_slots = GENMASK(SVC_I3C_MAX_DEVS - 1, 0);
14441523

@@ -1452,29 +1531,38 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
14521531
GFP_KERNEL);
14531532
if (!master->ibi.slots) {
14541533
ret = -ENOMEM;
1455-
goto err_disable_sclk;
1534+
goto err_disable_clks;
14561535
}
14571536

14581537
platform_set_drvdata(pdev, master);
14591538

1539+
pm_runtime_set_autosuspend_delay(&pdev->dev, SVC_I3C_PM_TIMEOUT_MS);
1540+
pm_runtime_use_autosuspend(&pdev->dev);
1541+
pm_runtime_get_noresume(&pdev->dev);
1542+
pm_runtime_set_active(&pdev->dev);
1543+
pm_runtime_enable(&pdev->dev);
1544+
14601545
svc_i3c_master_reset(master);
14611546

14621547
/* Register the master */
14631548
ret = i3c_master_register(&master->base, &pdev->dev,
14641549
&svc_i3c_master_ops, false);
14651550
if (ret)
1466-
goto err_disable_sclk;
1551+
goto rpm_disable;
1552+
1553+
pm_runtime_mark_last_busy(&pdev->dev);
1554+
pm_runtime_put_autosuspend(&pdev->dev);
14671555

14681556
return 0;
14691557

1470-
err_disable_sclk:
1471-
clk_disable_unprepare(master->sclk);
1558+
rpm_disable:
1559+
pm_runtime_dont_use_autosuspend(&pdev->dev);
1560+
pm_runtime_put_noidle(&pdev->dev);
1561+
pm_runtime_set_suspended(&pdev->dev);
1562+
pm_runtime_disable(&pdev->dev);
14721563

1473-
err_disable_fclk:
1474-
clk_disable_unprepare(master->fclk);
1475-
1476-
err_disable_pclk:
1477-
clk_disable_unprepare(master->pclk);
1564+
err_disable_clks:
1565+
svc_i3c_master_unprepare_clks(master);
14781566

14791567
return ret;
14801568
}
@@ -1488,13 +1576,40 @@ static int svc_i3c_master_remove(struct platform_device *pdev)
14881576
if (ret)
14891577
return ret;
14901578

1491-
clk_disable_unprepare(master->pclk);
1492-
clk_disable_unprepare(master->fclk);
1493-
clk_disable_unprepare(master->sclk);
1579+
pm_runtime_dont_use_autosuspend(&pdev->dev);
1580+
pm_runtime_disable(&pdev->dev);
14941581

14951582
return 0;
14961583
}
14971584

1585+
static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev)
1586+
{
1587+
struct svc_i3c_master *master = dev_get_drvdata(dev);
1588+
1589+
svc_i3c_master_unprepare_clks(master);
1590+
pinctrl_pm_select_sleep_state(dev);
1591+
1592+
return 0;
1593+
}
1594+
1595+
static int __maybe_unused svc_i3c_runtime_resume(struct device *dev)
1596+
{
1597+
struct svc_i3c_master *master = dev_get_drvdata(dev);
1598+
int ret = 0;
1599+
1600+
pinctrl_pm_select_default_state(dev);
1601+
svc_i3c_master_prepare_clks(master);
1602+
1603+
return ret;
1604+
}
1605+
1606+
static const struct dev_pm_ops svc_i3c_pm_ops = {
1607+
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1608+
pm_runtime_force_resume)
1609+
SET_RUNTIME_PM_OPS(svc_i3c_runtime_suspend,
1610+
svc_i3c_runtime_resume, NULL)
1611+
};
1612+
14981613
static const struct of_device_id svc_i3c_master_of_match_tbl[] = {
14991614
{ .compatible = "silvaco,i3c-master" },
15001615
{ /* sentinel */ },
@@ -1506,6 +1621,7 @@ static struct platform_driver svc_i3c_master = {
15061621
.driver = {
15071622
.name = "silvaco-i3c-master",
15081623
.of_match_table = svc_i3c_master_of_match_tbl,
1624+
.pm = &svc_i3c_pm_ops,
15091625
},
15101626
};
15111627
module_platform_driver(svc_i3c_master);

0 commit comments

Comments
 (0)