in spmi-mtk-pmif.c [310:371]
static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
u16 addr, u8 *buf, size_t len)
{
struct pmif *arb = spmi_controller_get_drvdata(ctrl);
struct ch_reg *inf_reg;
int ret;
u32 data, cmd;
/* Check for argument validation. */
if (sid & ~0xf) {
dev_err(&ctrl->dev, "exceed the max slv id\n");
return -EINVAL;
}
if (len > 4) {
dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);
return -EINVAL;
}
if (opc >= 0x60 && opc <= 0x7f)
opc = PMIF_CMD_REG;
else if ((opc >= 0x20 && opc <= 0x2f) || (opc >= 0x38 && opc <= 0x3f))
opc = PMIF_CMD_EXT_REG_LONG;
else
return -EINVAL;
/* Wait for Software Interface FSM state to be IDLE. */
inf_reg = &arb->chan;
ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
data, GET_SWINF(data) == SWINF_IDLE,
PMIF_DELAY_US, PMIF_TIMEOUT_US);
if (ret < 0) {
/* set channel ready if the data has transferred */
if (pmif_is_fsm_vldclr(arb))
pmif_writel(arb, 1, inf_reg->ch_rdy);
dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
return ret;
}
/* Send the command. */
cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr;
pmif_writel(arb, cmd, inf_reg->ch_send);
/*
* Wait for Software Interface FSM state to be WFVLDCLR,
* read the data and clear the valid flag.
*/
ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
data, GET_SWINF(data) == SWINF_WFVLDCLR,
PMIF_DELAY_US, PMIF_TIMEOUT_US);
if (ret < 0) {
dev_err(&ctrl->dev, "failed to wait for SWINF_WFVLDCLR\n");
return ret;
}
data = pmif_readl(arb, inf_reg->rdata);
memcpy(buf, &data, len);
pmif_writel(arb, 1, inf_reg->ch_rdy);
return 0;
}