drivers/mmc/host/loongson2-mmc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/loongson2-mmc.c
Extension
.c
Size
31519 bytes
Lines
1057
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 loongson2_dma_desc {
	u32 ndesc_addr;
	u32 mem_addr;
	u32 apb_addr;
	u32 len;
	u32 step_len;
	u32 step_times;
	u32 cmd;
	u32 stats;
	u32 high_ndesc_addr;
	u32 high_mem_addr;
	u32 reserved[2];
} __packed;

struct loongson2_mmc_host {
	struct device *dev;
	struct mmc_request *mrq;
	struct regmap *regmap;
	struct resource *res;
	struct clk *clk;
	u32 current_clk;
	void *sg_cpu;
	dma_addr_t sg_dma;
	int dma_complete;
	struct dma_chan *chan;
	int cmd_is_stop;
	int bus_width;
	spinlock_t lock; /* Prevent races with irq handler */
	enum loongson2_mmc_state state;
	const struct loongson2_mmc_pdata *pdata;
};

struct loongson2_mmc_pdata {
	u32 flags;
	const struct regmap_config *regmap_config;
	void (*reorder_cmd_data)(struct loongson2_mmc_host *host, struct mmc_command *cmd);
	void (*fix_data_timeout)(struct loongson2_mmc_host *host, struct mmc_command *cmd);
	int (*setting_dma)(struct loongson2_mmc_host *host, struct platform_device *pdev);
	int (*prepare_dma)(struct loongson2_mmc_host *host, struct mmc_data *data);
	void (*release_dma)(struct loongson2_mmc_host *host, struct device *dev);
};

static void loongson2_mmc_send_command(struct loongson2_mmc_host *host,
				       struct mmc_command *cmd)
{
	u32 cctrl;

	if (cmd->data)
		host->state = STATE_XFERFINISH_RSPFIN;
	else if (cmd->flags & MMC_RSP_PRESENT)
		host->state = STATE_RSPFIN;
	else
		host->state = STATE_CMDSENT;

	regmap_write(host->regmap, LOONGSON2_MMC_REG_CARG, cmd->arg);

	cctrl = FIELD_PREP(LOONGSON2_MMC_CCTL_INDEX, cmd->opcode);
	cctrl |= LOONGSON2_MMC_CCTL_HOST | LOONGSON2_MMC_CCTL_START;

	if (cmd->opcode == SD_SWITCH && cmd->data)
		cctrl |= LOONGSON2_MMC_CCTL_CMD6;

	if (cmd->flags & MMC_RSP_PRESENT)
		cctrl |= LOONGSON2_MMC_CCTL_WAIT_RSP;

	if (cmd->flags & MMC_RSP_136)
		cctrl |= LOONGSON2_MMC_CCTL_LONG_RSP;

	regmap_write(host->regmap, LOONGSON2_MMC_REG_CCTL, cctrl);
}

static int loongson2_mmc_setup_data(struct loongson2_mmc_host *host,
				    struct mmc_data *data)
{
	u32 dctrl;

	if ((data->blksz & 3) != 0)
		return -EINVAL;

	dctrl = FIELD_PREP(LOONGSON2_MMC_DCTL_BNUM, data->blocks);
	dctrl |= LOONGSON2_MMC_DCTL_START | LOONGSON2_MMC_DCTL_ENDMA;

	if (host->bus_width == MMC_BUS_WIDTH_4)
		dctrl |= LOONGSON2_MMC_DCTL_WIDE;
	else if (host->bus_width == MMC_BUS_WIDTH_8)
		dctrl |= LOONGSON2_MMC_DCTL_8BIT_BUS;

	regmap_write(host->regmap, LOONGSON2_MMC_REG_DCTL, dctrl);
	regmap_write(host->regmap, LOONGSON2_MMC_REG_BSIZE, data->blksz);
	regmap_write(host->regmap, LOONGSON2_MMC_REG_TIMER, U32_MAX);

Annotation

Implementation Notes