drivers/phy/intel/phy-intel-keembay-emmc.c

Source file repositories/reference/linux-study-clean/drivers/phy/intel/phy-intel-keembay-emmc.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/intel/phy-intel-keembay-emmc.c
Extension
.c
Size
8670 bytes
Lines
309
Domain
Driver Families
Bucket
drivers/phy
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 keembay_emmc_phy {
	struct regmap *syscfg;
	struct clk *emmcclk;
};

static const struct regmap_config keembay_regmap_config = {
	.reg_bits = 32,
	.val_bits = 32,
	.reg_stride = 4,
};

static int keembay_emmc_phy_power(struct phy *phy, bool on_off)
{
	struct keembay_emmc_phy *priv = phy_get_drvdata(phy);
	unsigned int caldone;
	unsigned int dllrdy;
	unsigned int freqsel;
	unsigned int mhz;
	int ret;

	/*
	 * Keep phyctrl_pdb and phyctrl_endll low to allow
	 * initialization of CALIO state M/C DFFs
	 */
	ret = regmap_update_bits(priv->syscfg, PHY_CFG_0, PWR_DOWN_MASK,
				 FIELD_PREP(PWR_DOWN_MASK, 0));
	if (ret) {
		dev_err(&phy->dev, "CALIO power down bar failed: %d\n", ret);
		return ret;
	}

	ret = regmap_update_bits(priv->syscfg, PHY_CFG_0, DLL_EN_MASK,
				 FIELD_PREP(DLL_EN_MASK, 0));
	if (ret) {
		dev_err(&phy->dev, "turn off the dll failed: %d\n", ret);
		return ret;
	}

	/* Already finish power off above */
	if (!on_off)
		return 0;

	mhz = DIV_ROUND_CLOSEST(clk_get_rate(priv->emmcclk), 1000000);
	if (mhz <= 200 && mhz >= 170)
		freqsel = FREQSEL_200M_170M;
	else if (mhz <= 170 && mhz >= 140)
		freqsel = FREQSEL_170M_140M;
	else if (mhz <= 140 && mhz >= 110)
		freqsel = FREQSEL_140M_110M;
	else if (mhz <= 110 && mhz >= 80)
		freqsel = FREQSEL_110M_80M;
	else if (mhz <= 80 && mhz >= 50)
		freqsel = FREQSEL_80M_50M;
	else
		freqsel = 0x0;

	/* Check for EMMC clock rate*/
	if (mhz > 175)
		dev_warn(&phy->dev, "Unsupported rate: %d MHz\n", mhz);

	/*
	 * According to the user manual, calpad calibration
	 * cycle takes more than 2us without the minimal recommended
	 * value, so we may need a little margin here
	 */
	udelay(5);

	ret = regmap_update_bits(priv->syscfg, PHY_CFG_0, PWR_DOWN_MASK,
				 FIELD_PREP(PWR_DOWN_MASK, 1));
	if (ret) {
		dev_err(&phy->dev, "CALIO power down bar failed: %d\n", ret);
		return ret;
	}

	/*
	 * According to the user manual, it asks driver to wait 5us for
	 * calpad busy trimming. However it is documented that this value is
	 * PVT(A.K.A. process, voltage and temperature) relevant, so some
	 * failure cases are found which indicates we should be more tolerant
	 * to calpad busy trimming.
	 */
	ret = regmap_read_poll_timeout(priv->syscfg, PHY_STAT,
				       caldone, IS_CALDONE(caldone),
				       0, 50);
	if (ret) {
		dev_err(&phy->dev, "caldone failed, ret=%d\n", ret);
		return ret;
	}

	/* Set the frequency of the DLL operation */

Annotation

Implementation Notes