drivers/mmc/host/sdhci-of-ma35d1.c

Source file repositories/reference/linux-study-clean/drivers/mmc/host/sdhci-of-ma35d1.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/sdhci-of-ma35d1.c
Extension
.c
Size
8635 bytes
Lines
308
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 ma35_priv {
	struct reset_control	*rst;
	struct pinctrl		*pinctrl;
	struct pinctrl_state	*pins_uhs;
	struct pinctrl_state	*pins_default;
};

struct ma35_restore_data {
	u32	reg;
	u32	width;
};

static const struct ma35_restore_data restore_data[] = {
	{ SDHCI_CLOCK_CONTROL,		sizeof(u32)},
	{ SDHCI_BLOCK_SIZE,		sizeof(u32)},
	{ SDHCI_INT_ENABLE,		sizeof(u32)},
	{ SDHCI_SIGNAL_ENABLE,		sizeof(u32)},
	{ SDHCI_AUTO_CMD_STATUS,	sizeof(u32)},
	{ SDHCI_HOST_CONTROL,		sizeof(u32)},
	{ SDHCI_TIMEOUT_CONTROL,	sizeof(u8) },
	{ MA35_SDHCI_MSHCCTL,		sizeof(u16)},
	{ MA35_SDHCI_MBIUCTL,		sizeof(u16)},
};

/*
 * If DMA addr spans 128MB boundary, we split the DMA transfer into two
 * so that each DMA transfer doesn't exceed the boundary.
 */
static void ma35_adma_write_desc(struct sdhci_host *host, void **desc, dma_addr_t addr, int len,
				 unsigned int cmd)
{
	int tmplen, offset;

	if (likely(!len || (ALIGN(addr, SZ_128M) == ALIGN(addr + len - 1, SZ_128M)))) {
		sdhci_adma_write_desc(host, desc, addr, len, cmd);
		return;
	}

	offset = addr & (SZ_128M - 1);
	tmplen = SZ_128M - offset;
	sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);

	addr += tmplen;
	len -= tmplen;
	sdhci_adma_write_desc(host, desc, addr, len, cmd);
}

static void ma35_set_clock(struct sdhci_host *host, unsigned int clock)
{
	u32 ctl;

	/*
	 * If the clock frequency exceeds MMC_HIGH_52_MAX_DTR,
	 * disable command conflict check.
	 */
	ctl = sdhci_readw(host, MA35_SDHCI_MSHCCTL);
	if (clock > MMC_HIGH_52_MAX_DTR)
		ctl &= ~MA35_SDHCI_CMD_CONFLICT_CHK;
	else
		ctl |= MA35_SDHCI_CMD_CONFLICT_CHK;
	sdhci_writew(host, ctl, MA35_SDHCI_MSHCCTL);

	sdhci_set_clock(host, clock);
}

static int ma35_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
{
	struct sdhci_host *host = mmc_priv(mmc);
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct ma35_priv *priv = sdhci_pltfm_priv(pltfm_host);

	switch (ios->signal_voltage) {
	case MMC_SIGNAL_VOLTAGE_180:
		if (!IS_ERR(priv->pinctrl) && !IS_ERR(priv->pins_uhs))
			pinctrl_select_state(priv->pinctrl, priv->pins_uhs);
		break;
	case MMC_SIGNAL_VOLTAGE_330:
		if (!IS_ERR(priv->pinctrl) && !IS_ERR(priv->pins_default))
			pinctrl_select_state(priv->pinctrl, priv->pins_default);
		break;
	default:
		dev_err(mmc_dev(host->mmc), "Unsupported signal voltage!\n");
		return -EINVAL;
	}

	return sdhci_start_signal_voltage_switch(mmc, ios);
}

static void ma35_voltage_switch(struct sdhci_host *host)
{

Annotation

Implementation Notes