drivers/clk/imx/clk-pllv4.c

Source file repositories/reference/linux-study-clean/drivers/clk/imx/clk-pllv4.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/imx/clk-pllv4.c
Extension
.c
Size
6443 bytes
Lines
291
Domain
Driver Families
Bucket
drivers/clk
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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_pllv4 {
	struct clk_hw	hw;
	void __iomem	*base;
	u32		cfg_offset;
	u32		num_offset;
	u32		denom_offset;
	bool		use_mult_range;
};

/* Valid PLL MULT Table */
static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16};

/* Valid PLL MULT range, (max, min) */
static const int pllv4_mult_range[] = {54, 27};

#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw)

#define LOCK_TIMEOUT_US		USEC_PER_MSEC

static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll)
{
	u32 csr;

	return readl_poll_timeout(pll->base  + PLL_CSR_OFFSET,
				  csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US);
}

static int clk_pllv4_is_prepared(struct clk_hw *hw)
{
	struct clk_pllv4 *pll = to_clk_pllv4(hw);

	if (readl_relaxed(pll->base) & PLL_EN)
		return 1;

	return 0;
}

static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw,
					   unsigned long parent_rate)
{
	struct clk_pllv4 *pll = to_clk_pllv4(hw);
	u32 mult, mfn, mfd;
	u64 temp64;

	mult = readl_relaxed(pll->base + pll->cfg_offset);
	mult &= BM_PLL_MULT;
	mult >>= BP_PLL_MULT;

	mfn = readl_relaxed(pll->base + pll->num_offset);
	mfd = readl_relaxed(pll->base + pll->denom_offset);
	temp64 = parent_rate;
	temp64 *= mfn;
	do_div(temp64, mfd);

	return (parent_rate * mult) + (u32)temp64;
}

static int clk_pllv4_determine_rate(struct clk_hw *hw,
				    struct clk_rate_request *req)
{
	struct clk_pllv4 *pll = to_clk_pllv4(hw);
	unsigned long parent_rate = req->best_parent_rate;
	unsigned long round_rate, i;
	u32 mfn, mfd = DEFAULT_MFD;
	bool found = false;
	u64 temp64;
	u32 mult;

	if (pll->use_mult_range) {
		temp64 = (u64) req->rate;
		do_div(temp64, parent_rate);
		mult = temp64;
		if (mult >= pllv4_mult_range[1] &&
		    mult <= pllv4_mult_range[0]) {
			round_rate = parent_rate * mult;
			found = true;
		}
	} else {
		for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
			round_rate = parent_rate * pllv4_mult_table[i];
			if (req->rate >= round_rate) {
				found = true;
				break;
			}
		}
	}

	if (!found) {
		pr_warn("%s: unable to round rate %lu, parent rate %lu\n",
			clk_hw_get_name(hw), req->rate, parent_rate);

Annotation

Implementation Notes