drivers/clk/xilinx/clk-xlnx-clock-wizard.c

Source file repositories/reference/linux-study-clean/drivers/clk/xilinx/clk-xlnx-clock-wizard.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/xilinx/clk-xlnx-clock-wizard.c
Extension
.c
Size
35423 bytes
Lines
1254
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 clk_wzrd {
	struct notifier_block nb;
	void __iomem *base;
	struct clk *clk_in1;
	struct clk *axi_clk;
	struct clk_hw *clks_internal[wzrd_clk_int_max];
	unsigned int speed_grade;
	bool suspended;
	struct clk_hw_onecell_data clk_data;
};

/**
 * struct clk_wzrd_divider - clock divider specific to clk_wzrd
 *
 * @hw:		handle between common and hardware-specific interfaces
 * @base:	base address of register containing the divider
 * @offset:	offset address of register containing the divider
 * @shift:	shift to the divider bit field
 * @width:	width of the divider bit field
 * @flags:	clk_wzrd divider flags
 * @table:	array of value/divider pairs, last entry should have div = 0
 * @m:	value of the multiplier
 * @m_frac:	fractional value of the multiplier
 * @d:	value of the common divider
 * @o:	value of the leaf divider
 * @o_frac:	value of the fractional leaf divider
 * @lock:	register lock
 */
struct clk_wzrd_divider {
	struct clk_hw hw;
	void __iomem *base;
	u16 offset;
	u8 shift;
	u8 width;
	u8 flags;
	const struct clk_div_table *table;
	u32 m;
	u32 m_frac;
	u32 d;
	u32 o;
	u32 o_frac;
	spinlock_t *lock;  /* divider lock */
};

struct versal_clk_data {
	bool is_versal;
};

#define to_clk_wzrd(_nb) container_of(_nb, struct clk_wzrd, nb)

/* maximum frequencies for input/output clocks per speed grade */
static const unsigned long clk_wzrd_max_freq[] = {
	800000000UL,
	933000000UL,
	1066000000UL
};

/* spin lock variable for clk_wzrd */
static DEFINE_SPINLOCK(clkwzrd_lock);

static unsigned long clk_wzrd_recalc_rate_ver(struct clk_hw *hw,
					      unsigned long parent_rate)
{
	struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
	void __iomem *div_addr = divider->base + divider->offset;
	u32 div, p5en, edge, prediv2, all;
	unsigned int vall, valh;

	edge = !!(readl(div_addr) & WZRD_CLKFBOUT_EDGE);
	p5en = !!(readl(div_addr) & WZRD_P5EN);
	prediv2 = !!(readl(div_addr) & WZRD_CLKOUT0_PREDIV2);
	vall = readl(div_addr + 4) & WZRD_CLKFBOUT_L_MASK;
	valh = readl(div_addr + 4) >> WZRD_CLKFBOUT_H_SHIFT;
	all = valh + vall + edge;
	if (!all)
		all = 1;

	if (prediv2)
		div = 2 * all + prediv2 * p5en;
	else
		div = all;

	return DIV_ROUND_UP_ULL((u64)parent_rate, div);
}

static unsigned long clk_wzrd_recalc_rate(struct clk_hw *hw,
					  unsigned long parent_rate)
{
	struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
	void __iomem *div_addr = divider->base + divider->offset;

Annotation

Implementation Notes