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
11481161static 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+
15821612static 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