drivers/clk/clk-divider.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/clk-divider.c
Extension
.c
Size
16282 bytes
Lines
631
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

if (rate * i == parent_rate_saved) {
			/*
			 * It's the most ideal case if the requested rate can be
			 * divided from parent clock without needing to change
			 * parent rate, so return the divider immediately.
			 */
			*best_parent_rate = parent_rate_saved;
			return i;
		}
		parent_rate = clk_hw_round_rate(parent, rate * i);
		now = DIV_ROUND_UP_ULL((u64)parent_rate, i);
		if (_is_best_div(rate, now, best, flags)) {
			bestdiv = i;
			best = now;
			*best_parent_rate = parent_rate;
		}
	}

	if (!bestdiv) {
		bestdiv = _get_maxdiv(table, width, flags);
		*best_parent_rate = clk_hw_round_rate(parent, 1);
	}

	return bestdiv;
}

int divider_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
			   const struct clk_div_table *table, u8 width,
			   unsigned long flags)
{
	int div;

	div = clk_divider_bestdiv(hw, req->best_parent_hw, req->rate,
				  &req->best_parent_rate, table, width, flags);

	req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);

	return 0;
}
EXPORT_SYMBOL_GPL(divider_determine_rate);

int divider_ro_determine_rate(struct clk_hw *hw, struct clk_rate_request *req,
			      const struct clk_div_table *table, u8 width,
			      unsigned long flags, unsigned int val)
{
	int div;

	div = _get_div(table, val, flags, width);

	/* Even a read-only clock can propagate a rate change */
	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
		if (!req->best_parent_hw)
			return -EINVAL;

		req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw,
							  req->rate * div);
	}

	req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);

	return 0;
}
EXPORT_SYMBOL_GPL(divider_ro_determine_rate);

static int clk_divider_determine_rate(struct clk_hw *hw,
				      struct clk_rate_request *req)
{
	struct clk_divider *divider = to_clk_divider(hw);

	/* if read only, just return current value */
	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
		u32 val;

		val = clk_div_readl(divider) >> divider->shift;
		val &= clk_div_mask(divider->width);

		return divider_ro_determine_rate(hw, req, divider->table,
						 divider->width,
						 divider->flags, val);
	}

	return divider_determine_rate(hw, req, divider->table, divider->width,
				      divider->flags);
}

int divider_get_val(unsigned long rate, unsigned long parent_rate,
		    const struct clk_div_table *table, u8 width,
		    unsigned long flags)
{
	unsigned int div, value;

Annotation

Implementation Notes