Skip to content

Commit a741958

Browse files
committed
Merge tag 'i3c/for-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
Pull i3c updates from Alexandre Belloni: - svc: fix suspend/resume on some platforms, fix locking issues * tag 'i3c/for-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: i3c: master: svc: add NACK check after start byte sent i3c: master: svc: fix cpu schedule in spin lock i3c: master: svc: fix i3c suspend/resume issue
2 parents ae80b40 + 49b472e commit a741958

1 file changed

Lines changed: 42 additions & 9 deletions

File tree

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

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
#define SVC_I3C_MINTCLR 0x094
9393
#define SVC_I3C_MINTMASKED 0x098
9494
#define SVC_I3C_MERRWARN 0x09C
95+
#define SVC_I3C_MERRWARN_NACK BIT(2)
9596
#define SVC_I3C_MDMACTRL 0x0A0
9697
#define SVC_I3C_MDATACTRL 0x0AC
9798
#define SVC_I3C_MDATACTRL_FLUSHTB BIT(0)
@@ -145,6 +146,11 @@ struct svc_i3c_xfer {
145146
struct svc_i3c_cmd cmds[];
146147
};
147148

149+
struct svc_i3c_regs_save {
150+
u32 mconfig;
151+
u32 mdynaddr;
152+
};
153+
148154
/**
149155
* struct svc_i3c_master - Silvaco I3C Master structure
150156
* @base: I3C master controller
@@ -173,6 +179,7 @@ struct svc_i3c_master {
173179
struct i3c_master_controller base;
174180
struct device *dev;
175181
void __iomem *regs;
182+
struct svc_i3c_regs_save saved_regs;
176183
u32 free_slots;
177184
u8 addrs[SVC_I3C_MAX_DEVS];
178185
struct i3c_dev_desc *descs[SVC_I3C_MAX_DEVS];
@@ -1008,6 +1015,11 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
10081015
if (ret)
10091016
goto emit_stop;
10101017

1018+
if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) {
1019+
ret = -ENXIO;
1020+
goto emit_stop;
1021+
}
1022+
10111023
if (rnw)
10121024
ret = svc_i3c_master_read(master, in, xfer_len);
10131025
else
@@ -1090,12 +1102,6 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
10901102
if (!xfer)
10911103
return;
10921104

1093-
ret = pm_runtime_resume_and_get(master->dev);
1094-
if (ret < 0) {
1095-
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
1096-
return;
1097-
}
1098-
10991105
svc_i3c_master_clear_merrwarn(master);
11001106
svc_i3c_master_flush_fifo(master);
11011107

@@ -1110,9 +1116,6 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
11101116
break;
11111117
}
11121118

1113-
pm_runtime_mark_last_busy(master->dev);
1114-
pm_runtime_put_autosuspend(master->dev);
1115-
11161119
xfer->ret = ret;
11171120
complete(&xfer->comp);
11181121

@@ -1133,6 +1136,13 @@ static void svc_i3c_master_enqueue_xfer(struct svc_i3c_master *master,
11331136
struct svc_i3c_xfer *xfer)
11341137
{
11351138
unsigned long flags;
1139+
int ret;
1140+
1141+
ret = pm_runtime_resume_and_get(master->dev);
1142+
if (ret < 0) {
1143+
dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
1144+
return;
1145+
}
11361146

11371147
init_completion(&xfer->comp);
11381148
spin_lock_irqsave(&master->xferqueue.lock, flags);
@@ -1143,6 +1153,9 @@ static void svc_i3c_master_enqueue_xfer(struct svc_i3c_master *master,
11431153
svc_i3c_master_start_xfer_locked(master);
11441154
}
11451155
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
1156+
1157+
pm_runtime_mark_last_busy(master->dev);
1158+
pm_runtime_put_autosuspend(master->dev);
11461159
}
11471160

11481161
static bool
@@ -1579,10 +1592,28 @@ static void svc_i3c_master_remove(struct platform_device *pdev)
15791592
pm_runtime_disable(&pdev->dev);
15801593
}
15811594

1595+
static void svc_i3c_save_regs(struct svc_i3c_master *master)
1596+
{
1597+
master->saved_regs.mconfig = readl(master->regs + SVC_I3C_MCONFIG);
1598+
master->saved_regs.mdynaddr = readl(master->regs + SVC_I3C_MDYNADDR);
1599+
}
1600+
1601+
static void svc_i3c_restore_regs(struct svc_i3c_master *master)
1602+
{
1603+
if (readl(master->regs + SVC_I3C_MDYNADDR) !=
1604+
master->saved_regs.mdynaddr) {
1605+
writel(master->saved_regs.mconfig,
1606+
master->regs + SVC_I3C_MCONFIG);
1607+
writel(master->saved_regs.mdynaddr,
1608+
master->regs + SVC_I3C_MDYNADDR);
1609+
}
1610+
}
1611+
15821612
static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev)
15831613
{
15841614
struct svc_i3c_master *master = dev_get_drvdata(dev);
15851615

1616+
svc_i3c_save_regs(master);
15861617
svc_i3c_master_unprepare_clks(master);
15871618
pinctrl_pm_select_sleep_state(dev);
15881619

@@ -1596,6 +1627,8 @@ static int __maybe_unused svc_i3c_runtime_resume(struct device *dev)
15961627
pinctrl_pm_select_default_state(dev);
15971628
svc_i3c_master_prepare_clks(master);
15981629

1630+
svc_i3c_restore_regs(master);
1631+
15991632
return 0;
16001633
}
16011634

0 commit comments

Comments
 (0)