diff options
-rw-r--r-- | drivers/i3c/master/svc-i3c-master.c | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index ed3f1bfbea37..7ef7e50b4b91 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -388,10 +388,11 @@ static int svc_i3c_master_handle_ibi(struct svc_i3c_master *master, return 0; } -static void svc_i3c_master_ack_ibi(struct svc_i3c_master *master, +static int svc_i3c_master_ack_ibi(struct svc_i3c_master *master, bool mandatory_byte) { unsigned int ibi_ack_nack; + u32 reg; ibi_ack_nack = SVC_I3C_MCTRL_REQUEST_IBI_ACKNACK; if (mandatory_byte) @@ -400,18 +401,30 @@ static void svc_i3c_master_ack_ibi(struct svc_i3c_master *master, ibi_ack_nack |= SVC_I3C_MCTRL_IBIRESP_ACK_WITHOUT_BYTE; writel(ibi_ack_nack, master->regs + SVC_I3C_MCTRL); + + return readl_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, reg, + SVC_I3C_MSTATUS_MCTRLDONE(reg), 1, 1000); + } -static void svc_i3c_master_nack_ibi(struct svc_i3c_master *master) +static int svc_i3c_master_nack_ibi(struct svc_i3c_master *master) { + int ret; + u32 reg; + writel(SVC_I3C_MCTRL_REQUEST_IBI_ACKNACK | SVC_I3C_MCTRL_IBIRESP_NACK, master->regs + SVC_I3C_MCTRL); + + ret = readl_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, reg, + SVC_I3C_MSTATUS_MCTRLDONE(reg), 1, 1000); + return ret; } static int svc_i3c_master_handle_ibi_won(struct svc_i3c_master *master, u32 mstatus) { u32 ibitype; + int ret = 0; ibitype = SVC_I3C_MSTATUS_IBITYPE(mstatus); @@ -421,10 +434,10 @@ static int svc_i3c_master_handle_ibi_won(struct svc_i3c_master *master, u32 msta switch (ibitype) { case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN: case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: - svc_i3c_master_nack_ibi(master); + ret = svc_i3c_master_nack_ibi(master); } - return 0; + return ret; } static void svc_i3c_master_ibi_work(struct work_struct *work) @@ -935,7 +948,9 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, if (ret) break; } else if (SVC_I3C_MSTATUS_IBIWON(reg)) { - svc_i3c_master_handle_ibi_won(master, reg); + ret = svc_i3c_master_handle_ibi_won(master, reg); + if (ret) + break; continue; } else if (SVC_I3C_MSTATUS_MCTRLDONE(reg)) { if (SVC_I3C_MSTATUS_STATE_IDLE(reg) && @@ -1209,7 +1224,9 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master, * start. */ if (SVC_I3C_MSTATUS_IBIWON(reg)) { - svc_i3c_master_handle_ibi_won(master, reg); + ret = svc_i3c_master_handle_ibi_won(master, reg); + if (ret) + goto emit_stop; continue; } |