in master/dw-i3c-master.c [826:893]
static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
struct i3c_priv_xfer *i3c_xfers,
int i3c_nxfers)
{
struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct dw_i3c_master *master = to_dw_i3c_master(m);
unsigned int nrxwords = 0, ntxwords = 0;
struct dw_i3c_xfer *xfer;
int i, ret = 0;
if (!i3c_nxfers)
return 0;
if (i3c_nxfers > master->caps.cmdfifodepth)
return -ENOTSUPP;
for (i = 0; i < i3c_nxfers; i++) {
if (i3c_xfers[i].rnw)
nrxwords += DIV_ROUND_UP(i3c_xfers[i].len, 4);
else
ntxwords += DIV_ROUND_UP(i3c_xfers[i].len, 4);
}
if (ntxwords > master->caps.datafifodepth ||
nrxwords > master->caps.datafifodepth)
return -ENOTSUPP;
xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
if (!xfer)
return -ENOMEM;
for (i = 0; i < i3c_nxfers; i++) {
struct dw_i3c_cmd *cmd = &xfer->cmds[i];
cmd->cmd_hi = COMMAND_PORT_ARG_DATA_LEN(i3c_xfers[i].len) |
COMMAND_PORT_TRANSFER_ARG;
if (i3c_xfers[i].rnw) {
cmd->rx_buf = i3c_xfers[i].data.in;
cmd->rx_len = i3c_xfers[i].len;
cmd->cmd_lo = COMMAND_PORT_READ_TRANSFER |
COMMAND_PORT_SPEED(dev->info.max_read_ds);
} else {
cmd->tx_buf = i3c_xfers[i].data.out;
cmd->tx_len = i3c_xfers[i].len;
cmd->cmd_lo =
COMMAND_PORT_SPEED(dev->info.max_write_ds);
}
cmd->cmd_lo |= COMMAND_PORT_TID(i) |
COMMAND_PORT_DEV_INDEX(data->index) |
COMMAND_PORT_ROC;
if (i == (i3c_nxfers - 1))
cmd->cmd_lo |= COMMAND_PORT_TOC;
}
dw_i3c_master_enqueue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
dw_i3c_master_dequeue_xfer(master, xfer);
ret = xfer->ret;
dw_i3c_master_free_xfer(xfer);
return ret;
}