in hisi-spmi-controller.c [111:185]
static int spmi_read_cmd(struct spmi_controller *ctrl,
u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc)
{
struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev);
u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel;
unsigned long flags;
u8 *buf = __buf;
u32 cmd, data;
int rc;
u8 op_code, i;
if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) {
dev_err(&ctrl->dev,
"spmi_controller supports 1..%d bytes per trans, but:%zu requested\n",
SPMI_CONTROLLER_MAX_TRANS_BYTES, bc);
return -EINVAL;
}
switch (opc) {
case SPMI_CMD_READ:
op_code = SPMI_CMD_REG_READ;
break;
case SPMI_CMD_EXT_READ:
op_code = SPMI_CMD_EXT_REG_READ;
break;
case SPMI_CMD_EXT_READL:
op_code = SPMI_CMD_EXT_REG_READ_L;
break;
default:
dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc);
return -EINVAL;
}
cmd = SPMI_APB_SPMI_CMD_EN |
(op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) |
((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) |
((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | /* slvid */
((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */
spin_lock_irqsave(&spmi_controller->lock, flags);
writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR);
rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller,
spmi_controller->base, slave_id, slave_addr);
if (rc)
goto done;
for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) {
data = readl(spmi_controller->base + chnl_ofst +
SPMI_SLAVE_OFFSET * slave_id +
SPMI_APB_SPMI_RDATA0_BASE_ADDR +
i * SPMI_PER_DATAREG_BYTE);
data = be32_to_cpu((__be32 __force)data);
if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) {
memcpy(buf, &data, sizeof(data));
buf += sizeof(data);
} else {
memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE);
buf += (bc % SPMI_PER_DATAREG_BYTE);
}
}
done:
spin_unlock_irqrestore(&spmi_controller->lock, flags);
if (rc)
dev_err(&ctrl->dev,
"spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n",
opc, slave_id, slave_addr, bc + 1);
else
dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n",
__func__, slave_id, slave_addr, (int)bc, __buf);
return rc;
}