drivers/clk/clk-npcm7xx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/clk-npcm7xx.c
Extension
.c
Size
15653 bytes
Lines
520
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 npcm7xx_clk_pll {
	struct clk_hw	hw;
	void __iomem	*pllcon;
	u8		flags;
};

#define to_npcm7xx_clk_pll(_hw) container_of(_hw, struct npcm7xx_clk_pll, hw)

#define PLLCON_LOKI	BIT(31)
#define PLLCON_LOKS	BIT(30)
#define PLLCON_FBDV	GENMASK(27, 16)
#define PLLCON_OTDV2	GENMASK(15, 13)
#define PLLCON_PWDEN	BIT(12)
#define PLLCON_OTDV1	GENMASK(10, 8)
#define PLLCON_INDV	GENMASK(5, 0)

static unsigned long npcm7xx_clk_pll_recalc_rate(struct clk_hw *hw,
						 unsigned long parent_rate)
{
	struct npcm7xx_clk_pll *pll = to_npcm7xx_clk_pll(hw);
	unsigned long fbdv, indv, otdv1, otdv2;
	unsigned int val;
	u64 ret;

	if (parent_rate == 0) {
		pr_err("%s: parent rate is zero", __func__);
		return 0;
	}

	val = readl_relaxed(pll->pllcon);

	indv = FIELD_GET(PLLCON_INDV, val);
	fbdv = FIELD_GET(PLLCON_FBDV, val);
	otdv1 = FIELD_GET(PLLCON_OTDV1, val);
	otdv2 = FIELD_GET(PLLCON_OTDV2, val);

	ret = (u64)parent_rate * fbdv;
	do_div(ret, indv * otdv1 * otdv2);

	return ret;
}

static const struct clk_ops npcm7xx_clk_pll_ops = {
	.recalc_rate = npcm7xx_clk_pll_recalc_rate,
};

static struct clk_hw *
npcm7xx_clk_register_pll(void __iomem *pllcon, const char *name,
			 const char *parent_name, unsigned long flags)
{
	struct npcm7xx_clk_pll *pll;
	struct clk_init_data init;
	struct clk_hw *hw;
	int ret;

	pll = kzalloc_obj(*pll);
	if (!pll)
		return ERR_PTR(-ENOMEM);

	pr_debug("%s reg, name=%s, p=%s\n", __func__, name, parent_name);

	init.name = name;
	init.ops = &npcm7xx_clk_pll_ops;
	init.parent_names = &parent_name;
	init.num_parents = 1;
	init.flags = flags;

	pll->pllcon = pllcon;
	pll->hw.init = &init;

	hw = &pll->hw;

	ret = clk_hw_register(NULL, hw);
	if (ret) {
		kfree(pll);
		hw = ERR_PTR(ret);
	}

	return hw;
}

#define NPCM7XX_CLKEN1          (0x00)
#define NPCM7XX_CLKEN2          (0x28)
#define NPCM7XX_CLKEN3          (0x30)
#define NPCM7XX_CLKSEL          (0x04)
#define NPCM7XX_CLKDIV1         (0x08)
#define NPCM7XX_CLKDIV2         (0x2C)
#define NPCM7XX_CLKDIV3         (0x58)
#define NPCM7XX_PLLCON0         (0x0C)
#define NPCM7XX_PLLCON1         (0x10)

Annotation

Implementation Notes