drivers/mmc/host/sh_mmcif.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/sh_mmcif.c
Extension
.c
Size
42318 bytes
Lines
1601
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 sh_mmcif_host {
	struct mmc_host *mmc;
	struct mmc_request *mrq;
	struct platform_device *pd;
	struct clk *clk;
	int bus_width;
	unsigned char timing;
	bool sd_error;
	bool dying;
	long timeout;
	void __iomem *addr;
	spinlock_t lock;		/* protect sh_mmcif_host::state */
	enum sh_mmcif_state state;
	enum sh_mmcif_wait_for wait_for;
	struct delayed_work timeout_work;
	size_t blocksize;
	struct sg_mapping_iter sg_miter;
	bool power;
	bool ccs_enable;		/* Command Completion Signal support */
	bool clk_ctrl2_enable;
	struct mutex thread_lock;
	u32 clkdiv_map;         /* see CE_CLK_CTRL::CLKDIV */

	/* DMA support */
	struct dma_chan		*chan_rx;
	struct dma_chan		*chan_tx;
	struct completion	dma_complete;
	bool			dma_active;
};

static const struct of_device_id sh_mmcif_of_match[] = {
	{ .compatible = "renesas,sh-mmcif" },
	{ }
};
MODULE_DEVICE_TABLE(of, sh_mmcif_of_match);

#define sh_mmcif_host_to_dev(host) (&host->pd->dev)

static inline void sh_mmcif_bitset(struct sh_mmcif_host *host,
					unsigned int reg, u32 val)
{
	writel(val | readl(host->addr + reg), host->addr + reg);
}

static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
					unsigned int reg, u32 val)
{
	writel(~val & readl(host->addr + reg), host->addr + reg);
}

static void sh_mmcif_dma_complete(void *arg)
{
	struct sh_mmcif_host *host = arg;
	struct mmc_request *mrq = host->mrq;
	struct device *dev = sh_mmcif_host_to_dev(host);

	dev_dbg(dev, "Command completed\n");

	if (WARN(!mrq || !mrq->data, "%s: NULL data in DMA completion!\n",
		 dev_name(dev)))
		return;

	complete(&host->dma_complete);
}

static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
{
	struct mmc_data *data = host->mrq->data;
	struct scatterlist *sg = data->sg;
	struct dma_async_tx_descriptor *desc = NULL;
	struct dma_chan *chan = host->chan_rx;
	struct device *dev = sh_mmcif_host_to_dev(host);
	dma_cookie_t cookie = -EINVAL;
	int ret;

	ret = dma_map_sg(chan->device->dev, sg, data->sg_len,
			 DMA_FROM_DEVICE);
	if (ret > 0) {
		host->dma_active = true;
		desc = dmaengine_prep_slave_sg(chan, sg, ret,
			DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
	}

	if (desc) {
		desc->callback = sh_mmcif_dma_complete;
		desc->callback_param = host;
		cookie = dmaengine_submit(desc);
		sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN);
		dma_async_issue_pending(chan);
	}

Annotation

Implementation Notes