static int pmif_spmi_read_cmd()

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;
}