drivers/mmc/host/sdhci-pxav2.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/sdhci-pxav2.c
Extension
.c
Size
9951 bytes
Lines
349
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 sdhci_pxav2_host {
	struct mmc_request *sdio_mrq;
	struct pinctrl *pinctrl;
	struct pinctrl_state *pins_default;
	struct pinctrl_state *pins_cmd_gpio;
};

static void pxav2_reset(struct sdhci_host *host, u8 mask)
{
	struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
	struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;

	sdhci_reset(host, mask);

	if (mask == SDHCI_RESET_ALL) {
		u16 tmp = 0;

		/*
		 * tune timing of read data/command when crc error happen
		 * no performance impact
		 */
		if (pdata && pdata->clk_delay_sel == 1) {
			tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);

			tmp &= ~(SDCLK_DELAY_MASK << SDCLK_DELAY_SHIFT);
			tmp |= (pdata->clk_delay_cycles & SDCLK_DELAY_MASK)
				<< SDCLK_DELAY_SHIFT;
			tmp &= ~(SDCLK_SEL_MASK << SDCLK_SEL_SHIFT);
			tmp |= (1 & SDCLK_SEL_MASK) << SDCLK_SEL_SHIFT;

			writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
		}

		if (pdata && (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING)) {
			tmp = readw(host->ioaddr + SD_FIFO_PARAM);
			tmp &= ~CLK_GATE_SETTING_BITS;
			writew(tmp, host->ioaddr + SD_FIFO_PARAM);
		} else {
			tmp = readw(host->ioaddr + SD_FIFO_PARAM);
			tmp &= ~CLK_GATE_SETTING_BITS;
			tmp |= CLK_GATE_SETTING_BITS;
			writew(tmp, host->ioaddr + SD_FIFO_PARAM);
		}
	}
}

static u16 pxav1_readw(struct sdhci_host *host, int reg)
{
	/* Workaround for data abort exception on SDH2 and SDH4 on PXA168 */
	if (reg == SDHCI_HOST_VERSION)
		return readl(host->ioaddr + SDHCI_HOST_VERSION - 2) >> 16;

	return readw(host->ioaddr + reg);
}

static u32 pxav1_irq(struct sdhci_host *host, u32 intmask)
{
	struct sdhci_pxav2_host *pxav2_host = sdhci_pltfm_priv(sdhci_priv(host));
	struct mmc_request *sdio_mrq;

	if (pxav2_host->sdio_mrq && (intmask & SDHCI_INT_CMD_MASK)) {
		/* The dummy CMD0 for the SDIO workaround just completed */
		sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, SDHCI_INT_STATUS);
		intmask &= ~SDHCI_INT_CMD_MASK;

		/* Restore MMC function to CMD pin */
		if (pxav2_host->pinctrl && pxav2_host->pins_default)
			pinctrl_select_state(pxav2_host->pinctrl, pxav2_host->pins_default);

		sdio_mrq = pxav2_host->sdio_mrq;
		pxav2_host->sdio_mrq = NULL;
		mmc_request_done(host->mmc, sdio_mrq);
	}

	return intmask;
}

static void pxav1_request_done(struct sdhci_host *host, struct mmc_request *mrq)
{
	u16 tmp;
	struct sdhci_pxav2_host *pxav2_host;

	/* If this is an SDIO command, perform errata workaround for silicon bug */
	if (!mrq->cmd->error &&
	    (mrq->cmd->opcode == SD_IO_RW_DIRECT ||
	     mrq->cmd->opcode == SD_IO_RW_EXTENDED)) {
		/* Reset data port */
		tmp = readw(host->ioaddr + SDHCI_TIMEOUT_CONTROL);
		tmp |= 0x400;
		writew(tmp, host->ioaddr + SDHCI_TIMEOUT_CONTROL);

Annotation

Implementation Notes