drivers/mmc/host/dw_mmc-hi3798mv200.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/dw_mmc-hi3798mv200.c
Extension
.c
Size
6543 bytes
Lines
243
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 dw_mci_hi3798mv200_priv {
	struct clk *sample_clk;
	struct clk *drive_clk;
	struct regmap *crg_reg;
	u32 sap_dll_offset;
};

static void dw_mci_hi3798mv200_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
	struct dw_mci_hi3798mv200_priv *priv = host->priv;
	struct mmc_clk_phase phase = host->phase_map.phase[ios->timing];
	u32 val;

	val = mci_readl(host, ENABLE_SHIFT);
	if (ios->timing == MMC_TIMING_MMC_DDR52
	    || ios->timing == MMC_TIMING_UHS_DDR50)
		val |= SDMMC_ENABLE_PHASE;
	else
		val &= ~SDMMC_ENABLE_PHASE;
	mci_writel(host, ENABLE_SHIFT, val);

	val = mci_readl(host, DDR_REG);
	if (ios->timing == MMC_TIMING_MMC_HS400)
		val |= SDMMC_DDR_HS400;
	else
		val &= ~SDMMC_DDR_HS400;
	mci_writel(host, DDR_REG, val);

	if (clk_set_rate(host->ciu_clk, ios->clock))
		dev_warn(host->dev, "Failed to set rate to %u\n", ios->clock);
	else
		/*
		 * CLK_MUX_ROUND_NEAREST is enabled for this clock
		 * The actual clock rate is not what we set, but a rounded value
		 * so we should get the rate once again
		 */
		host->bus_hz = clk_get_rate(host->ciu_clk);

	if (phase.valid) {
		clk_set_phase(priv->drive_clk, phase.out_deg);
		clk_set_phase(priv->sample_clk, phase.in_deg);
	} else {
		dev_warn(host->dev,
			 "The phase entry for timing mode %d is missing in device tree.\n",
			 ios->timing);
	}
}

static inline int dw_mci_hi3798mv200_enable_tuning(struct dw_mci *host)
{
	struct dw_mci_hi3798mv200_priv *priv = host->priv;

	return regmap_clear_bits(priv->crg_reg, priv->sap_dll_offset, SAP_DLL_CTRL_DLLMODE);
}

static inline int dw_mci_hi3798mv200_disable_tuning(struct dw_mci *host)
{
	struct dw_mci_hi3798mv200_priv *priv = host->priv;

	return regmap_set_bits(priv->crg_reg, priv->sap_dll_offset, SAP_DLL_CTRL_DLLMODE);
}

static int dw_mci_hi3798mv200_execute_tuning_mix_mode(struct dw_mci *host,
					     u32 opcode)
{
	static const int degrees[] = { 0, 45, 90, 135, 180, 225, 270, 315 };
	struct dw_mci_hi3798mv200_priv *priv = host->priv;
	int raise_point = -1, fall_point = -1, mid;
	int err, prev_err = -1;
	int found = 0;
	int regval;
	int i;
	int ret;

	ret = dw_mci_hi3798mv200_enable_tuning(host);
	if (ret < 0)
		return ret;

	for (i = 0; i < ARRAY_SIZE(degrees); i++) {
		clk_set_phase(priv->sample_clk, degrees[i]);
		mci_writel(host, RINTSTS, ALL_INT_CLR);

		/*
		 * HiSilicon implemented a tuning mechanism.
		 * It needs special interaction with the DLL.
		 *
		 * Treat edge(flip) found as an error too.
		 */
		err = mmc_send_tuning(host->mmc, opcode, NULL);
		regval = mci_readl(host, TUNING_CTRL);

Annotation

Implementation Notes