Skip to content

Commit d5e5125

Browse files
wangxiaoningnxpalexandrebelloni
authored andcommitted
i3c: master: svc: add support for slave to stop returning data
When i3c controller reads data from slave device, slave device can stop returning data with an ACK after any byte. Add this support for svc i3c controller. Otherwise, it will timeout when the slave device ends the read operation early. Signed-off-by: Clark Wang <[email protected]> Reviewed-by: Jun Li <[email protected]> Reviewed-by: Miquel Raynal <[email protected]> Signed-off-by: Alexandre Belloni <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 9fd6b5c commit d5e5125

File tree

1 file changed

+40
-16
lines changed

1 file changed

+40
-16
lines changed

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

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -896,27 +896,35 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
896896
static int svc_i3c_master_read(struct svc_i3c_master *master,
897897
u8 *in, unsigned int len)
898898
{
899-
int offset = 0, i, ret;
900-
u32 mdctrl;
899+
int offset = 0, i;
900+
u32 mdctrl, mstatus;
901+
bool completed = false;
902+
unsigned int count;
903+
unsigned long start = jiffies;
901904

902-
while (offset < len) {
903-
unsigned int count;
905+
while (!completed) {
906+
mstatus = readl(master->regs + SVC_I3C_MSTATUS);
907+
if (SVC_I3C_MSTATUS_COMPLETE(mstatus) != 0)
908+
completed = true;
904909

905-
ret = readl_poll_timeout(master->regs + SVC_I3C_MDATACTRL,
906-
mdctrl,
907-
!(mdctrl & SVC_I3C_MDATACTRL_RXEMPTY),
908-
0, 1000);
909-
if (ret)
910-
return ret;
910+
if (time_after(jiffies, start + msecs_to_jiffies(1000))) {
911+
dev_dbg(master->dev, "I3C read timeout\n");
912+
return -ETIMEDOUT;
913+
}
911914

915+
mdctrl = readl(master->regs + SVC_I3C_MDATACTRL);
912916
count = SVC_I3C_MDATACTRL_RXCOUNT(mdctrl);
917+
if (offset + count > len) {
918+
dev_err(master->dev, "I3C receive length too long!\n");
919+
return -EINVAL;
920+
}
913921
for (i = 0; i < count; i++)
914922
in[offset + i] = readl(master->regs + SVC_I3C_MRDATAB);
915923

916924
offset += count;
917925
}
918926

919-
return 0;
927+
return offset;
920928
}
921929

922930
static int svc_i3c_master_write(struct svc_i3c_master *master,
@@ -949,7 +957,7 @@ static int svc_i3c_master_write(struct svc_i3c_master *master,
949957
static int svc_i3c_master_xfer(struct svc_i3c_master *master,
950958
bool rnw, unsigned int xfer_type, u8 addr,
951959
u8 *in, const u8 *out, unsigned int xfer_len,
952-
unsigned int read_len, bool continued)
960+
unsigned int *read_len, bool continued)
953961
{
954962
u32 reg;
955963
int ret;
@@ -959,7 +967,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
959967
SVC_I3C_MCTRL_IBIRESP_NACK |
960968
SVC_I3C_MCTRL_DIR(rnw) |
961969
SVC_I3C_MCTRL_ADDR(addr) |
962-
SVC_I3C_MCTRL_RDTERM(read_len),
970+
SVC_I3C_MCTRL_RDTERM(*read_len),
963971
master->regs + SVC_I3C_MCTRL);
964972

965973
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
@@ -971,17 +979,27 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
971979
ret = svc_i3c_master_read(master, in, xfer_len);
972980
else
973981
ret = svc_i3c_master_write(master, out, xfer_len);
974-
if (ret)
982+
if (ret < 0)
975983
goto emit_stop;
976984

985+
if (rnw)
986+
*read_len = ret;
987+
977988
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
978989
SVC_I3C_MSTATUS_COMPLETE(reg), 0, 1000);
979990
if (ret)
980991
goto emit_stop;
981992

982-
if (!continued)
993+
writel(SVC_I3C_MINT_COMPLETE, master->regs + SVC_I3C_MSTATUS);
994+
995+
if (!continued) {
983996
svc_i3c_master_emit_stop(master);
984997

998+
/* Wait idle if stop is sent. */
999+
readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
1000+
SVC_I3C_MSTATUS_STATE_IDLE(reg), 0, 1000);
1001+
}
1002+
9851003
return 0;
9861004

9871005
emit_stop:
@@ -1039,12 +1057,15 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
10391057
if (!xfer)
10401058
return;
10411059

1060+
svc_i3c_master_clear_merrwarn(master);
1061+
svc_i3c_master_flush_fifo(master);
1062+
10421063
for (i = 0; i < xfer->ncmds; i++) {
10431064
struct svc_i3c_cmd *cmd = &xfer->cmds[i];
10441065

10451066
ret = svc_i3c_master_xfer(master, cmd->rnw, xfer->type,
10461067
cmd->addr, cmd->in, cmd->out,
1047-
cmd->len, cmd->read_len,
1068+
cmd->len, &cmd->read_len,
10481069
cmd->continued);
10491070
if (ret)
10501071
break;
@@ -1173,6 +1194,9 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master,
11731194
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
11741195
svc_i3c_master_dequeue_xfer(master, xfer);
11751196

1197+
if (cmd->read_len != xfer_len)
1198+
ccc->dests[0].payload.len = cmd->read_len;
1199+
11761200
ret = xfer->ret;
11771201
svc_i3c_master_free_xfer(xfer);
11781202

0 commit comments

Comments
 (0)