drivers/clk/meson/sclk-div.c

Source file repositories/reference/linux-study-clean/drivers/clk/meson/sclk-div.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/meson/sclk-div.c
Extension
.c
Size
6242 bytes
Lines
261
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 (abs(rate - now) < abs(rate - best)) {
			bestdiv = i;
			best = now;
			best_parent = parent_now;
		}
	}

	if (!bestdiv)
		bestdiv = sclk_div_maxdiv(sclk);
	else
		*prate = best_parent;

	return bestdiv;
}

static int sclk_div_determine_rate(struct clk_hw *hw,
				   struct clk_rate_request *req)
{
	struct clk_regmap *clk = to_clk_regmap(hw);
	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
	int div;

	div = sclk_div_bestdiv(hw, req->rate, &req->best_parent_rate, sclk);
	req->rate = DIV_ROUND_UP_ULL((u64)req->best_parent_rate, div);

	return 0;
}

static void sclk_apply_ratio(struct clk_regmap *clk,
			     struct meson_sclk_div_data *sclk)
{
	unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div *
					    sclk->cached_duty.num,
					    sclk->cached_duty.den);

	if (hi)
		hi -= 1;

	meson_parm_write(clk->map, &sclk->hi, hi);
}

static int sclk_div_set_duty_cycle(struct clk_hw *hw,
				   struct clk_duty *duty)
{
	struct clk_regmap *clk = to_clk_regmap(hw);
	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);

	if (MESON_PARM_APPLICABLE(&sclk->hi)) {
		memcpy(&sclk->cached_duty, duty, sizeof(*duty));
		sclk_apply_ratio(clk, sclk);
	}

	return 0;
}

static int sclk_div_get_duty_cycle(struct clk_hw *hw,
				   struct clk_duty *duty)
{
	struct clk_regmap *clk = to_clk_regmap(hw);
	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
	int hi;

	if (!MESON_PARM_APPLICABLE(&sclk->hi)) {
		duty->num = 1;
		duty->den = 2;
		return 0;
	}

	hi = meson_parm_read(clk->map, &sclk->hi);
	duty->num = hi + 1;
	duty->den = sclk->cached_div;
	return 0;
}

static void sclk_apply_divider(struct clk_regmap *clk,
			       struct meson_sclk_div_data *sclk)
{
	if (MESON_PARM_APPLICABLE(&sclk->hi))
		sclk_apply_ratio(clk, sclk);

	meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1);
}

static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
			     unsigned long prate)
{
	struct clk_regmap *clk = to_clk_regmap(hw);
	struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
	unsigned long maxdiv = sclk_div_maxdiv(sclk);

Annotation

Implementation Notes