drivers/net/mdio/mdio-mux-meson-g12a.c

Source file repositories/reference/linux-study-clean/drivers/net/mdio/mdio-mux-meson-g12a.c

File Facts

System
Linux kernel
Corpus path
drivers/net/mdio/mdio-mux-meson-g12a.c
Extension
.c
Size
9021 bytes
Lines
362
Domain
Driver Families
Bucket
drivers/net
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 g12a_mdio_mux {
	void __iomem *regs;
	void *mux_handle;
	struct clk *pll;
};

struct g12a_ephy_pll {
	void __iomem *base;
	struct clk_hw hw;
};

#define g12a_ephy_pll_to_dev(_hw)			\
	container_of(_hw, struct g12a_ephy_pll, hw)

static unsigned long g12a_ephy_pll_recalc_rate(struct clk_hw *hw,
					       unsigned long parent_rate)
{
	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
	u32 val, m, n;

	val = readl(pll->base + ETH_PLL_CTL0);
	m = FIELD_GET(PLL_CTL0_M, val);
	n = FIELD_GET(PLL_CTL0_N, val);

	return parent_rate * m / n;
}

static int g12a_ephy_pll_enable(struct clk_hw *hw)
{
	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
	u32 val = readl(pll->base + ETH_PLL_CTL0);

	/* Apply both enable an reset */
	val |= PLL_CTL0_RST | PLL_CTL0_EN;
	writel(val, pll->base + ETH_PLL_CTL0);

	/* Clear the reset to let PLL lock */
	val &= ~PLL_CTL0_RST;
	writel(val, pll->base + ETH_PLL_CTL0);

	/* Poll on the digital lock instead of the usual analog lock
	 * This is done because bit 31 is unreliable on some SoC. Bit
	 * 31 may indicate that the PLL is not lock even though the clock
	 * is actually running
	 */
	return readl_poll_timeout(pll->base + ETH_PLL_CTL0, val,
				  val & PLL_CTL0_LOCK_DIG, 0, PLL_LOCK_TIMEOUT);
}

static void g12a_ephy_pll_disable(struct clk_hw *hw)
{
	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
	u32 val;

	val = readl(pll->base + ETH_PLL_CTL0);
	val &= ~PLL_CTL0_EN;
	val |= PLL_CTL0_RST;
	writel(val, pll->base + ETH_PLL_CTL0);
}

static int g12a_ephy_pll_is_enabled(struct clk_hw *hw)
{
	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
	unsigned int val;

	val = readl(pll->base + ETH_PLL_CTL0);

	return (val & PLL_CTL0_LOCK_DIG) ? 1 : 0;
}

static int g12a_ephy_pll_init(struct clk_hw *hw)
{
	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);

	/* Apply PLL HW settings */
	writel(0x29c0040a, pll->base + ETH_PLL_CTL0);
	writel(0x927e0000, pll->base + ETH_PLL_CTL1);
	writel(0xac5f49e5, pll->base + ETH_PLL_CTL2);
	writel(0x00000000, pll->base + ETH_PLL_CTL3);
	writel(0x00000000, pll->base + ETH_PLL_CTL4);
	writel(0x20200000, pll->base + ETH_PLL_CTL5);
	writel(0x0000c002, pll->base + ETH_PLL_CTL6);
	writel(0x00000023, pll->base + ETH_PLL_CTL7);

	return 0;
}

static const struct clk_ops g12a_ephy_pll_ops = {
	.recalc_rate	= g12a_ephy_pll_recalc_rate,
	.is_enabled	= g12a_ephy_pll_is_enabled,

Annotation

Implementation Notes