drivers/clk/sunxi/clk-factors.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/sunxi/clk-factors.c
Extension
.c
Size
7829 bytes
Lines
305
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

if (child_rate <= req->rate && child_rate > best_child_rate) {
			best_parent = parent;
			best = parent_rate;
			best_child_rate = child_rate;
		}
	}

	if (!best_parent)
		return -EINVAL;

	req->best_parent_hw = best_parent;
	req->best_parent_rate = best;
	req->rate = best_child_rate;

	return 0;
}

static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
				unsigned long parent_rate)
{
	struct factors_request req = {
		.rate = rate,
		.parent_rate = parent_rate,
	};
	u32 reg;
	struct clk_factors *factors = to_clk_factors(hw);
	const struct clk_factors_config *config = factors->config;
	unsigned long flags = 0;

	factors->get_factors(&req);

	if (factors->lock)
		spin_lock_irqsave(factors->lock, flags);

	/* Fetch the register value */
	reg = readl(factors->reg);

	/* Set up the new factors - macros do not do anything if width is 0 */
	reg = FACTOR_SET(config->nshift, config->nwidth, reg, req.n);
	reg = FACTOR_SET(config->kshift, config->kwidth, reg, req.k);
	reg = FACTOR_SET(config->mshift, config->mwidth, reg, req.m);
	reg = FACTOR_SET(config->pshift, config->pwidth, reg, req.p);

	/* Apply them now */
	writel(reg, factors->reg);

	/* delay 500us so pll stabilizes */
	__delay((rate >> 20) * 500 / 2);

	if (factors->lock)
		spin_unlock_irqrestore(factors->lock, flags);

	return 0;
}

static const struct clk_ops clk_factors_ops = {
	.determine_rate = clk_factors_determine_rate,
	.recalc_rate = clk_factors_recalc_rate,
	.set_rate = clk_factors_set_rate,
};

static struct clk *__sunxi_factors_register(struct device_node *node,
					    const struct factors_data *data,
					    spinlock_t *lock, void __iomem *reg,
					    unsigned long flags)
{
	struct clk *clk;
	struct clk_factors *factors;
	struct clk_gate *gate = NULL;
	struct clk_mux *mux = NULL;
	struct clk_hw *gate_hw = NULL;
	struct clk_hw *mux_hw = NULL;
	const char *clk_name = node->name;
	const char *parents[FACTORS_MAX_PARENTS];
	int ret, i = 0;

	/* if we have a mux, we will have >1 parents */
	i = of_clk_parent_fill(node, parents, FACTORS_MAX_PARENTS);

	/*
	 * some factor clocks, such as pll5 and pll6, may have multiple
	 * outputs, and have their name designated in factors_data
	 */
	if (data->name)
		clk_name = data->name;
	else
		of_property_read_string(node, "clock-output-names", &clk_name);

	factors = kzalloc_obj(struct clk_factors);
	if (!factors)

Annotation

Implementation Notes