drivers/clk/clk-loongson1.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/clk-loongson1.c
Extension
.c
Size
8007 bytes
Lines
303
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 ls1x_clk_pll_data {
	u32 fixed;
	u8 shift;
	u8 int_shift;
	u8 int_width;
	u8 frac_shift;
	u8 frac_width;
};

struct ls1x_clk_div_data {
	u8 shift;
	u8 width;
	unsigned long flags;
	const struct clk_div_table *table;
	u8 bypass_shift;
	u8 bypass_inv;
	spinlock_t *lock;	/* protect access to DIV registers */
};

struct ls1x_clk {
	void __iomem *reg;
	unsigned int offset;
	struct clk_hw hw;
	const void *data;
};

#define to_ls1x_clk(_hw) container_of(_hw, struct ls1x_clk, hw)

static inline unsigned long ls1x_pll_rate_part(unsigned int val,
					       unsigned int shift,
					       unsigned int width)
{
	return (val & GENMASK(shift + width, shift)) >> shift;
}

static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw,
					  unsigned long parent_rate)
{
	struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw);
	const struct ls1x_clk_pll_data *d = ls1x_clk->data;
	u32 val, rate;

	val = readl(ls1x_clk->reg);
	rate = d->fixed;
	rate += ls1x_pll_rate_part(val, d->int_shift, d->int_width);
	if (d->frac_width)
		rate += ls1x_pll_rate_part(val, d->frac_shift, d->frac_width);
	rate *= parent_rate;
	rate >>= d->shift;

	return rate;
}

static const struct clk_ops ls1x_pll_clk_ops = {
	.recalc_rate = ls1x_pll_recalc_rate,
};

static unsigned long ls1x_divider_recalc_rate(struct clk_hw *hw,
					      unsigned long parent_rate)
{
	struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw);
	const struct ls1x_clk_div_data *d = ls1x_clk->data;
	unsigned int val;

	val = readl(ls1x_clk->reg) >> d->shift;
	val &= clk_div_mask(d->width);

	return divider_recalc_rate(hw, parent_rate, val, d->table,
				   d->flags, d->width);
}

static int ls1x_divider_determine_rate(struct clk_hw *hw,
				       struct clk_rate_request *req)
{
	struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw);
	const struct ls1x_clk_div_data *d = ls1x_clk->data;

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

static int ls1x_divider_set_rate(struct clk_hw *hw, unsigned long rate,
				 unsigned long parent_rate)
{
	struct ls1x_clk *ls1x_clk = to_ls1x_clk(hw);
	const struct ls1x_clk_div_data *d = ls1x_clk->data;
	int val, div_val;
	unsigned long flags = 0;

	div_val = divider_get_val(rate, parent_rate, d->table,
				  d->width, d->flags);

Annotation

Implementation Notes