drivers/clk/sophgo/clk-cv18xx-pll.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/sophgo/clk-cv18xx-pll.c
Extension
.c
Size
10331 bytes
Lines
420
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

for_each_pll_limit_range(div, &limit->div) {
			for_each_pll_limit_range(post, &limit->post_div) {
				tmp = ipll_calc_rate(prate, pre, div, post);

				if (tmp > trate)
					continue;

				if ((trate - tmp) < (trate - best_rate)) {
					best_rate = tmp;
					pre_div_sel = pre;
					div_sel = div;
					post_div_sel = post;
				}
			}
		}
	}

	if (best_rate) {
		detected = PLL_SET_PRE_DIV_SEL(detected, pre_div_sel);
		detected = PLL_SET_POST_DIV_SEL(detected, post_div_sel);
		detected = PLL_SET_DIV_SEL(detected, div_sel);
		*value = detected;
		*rate = best_rate;
		return 0;
	}

	return -EINVAL;
}

static int ipll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
	u32 val;
	struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);

	return ipll_find_rate(pll->pll_limit, req->best_parent_rate,
			      &req->rate, &val);
}

static void pll_get_mode_ctrl(unsigned long div_sel,
			      bool (*mode_ctrl_check)(unsigned long,
						      unsigned long,
						      unsigned long),
			      const struct cv1800_clk_pll_limit *limit,
			      u32 *value)
{
	unsigned long ictrl = 0, mode = 0;
	u32 detected = *value;

	for_each_pll_limit_range(mode, &limit->mode) {
		for_each_pll_limit_range(ictrl, &limit->ictrl) {
			if (mode_ctrl_check(div_sel, ictrl, mode)) {
				detected = PLL_SET_SEL_MODE(detected, mode);
				detected = PLL_SET_ICTRL(detected, ictrl);
				*value = detected;
				return;
			}
		}
	}
}

static bool ipll_check_mode_ctrl_restrict(unsigned long div_sel,
					  unsigned long ictrl,
					  unsigned long mode)
{
	unsigned long left_rest = 20 * div_sel;
	unsigned long right_rest = 35 * div_sel;
	unsigned long test = 184 * (1 + mode) * (1 + ictrl) / 2;

	return test > left_rest && test <= right_rest;
}

static int ipll_set_rate(struct clk_hw *hw, unsigned long rate,
			 unsigned long parent_rate)
{
	u32 regval, detected = 0;
	unsigned long flags;
	struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw);

	ipll_find_rate(pll->pll_limit, parent_rate, &rate, &detected);
	pll_get_mode_ctrl(PLL_GET_DIV_SEL(detected),
			  ipll_check_mode_ctrl_restrict,
			  pll->pll_limit, &detected);

	spin_lock_irqsave(pll->common.lock, flags);

	regval = readl(pll->common.base + pll->pll_reg);
	regval = PLL_COPY_REG(regval, detected);

	writel(regval, pll->common.base + pll->pll_reg);

Annotation

Implementation Notes