drivers/mmc/host/litex_mmc.c

Source file repositories/reference/linux-study-clean/drivers/mmc/host/litex_mmc.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/litex_mmc.c
Extension
.c
Size
18149 bytes
Lines
667
Domain
Driver Families
Bucket
drivers/mmc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct litex_mmc_host {
	struct mmc_host *mmc;

	void __iomem *sdphy;
	void __iomem *sdcore;
	void __iomem *sdreader;
	void __iomem *sdwriter;
	void __iomem *sdirq;

	void *buffer;
	size_t buf_size;
	dma_addr_t dma;

	struct completion cmd_done;
	int irq;

	unsigned int ref_clk;
	unsigned int sd_clk;

	u32 resp[4];
	u16 rca;

	bool is_bus_width_set;
	bool app_cmd;
};

static int litex_mmc_sdcard_wait_done(void __iomem *reg, struct device *dev)
{
	u8 evt;
	int ret;

	ret = readx_poll_timeout(litex_read8, reg, evt, evt & SD_BIT_DONE,
				 SD_SLEEP_US, SD_TIMEOUT_US);
	if (ret)
		return ret;
	if (evt == SD_BIT_DONE)
		return 0;
	if (evt & SD_BIT_WR_ERR)
		return -EIO;
	if (evt & SD_BIT_TIMEOUT)
		return -ETIMEDOUT;
	if (evt & SD_BIT_CRC_ERR)
		return -EILSEQ;
	dev_err(dev, "%s: unknown error (evt=%x)\n", __func__, evt);
	return -EINVAL;
}

static int litex_mmc_send_cmd(struct litex_mmc_host *host,
			      u8 cmd, u32 arg, u8 response_len, u8 transfer)
{
	struct device *dev = mmc_dev(host->mmc);
	void __iomem *reg;
	int ret;
	u8 evt;

	litex_write32(host->sdcore + LITEX_CORE_CMDARG, arg);
	litex_write32(host->sdcore + LITEX_CORE_CMDCMD,
		      cmd << 8 | transfer << 5 | response_len);
	litex_write8(host->sdcore + LITEX_CORE_CMDSND, 1);

	/*
	 * Wait for an interrupt if we have an interrupt and either there is
	 * data to be transferred, or if the card can report busy via DAT0.
	 */
	if (host->irq > 0 &&
	    (transfer != SD_CTL_DATA_XFER_NONE ||
	     response_len == SD_CTL_RESP_SHORT_BUSY)) {
		reinit_completion(&host->cmd_done);
		litex_write32(host->sdirq + LITEX_IRQ_ENABLE,
			      SDIRQ_CMD_DONE | SDIRQ_CARD_DETECT);
		wait_for_completion(&host->cmd_done);
	}

	ret = litex_mmc_sdcard_wait_done(host->sdcore + LITEX_CORE_CMDEVT, dev);
	if (ret) {
		dev_err(dev, "Command (cmd %d) error, status %d\n", cmd, ret);
		return ret;
	}

	if (response_len != SD_CTL_RESP_NONE) {
		/*
		 * NOTE: this matches the semantics of litex_read32()
		 * regardless of underlying arch endianness!
		 */
		memcpy_fromio(host->resp,
			      host->sdcore + LITEX_CORE_CMDRSP, 0x10);
	}

	if (!host->app_cmd && cmd == SD_SEND_RELATIVE_ADDR)
		host->rca = (host->resp[3] >> 16);

Annotation

Implementation Notes