drivers/mmc/host/sunplus-mmc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/sunplus-mmc.c
Extension
.c
Size
29011 bytes
Lines
998
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 spmmc_tuning_info {
	int enable_tuning;
	int need_tuning;
	int retried; /* how many times has been retried */
	u32 rd_crc_dly:3;
	u32 rd_dat_dly:3;
	u32 rd_rsp_dly:3;
	u32 wr_cmd_dly:3;
	u32 wr_dat_dly:3;
	u32 clk_dly:3;
};

#define SPMMC_DMA_MODE 0
#define	SPMMC_PIO_MODE 1

struct spmmc_host {
	void __iomem *base;
	struct clk *clk;
	struct reset_control *rstc;
	struct mmc_host *mmc;
	struct mmc_request *mrq; /* current mrq */
	int irq;
	int dmapio_mode;
	struct spmmc_tuning_info tuning_info;
	int dma_int_threshold;
	int dma_use_int;
};

static inline int spmmc_wait_finish(struct spmmc_host *host)
{
	u32 state;

	return readl_poll_timeout(host->base + SPMMC_SD_STATE_REG, state,
					(state & SPMMC_SDSTATE_FINISH),
					SPMMC_POLL_DELAY_US, SPMMC_TIMEOUT_US);
}

static inline int spmmc_wait_sdstatus(struct spmmc_host *host, unsigned int status_bit)
{
	u32 status;

	return readl_poll_timeout(host->base + SPMMC_SD_STATUS_REG, status,
					(status & status_bit),
					SPMMC_POLL_DELAY_US, SPMMC_TIMEOUT_US);
}

#define spmmc_wait_rspbuf_full(host) spmmc_wait_sdstatus(host, SPMMC_SDSTATUS_RSP_BUF_FULL)
#define spmmc_wait_rxbuf_full(host) spmmc_wait_sdstatus(host, SPMMC_SDSTATUS_RX_DATA_BUF_FULL)
#define spmmc_wait_txbuf_empty(host) spmmc_wait_sdstatus(host, SPMMC_SDSTATUS_TX_DATA_BUF_EMPTY)

static void spmmc_get_rsp(struct spmmc_host *host, struct mmc_command *cmd)
{
	u32 value0_3, value4_5;

	if (!(cmd->flags & MMC_RSP_PRESENT))
		return;
	if (cmd->flags & MMC_RSP_136) {
		if (spmmc_wait_rspbuf_full(host))
			return;
		value0_3 = readl(host->base + SPMMC_SD_RSPBUF0_3_REG);
		value4_5 = readl(host->base + SPMMC_SD_RSPBUF4_5_REG) & 0xffff;
		cmd->resp[0] = (value0_3 << 8) | (value4_5 >> 8);
		cmd->resp[1] = value4_5 << 24;
		value0_3 = readl(host->base + SPMMC_SD_RSPBUF0_3_REG);
		value4_5 = readl(host->base + SPMMC_SD_RSPBUF4_5_REG) & 0xffff;
		cmd->resp[1] |= value0_3 >> 8;
		cmd->resp[2] = value0_3 << 24;
		cmd->resp[2] |= value4_5 << 8;
		value0_3 = readl(host->base + SPMMC_SD_RSPBUF0_3_REG);
		value4_5 = readl(host->base + SPMMC_SD_RSPBUF4_5_REG) & 0xffff;
		cmd->resp[2] |= value0_3 >> 24;
		cmd->resp[3] = value0_3 << 8;
		cmd->resp[3] |= value4_5 >> 8;
	} else {
		if (spmmc_wait_rspbuf_full(host))
			return;
		value0_3 = readl(host->base + SPMMC_SD_RSPBUF0_3_REG);
		value4_5 = readl(host->base + SPMMC_SD_RSPBUF4_5_REG) & 0xffff;
		cmd->resp[0] = (value0_3 << 8) | (value4_5 >> 8);
		cmd->resp[1] = value4_5 << 24;
	}
}

static void spmmc_set_bus_clk(struct spmmc_host *host, int clk)
{
	unsigned int clkdiv;
	int f_min = host->mmc->f_min;
	int f_max = host->mmc->f_max;
	u32 value = readl(host->base + SPMMC_SD_CONFIG0_REG);

Annotation

Implementation Notes