in master/dw-i3c-master.c [451:516]
static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr)
{
struct dw_i3c_xfer *xfer = master->xferqueue.cur;
int i, ret = 0;
u32 nresp;
if (!xfer)
return;
nresp = readl(master->regs + QUEUE_STATUS_LEVEL);
nresp = QUEUE_STATUS_LEVEL_RESP(nresp);
for (i = 0; i < nresp; i++) {
struct dw_i3c_cmd *cmd;
u32 resp;
resp = readl(master->regs + RESPONSE_QUEUE_PORT);
cmd = &xfer->cmds[RESPONSE_PORT_TID(resp)];
cmd->rx_len = RESPONSE_PORT_DATA_LEN(resp);
cmd->error = RESPONSE_PORT_ERR_STATUS(resp);
if (cmd->rx_len && !cmd->error)
dw_i3c_master_read_rx_fifo(master, cmd->rx_buf,
cmd->rx_len);
}
for (i = 0; i < nresp; i++) {
switch (xfer->cmds[i].error) {
case RESPONSE_NO_ERROR:
break;
case RESPONSE_ERROR_PARITY:
case RESPONSE_ERROR_IBA_NACK:
case RESPONSE_ERROR_TRANSF_ABORT:
case RESPONSE_ERROR_CRC:
case RESPONSE_ERROR_FRAME:
ret = -EIO;
break;
case RESPONSE_ERROR_OVER_UNDER_FLOW:
ret = -ENOSPC;
break;
case RESPONSE_ERROR_I2C_W_NACK_ERR:
case RESPONSE_ERROR_ADDRESS_NACK:
default:
ret = -EINVAL;
break;
}
}
xfer->ret = ret;
complete(&xfer->comp);
if (ret < 0) {
dw_i3c_master_dequeue_xfer_locked(master, xfer);
writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_RESUME,
master->regs + DEVICE_CTRL);
}
xfer = list_first_entry_or_null(&master->xferqueue.list,
struct dw_i3c_xfer,
node);
if (xfer)
list_del_init(&xfer->node);
master->xferqueue.cur = xfer;
dw_i3c_master_start_xfer_locked(master);
}