drivers/mmc/host/meson-mx-sdhc-mmc.c

Source file repositories/reference/linux-study-clean/drivers/mmc/host/meson-mx-sdhc-mmc.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/meson-mx-sdhc-mmc.c
Extension
.c
Size
24499 bytes
Lines
909
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 meson_mx_sdhc_data {
	void		(*init_hw)(struct mmc_host *mmc);
	void		(*set_pdma)(struct mmc_host *mmc);
	void		(*wait_before_send)(struct mmc_host *mmc);
	bool		hardware_flush_all_cmds;
};

struct meson_mx_sdhc_host {
	struct mmc_host			*mmc;

	struct mmc_request		*mrq;
	struct mmc_command		*cmd;
	int				error;

	struct regmap			*regmap;

	struct clk			*pclk;
	struct clk			*sd_clk;
	struct clk_bulk_data		bulk_clks[MESON_SDHC_NUM_BULK_CLKS];
	bool				bulk_clks_enabled;

	const struct meson_mx_sdhc_data	*platform;
};

static const struct regmap_config meson_mx_sdhc_regmap_config = {
	.reg_bits = 8,
	.val_bits = 32,
	.reg_stride = 4,
	.max_register = MESON_SDHC_CLK2,
};

static void meson_mx_sdhc_reset(struct meson_mx_sdhc_host *host)
{
	regmap_write(host->regmap, MESON_SDHC_SRST, MESON_SDHC_SRST_MAIN_CTRL |
		     MESON_SDHC_SRST_RXFIFO | MESON_SDHC_SRST_TXFIFO |
		     MESON_SDHC_SRST_DPHY_RX | MESON_SDHC_SRST_DPHY_TX |
		     MESON_SDHC_SRST_DMA_IF);
	usleep_range(10, 100);

	regmap_write(host->regmap, MESON_SDHC_SRST, 0);
	usleep_range(10, 100);
}

static void meson_mx_sdhc_clear_fifo(struct mmc_host *mmc)
{
	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
	u32 stat;

	regmap_read(host->regmap, MESON_SDHC_STAT, &stat);
	if (!FIELD_GET(MESON_SDHC_STAT_RXFIFO_CNT, stat) &&
	    !FIELD_GET(MESON_SDHC_STAT_TXFIFO_CNT, stat))
		return;

	regmap_write(host->regmap, MESON_SDHC_SRST, MESON_SDHC_SRST_RXFIFO |
		     MESON_SDHC_SRST_TXFIFO | MESON_SDHC_SRST_MAIN_CTRL);
	udelay(5);

	regmap_read(host->regmap, MESON_SDHC_STAT, &stat);
	if (FIELD_GET(MESON_SDHC_STAT_RXFIFO_CNT, stat) ||
	    FIELD_GET(MESON_SDHC_STAT_TXFIFO_CNT, stat))
		dev_warn(mmc_dev(host->mmc),
			 "Failed to clear FIFOs, RX: %lu, TX: %lu\n",
			 FIELD_GET(MESON_SDHC_STAT_RXFIFO_CNT, stat),
			 FIELD_GET(MESON_SDHC_STAT_TXFIFO_CNT, stat));
}

static void meson_mx_sdhc_wait_cmd_ready(struct mmc_host *mmc)
{
	struct meson_mx_sdhc_host *host = mmc_priv(mmc);
	u32 stat, esta;
	int ret;

	ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_STAT, stat,
				       !(stat & MESON_SDHC_STAT_CMD_BUSY),
				       MESON_SDHC_WAIT_CMD_READY_SLEEP_US,
				       MESON_SDHC_WAIT_CMD_READY_TIMEOUT_US);
	if (ret) {
		dev_warn(mmc_dev(mmc),
			 "Failed to poll for CMD_BUSY while processing CMD%d\n",
			 host->cmd->opcode);
		meson_mx_sdhc_reset(host);
	}

	ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_ESTA, esta,
				       !(esta & MESON_SDHC_ESTA_11_13),
				       MESON_SDHC_WAIT_CMD_READY_SLEEP_US,
				       MESON_SDHC_WAIT_CMD_READY_TIMEOUT_US);
	if (ret) {
		dev_warn(mmc_dev(mmc),
			 "Failed to poll for ESTA[13:11] while processing CMD%d\n",

Annotation

Implementation Notes