drivers/clk/imx/clk-pfdv2.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/imx/clk-pfdv2.c
Extension
.c
Size
5142 bytes
Lines
243
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

struct clk_pfdv2 {
	struct clk_hw	hw;
	void __iomem	*reg;
	u8		gate_bit;
	u8		vld_bit;
	u8		frac_off;
};

#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw)

#define CLK_PFDV2_FRAC_MASK 0x3f

#define LOCK_TIMEOUT_US		USEC_PER_MSEC

static DEFINE_SPINLOCK(pfd_lock);

static int clk_pfdv2_wait(struct clk_pfdv2 *pfd)
{
	u32 val;

	return readl_poll_timeout(pfd->reg, val, val & (1 << pfd->vld_bit),
				  0, LOCK_TIMEOUT_US);
}

static int clk_pfdv2_enable(struct clk_hw *hw)
{
	struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
	unsigned long flags;
	u32 val;

	spin_lock_irqsave(&pfd_lock, flags);
	val = readl_relaxed(pfd->reg);
	val &= ~(1 << pfd->gate_bit);
	writel_relaxed(val, pfd->reg);
	spin_unlock_irqrestore(&pfd_lock, flags);

	return clk_pfdv2_wait(pfd);
}

static void clk_pfdv2_disable(struct clk_hw *hw)
{
	struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
	unsigned long flags;
	u32 val;

	spin_lock_irqsave(&pfd_lock, flags);
	val = readl_relaxed(pfd->reg);
	val |= (1 << pfd->gate_bit);
	writel_relaxed(val, pfd->reg);
	spin_unlock_irqrestore(&pfd_lock, flags);
}

static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw,
					   unsigned long parent_rate)
{
	struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
	u64 tmp = parent_rate;
	u8 frac;

	frac = (readl_relaxed(pfd->reg) >> pfd->frac_off)
		& CLK_PFDV2_FRAC_MASK;

	if (!frac) {
		pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n",
			 clk_hw_get_name(hw));
		return 0;
	}

	tmp *= 18;
	do_div(tmp, frac);

	return tmp;
}

static int clk_pfdv2_determine_rate(struct clk_hw *hw,
				    struct clk_rate_request *req)
{
	unsigned long parent_rates[] = {
					480000000,
					528000000,
					req->best_parent_rate
				       };
	unsigned long best_rate = -1UL, rate = req->rate;
	unsigned long best_parent_rate = req->best_parent_rate;
	u64 tmp;
	u8 frac;
	int i;

	for (i = 0; i < ARRAY_SIZE(parent_rates); i++) {
		tmp = parent_rates[i];

Annotation

Implementation Notes