drivers/phy/rockchip/phy-rockchip-emmc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/phy/rockchip/phy-rockchip-emmc.c
Extension
.c
Size
12491 bytes
Lines
428
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 rockchip_emmc_phy {
	unsigned int	reg_offset;
	struct regmap	*reg_base;
	struct clk	*emmcclk;
	unsigned int drive_impedance;
	unsigned int enable_strobe_pulldown;
	unsigned int output_tapdelay_select;
};

static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
{
	struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
	unsigned int caldone;
	unsigned int dllrdy;
	unsigned int freqsel = PHYCTRL_FREQSEL_200M;
	unsigned long rate;
	int ret;

	/*
	 * Keep phyctrl_pdb and phyctrl_endll low to allow
	 * initialization of CALIO state M/C DFFs
	 */
	regmap_write(rk_phy->reg_base,
		     rk_phy->reg_offset + GRF_EMMCPHY_CON6,
		     HIWORD_UPDATE(PHYCTRL_PDB_PWR_OFF,
				   PHYCTRL_PDB_MASK,
				   PHYCTRL_PDB_SHIFT));
	regmap_write(rk_phy->reg_base,
		     rk_phy->reg_offset + GRF_EMMCPHY_CON6,
		     HIWORD_UPDATE(PHYCTRL_ENDLL_DISABLE,
				   PHYCTRL_ENDLL_MASK,
				   PHYCTRL_ENDLL_SHIFT));

	/* Already finish power_off above */
	if (on_off == PHYCTRL_PDB_PWR_OFF)
		return 0;

	rate = clk_get_rate(rk_phy->emmcclk);

	if (rate != 0) {
		unsigned long ideal_rate;
		unsigned long diff;

		switch (rate) {
		case 1 ... 74999999:
			ideal_rate = 50000000;
			freqsel = PHYCTRL_FREQSEL_50M;
			break;
		case 75000000 ... 124999999:
			ideal_rate = 100000000;
			freqsel = PHYCTRL_FREQSEL_100M;
			break;
		case 125000000 ... 174999999:
			ideal_rate = 150000000;
			freqsel = PHYCTRL_FREQSEL_150M;
			break;
		default:
			ideal_rate = 200000000;
			break;
		}

		diff = (rate > ideal_rate) ?
			rate - ideal_rate : ideal_rate - rate;

		/*
		 * In order for tuning delays to be accurate we need to be
		 * pretty spot on for the DLL range, so warn if we're too
		 * far off.  Also warn if we're above the 200 MHz max.  Don't
		 * warn for really slow rates since we won't be tuning then.
		 */
		if ((rate > 50000000 && diff > 15000000) || (rate > 200000000))
			dev_warn(&phy->dev, "Unsupported rate: %lu\n", rate);
	}

	/*
	 * 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(3);
	regmap_write(rk_phy->reg_base,
		     rk_phy->reg_offset + GRF_EMMCPHY_CON6,
		     HIWORD_UPDATE(PHYCTRL_PDB_PWR_ON,
				   PHYCTRL_PDB_MASK,
				   PHYCTRL_PDB_SHIFT));

	/*
	 * 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

Annotation

Implementation Notes