drivers/clk/bcm/clk-iproc-pll.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/bcm/clk-iproc-pll.c
Extension
.c
Size
22038 bytes
Lines
864
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 iproc_pll {
	void __iomem *status_base;
	void __iomem *control_base;
	void __iomem *pwr_base;
	void __iomem *asiu_base;

	const struct iproc_pll_ctrl *ctrl;
	const struct iproc_pll_vco_param *vco_param;
	unsigned int num_vco_entries;
};

struct iproc_clk {
	struct clk_hw hw;
	struct iproc_pll *pll;
	const struct iproc_clk_ctrl *ctrl;
};

#define to_iproc_clk(hw) container_of(hw, struct iproc_clk, hw)

static int pll_calc_param(unsigned long target_rate,
			unsigned long parent_rate,
			struct iproc_pll_vco_param *vco_out)
{
	u64 ndiv_int, ndiv_frac, residual;

	ndiv_int = target_rate / parent_rate;

	if (!ndiv_int || (ndiv_int > 255))
		return -EINVAL;

	residual = target_rate - (ndiv_int * parent_rate);
	residual <<= 20;

	/*
	 * Add half of the divisor so the result will be rounded to closest
	 * instead of rounded down.
	 */
	residual += (parent_rate / 2);
	ndiv_frac = div64_u64((u64)residual, (u64)parent_rate);

	vco_out->ndiv_int = ndiv_int;
	vco_out->ndiv_frac = ndiv_frac;
	vco_out->pdiv = 1;

	vco_out->rate = vco_out->ndiv_int * parent_rate;
	residual = (u64)vco_out->ndiv_frac * (u64)parent_rate;
	residual >>= 20;
	vco_out->rate += residual;

	return 0;
}

/*
 * Based on the target frequency, find a match from the VCO frequency parameter
 * table and return its index
 */
static int pll_get_rate_index(struct iproc_pll *pll, unsigned int target_rate)
{
	int i;

	for (i = 0; i < pll->num_vco_entries; i++)
		if (target_rate == pll->vco_param[i].rate)
			break;

	if (i >= pll->num_vco_entries)
		return -EINVAL;

	return i;
}

static int get_kp(unsigned long ref_freq, enum kp_band kp_index)
{
	int i;

	if (ref_freq < ref_freq_table[0][0])
		return -EINVAL;

	for (i = 0; i < NUM_FREQ_BANDS; i++) {
		if (ref_freq >= ref_freq_table[i][0] &&
		    ref_freq < ref_freq_table[i][1])
			return kp_table[kp_index][i];
	}
	return -EINVAL;
}

static int pll_wait_for_lock(struct iproc_pll *pll)
{
	int i;
	const struct iproc_pll_ctrl *ctrl = pll->ctrl;

Annotation

Implementation Notes