drivers/clk/berlin/berlin2-avpll.c

Source file repositories/reference/linux-study-clean/drivers/clk/berlin/berlin2-avpll.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/berlin/berlin2-avpll.c
Extension
.c
Size
10755 bytes
Lines
383
Domain
Driver Families
Bucket
drivers/clk
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 berlin2_avpll_vco {
	struct clk_hw hw;
	void __iomem *base;
	u8 flags;
};

#define to_avpll_vco(hw) container_of(hw, struct berlin2_avpll_vco, hw)

static int berlin2_avpll_vco_is_enabled(struct clk_hw *hw)
{
	struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
	u32 reg;

	reg = readl_relaxed(vco->base + VCO_CTRL0);
	if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK)
		reg >>= 4;

	return !!(reg & VCO_POWERUP);
}

static int berlin2_avpll_vco_enable(struct clk_hw *hw)
{
	struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
	u32 reg;

	reg = readl_relaxed(vco->base + VCO_CTRL0);
	if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK)
		reg |= VCO_POWERUP << 4;
	else
		reg |= VCO_POWERUP;
	writel_relaxed(reg, vco->base + VCO_CTRL0);

	return 0;
}

static void berlin2_avpll_vco_disable(struct clk_hw *hw)
{
	struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
	u32 reg;

	reg = readl_relaxed(vco->base + VCO_CTRL0);
	if (vco->flags & BERLIN2_AVPLL_BIT_QUIRK)
		reg &= ~(VCO_POWERUP << 4);
	else
		reg &= ~VCO_POWERUP;
	writel_relaxed(reg, vco->base + VCO_CTRL0);
}

static u8 vco_refdiv[] = { 1, 2, 4, 3 };

static unsigned long
berlin2_avpll_vco_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
	struct berlin2_avpll_vco *vco = to_avpll_vco(hw);
	u32 reg, refdiv, fbdiv;
	u64 freq = parent_rate;

	/* AVPLL VCO frequency: Fvco = (Fref / refdiv) * fbdiv */
	reg = readl_relaxed(vco->base + VCO_CTRL1);
	refdiv = (reg & VCO_REFDIV_MASK) >> VCO_REFDIV_SHIFT;
	refdiv = vco_refdiv[refdiv];
	fbdiv = (reg & VCO_FBDIV_MASK) >> VCO_FBDIV_SHIFT;
	freq *= fbdiv;
	do_div(freq, refdiv);

	return (unsigned long)freq;
}

static const struct clk_ops berlin2_avpll_vco_ops = {
	.is_enabled	= berlin2_avpll_vco_is_enabled,
	.enable		= berlin2_avpll_vco_enable,
	.disable	= berlin2_avpll_vco_disable,
	.recalc_rate	= berlin2_avpll_vco_recalc_rate,
};

int __init berlin2_avpll_vco_register(void __iomem *base,
			       const char *name, const char *parent_name,
			       u8 vco_flags, unsigned long flags)
{
	struct berlin2_avpll_vco *vco;
	struct clk_init_data init;

	vco = kzalloc_obj(*vco);
	if (!vco)
		return -ENOMEM;

	vco->base = base;
	vco->flags = vco_flags;
	vco->hw.init = &init;
	init.name = name;

Annotation

Implementation Notes