drivers/mmc/host/renesas_sdhi_core.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/renesas_sdhi_core.c
Extension
.c
Size
40928 bytes
Lines
1365
Domain
Driver Families
Bucket
drivers/mmc
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

if (freq > new_upper_limit) {
			/* Too fast; look for a slightly slower option */
			freq = clk_round_rate(ref_clk, (new_clock << i) / 4 * 3);
			if (freq > new_upper_limit)
				continue;
		}

		diff = new_clock - (freq >> i);
		if (diff <= diff_min) {
			best_freq = freq;
			diff_min = diff;
		}
	}

	clk_set_rate(ref_clk, best_freq);

	if (priv->clkh)
		clk_set_rate(priv->clk, best_freq >> clkh_shift);

	return clk_get_rate(priv->clk);
}

static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
				   unsigned int new_clock)
{
	unsigned int clk_margin;
	u32 clk = 0, clock;

	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));

	if (new_clock == 0) {
		host->mmc->actual_clock = 0;
		goto out;
	}

	host->mmc->actual_clock = renesas_sdhi_clk_update(host, new_clock);
	clock = host->mmc->actual_clock / 512;

	/*
	 * Add a margin of 1/1024 rate higher to the clock rate in order
	 * to avoid clk variable setting a value of 0 due to the margin
	 * provided for actual_clock in renesas_sdhi_clk_update().
	 */
	clk_margin = new_clock >> 10;
	for (clk = 0x80000080; new_clock + clk_margin >= (clock << 1); clk >>= 1)
		clock <<= 1;

	/* 1/1 clock is option */
	if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1)) {
		if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400))
			clk |= 0xff;
		else
			clk &= ~0xff;
	}

	clock = clk & CLK_CTL_DIV_MASK;
	if (clock != CLK_CTL_DIV_MASK)
		host->mmc->actual_clock /= (1 << (ffs(clock) + 1));

	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock);
	if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
		usleep_range(10000, 11000);

	sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
		sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));

out:
	/* HW engineers overrode docs: no sleep needed on R-Car2+ */
	if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
		usleep_range(10000, 11000);
}

static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host)
{
	struct renesas_sdhi *priv = host_to_priv(host);

	clk_disable_unprepare(priv->clk_cd);
}

static int renesas_sdhi_card_busy(struct mmc_host *mmc)
{
	struct tmio_mmc_host *host = mmc_priv(mmc);

	return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) &
		 TMIO_STAT_DAT0);
}

static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
						    struct mmc_ios *ios)

Annotation

Implementation Notes