drivers/clk/keystone/pll.c

Source file repositories/reference/linux-study-clean/drivers/clk/keystone/pll.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/keystone/pll.c
Extension
.c
Size
9187 bytes
Lines
345
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 clk_pll_data {
	bool has_pllctrl;
	u32 phy_pllm;
	u32 phy_pll_ctl0;
	void __iomem *pllm;
	void __iomem *pllod;
	void __iomem *pll_ctl0;
	u32 pllm_lower_mask;
	u32 pllm_upper_mask;
	u32 pllm_upper_shift;
	u32 plld_mask;
	u32 clkod_mask;
	u32 clkod_shift;
	u32 postdiv;
};

/**
 * struct clk_pll - Main pll clock
 * @hw: clk_hw for the pll
 * @pll_data: PLL driver specific data
 */
struct clk_pll {
	struct clk_hw hw;
	struct clk_pll_data *pll_data;
};

#define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw)

static unsigned long clk_pllclk_recalc(struct clk_hw *hw,
					unsigned long parent_rate)
{
	struct clk_pll *pll = to_clk_pll(hw);
	struct clk_pll_data *pll_data = pll->pll_data;
	unsigned long rate = parent_rate;
	u32  mult = 0, prediv, postdiv, val;

	/*
	 * get bits 0-5 of multiplier from pllctrl PLLM register
	 * if has_pllctrl is non zero
	 */
	if (pll_data->has_pllctrl) {
		val = readl(pll_data->pllm);
		mult = (val & pll_data->pllm_lower_mask);
	}

	/* bit6-12 of PLLM is in Main PLL control register */
	val = readl(pll_data->pll_ctl0);
	mult |= ((val & pll_data->pllm_upper_mask)
			>> pll_data->pllm_upper_shift);
	prediv = (val & pll_data->plld_mask);

	if (!pll_data->has_pllctrl)
		/* read post divider from od bits*/
		postdiv = ((val & pll_data->clkod_mask) >>
				 pll_data->clkod_shift) + 1;
	else if (pll_data->pllod) {
		postdiv = readl(pll_data->pllod);
		postdiv = ((postdiv & pll_data->clkod_mask) >>
				pll_data->clkod_shift) + 1;
	} else
		postdiv = pll_data->postdiv;

	rate /= (prediv + 1);
	rate = (rate * (mult + 1));
	rate /= postdiv;

	return rate;
}

static const struct clk_ops clk_pll_ops = {
	.recalc_rate = clk_pllclk_recalc,
};

static struct clk *clk_register_pll(struct device *dev,
			const char *name,
			const char *parent_name,
			struct clk_pll_data *pll_data)
{
	struct clk_init_data init;
	struct clk_pll *pll;
	struct clk *clk;

	pll = kzalloc_obj(*pll);
	if (!pll)
		return ERR_PTR(-ENOMEM);

	init.name = name;
	init.ops = &clk_pll_ops;
	init.flags = 0;
	init.parent_names = (parent_name ? &parent_name : NULL);

Annotation

Implementation Notes