static int __opb_read()

in fsi-master-aspeed.c [149:204]


static int __opb_read(struct fsi_master_aspeed *aspeed, uint32_t addr,
		      u32 transfer_size, void *out)
{
	void __iomem *base = aspeed->base;
	u32 result, reg;
	int status, ret;

	/*
	 * The ordering of these writes up until the trigger
	 * write does not matter, so use writel_relaxed.
	 */
	writel_relaxed(CMD_READ, base + OPB0_RW);
	writel_relaxed(transfer_size, base + OPB0_XFER_SIZE);
	writel_relaxed(addr, base + OPB0_FSI_ADDR);
	writel_relaxed(0x1, base + OPB_IRQ_CLEAR);
	writel(0x1, base + OPB_TRIGGER);

	ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
			   (reg & OPB0_XFER_ACK_EN) != 0,
			   0, OPB_POLL_TIMEOUT);

	status = readl(base + OPB0_STATUS);

	result = readl(base + OPB0_FSI_DATA_R);

	trace_fsi_master_aspeed_opb_read(addr, transfer_size, result,
			readl(base + OPB0_STATUS),
			reg);

	/* Return error when poll timed out */
	if (ret)
		return ret;

	/* Command failed, master will reset */
	if (status & STATUS_ERR_ACK)
		return -EIO;

	if (out) {
		switch (transfer_size) {
		case XFER_BYTE:
			*(u8 *)out = result;
			break;
		case XFER_HALFWORD:
			*(u16 *)out = result;
			break;
		case XFER_FULLWORD:
			*(u32 *)out = result;
			break;
		default:
			return -EINVAL;
		}

	}

	return 0;
}