drivers/phy/cadence/cdns-dphy.c

Source file repositories/reference/linux-study-clean/drivers/phy/cadence/cdns-dphy.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/cadence/cdns-dphy.c
Extension
.c
Size
14688 bytes
Lines
544
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 cdns_dphy_cfg {
	u8 pll_ipdiv;
	u8 pll_opdiv;
	u16 pll_fbdiv;
	u32 hs_clk_rate;
	unsigned int nlanes;
};

enum cdns_dphy_clk_lane_cfg {
	DPHY_CLK_CFG_LEFT_DRIVES_ALL = 0,
	DPHY_CLK_CFG_LEFT_DRIVES_RIGHT = 1,
	DPHY_CLK_CFG_LEFT_DRIVES_LEFT = 2,
	DPHY_CLK_CFG_RIGHT_DRIVES_ALL = 3,
};

struct cdns_dphy;
struct cdns_dphy_ops {
	int (*probe)(struct cdns_dphy *dphy);
	void (*remove)(struct cdns_dphy *dphy);
	void (*set_psm_div)(struct cdns_dphy *dphy, u8 div);
	void (*set_clk_lane_cfg)(struct cdns_dphy *dphy,
				 enum cdns_dphy_clk_lane_cfg cfg);
	void (*set_pll_cfg)(struct cdns_dphy *dphy,
			    const struct cdns_dphy_cfg *cfg);
	unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy);
	int (*wait_for_pll_lock)(struct cdns_dphy *dphy);
	int (*wait_for_cmn_ready)(struct cdns_dphy *dphy);
};

struct cdns_dphy {
	struct cdns_dphy_cfg cfg;
	void __iomem *regs;
	struct clk *psm_clk;
	struct clk *pll_ref_clk;
	const struct cdns_dphy_ops *ops;
	struct phy *phy;
	bool is_configured;
	bool is_powered;
};

/* Order of bands is important since the index is the band number. */
static const unsigned int tx_bands[] = {
	80, 100, 120, 160, 200, 240, 320, 390, 450, 510, 560, 640, 690, 770,
	870, 950, 1000, 1200, 1400, 1600, 1800, 2000, 2200, 2500
};

static int cdns_dphy_get_pll_cfg(struct cdns_dphy *dphy,
				 struct cdns_dphy_cfg *cfg,
				 struct phy_configure_opts_mipi_dphy *opts)
{
	unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk);
	u64 dlane_bps;

	memset(cfg, 0, sizeof(*cfg));

	if (pll_ref_hz < 9600000 || pll_ref_hz >= 150000000)
		return -EINVAL;
	else if (pll_ref_hz < 19200000)
		cfg->pll_ipdiv = 1;
	else if (pll_ref_hz < 38400000)
		cfg->pll_ipdiv = 2;
	else if (pll_ref_hz < 76800000)
		cfg->pll_ipdiv = 4;
	else
		cfg->pll_ipdiv = 8;

	dlane_bps = opts->hs_clk_rate;

	if (dlane_bps > 2500000000UL || dlane_bps < 80000000UL)
		return -EINVAL;
	else if (dlane_bps >= 1250000000)
		cfg->pll_opdiv = 1;
	else if (dlane_bps >= 630000000)
		cfg->pll_opdiv = 2;
	else if (dlane_bps >= 320000000)
		cfg->pll_opdiv = 4;
	else if (dlane_bps >= 160000000)
		cfg->pll_opdiv = 8;
	else if (dlane_bps >= 80000000)
		cfg->pll_opdiv = 16;

	cfg->pll_fbdiv = DIV_ROUND_UP_ULL(dlane_bps * 2 * cfg->pll_opdiv *
					  cfg->pll_ipdiv,
					  pll_ref_hz);

	cfg->hs_clk_rate = div_u64((u64)pll_ref_hz * cfg->pll_fbdiv,
				   2 * cfg->pll_opdiv * cfg->pll_ipdiv);

	return 0;
}

Annotation

Implementation Notes