drivers/clk/sophgo/clk-sg2042-pll.c

Source file repositories/reference/linux-study-clean/drivers/clk/sophgo/clk-sg2042-pll.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/sophgo/clk-sg2042-pll.c
Extension
.c
Size
15160 bytes
Lines
560
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 sg2042_pll_clock {
	struct clk_hw hw;

	unsigned int id;
	void __iomem *base;
	/* protect register access */
	spinlock_t *lock;

	u32 offset_ctrl;
	u8 shift_status_lock;
	u8 shift_status_updating;
	u8 shift_enable;
};

#define to_sg2042_pll_clk(_hw) container_of(_hw, struct sg2042_pll_clock, hw)

#define KHZ 1000UL
#define MHZ (KHZ * KHZ)

#define REFDIV_MIN 1
#define REFDIV_MAX 63
#define FBDIV_MIN 16
#define FBDIV_MAX 320

#define PLL_FREF_SG2042 (25 * MHZ)

#define PLL_FOUTPOSTDIV_MIN (16 * MHZ)
#define PLL_FOUTPOSTDIV_MAX (3200 * MHZ)

#define PLL_FOUTVCO_MIN (800 * MHZ)
#define PLL_FOUTVCO_MAX (3200 * MHZ)

struct sg2042_pll_ctrl {
	unsigned long freq;
	unsigned int fbdiv;
	unsigned int postdiv1;
	unsigned int postdiv2;
	unsigned int refdiv;
};

#define PLLCTRL_FBDIV_MASK	GENMASK(27, 16)
#define PLLCTRL_POSTDIV2_MASK	GENMASK(14, 12)
#define PLLCTRL_POSTDIV1_MASK	GENMASK(10, 8)
#define PLLCTRL_REFDIV_MASK	GENMASK(5, 0)

static inline u32 sg2042_pll_ctrl_encode(struct sg2042_pll_ctrl *ctrl)
{
	return FIELD_PREP(PLLCTRL_FBDIV_MASK, ctrl->fbdiv) |
	       FIELD_PREP(PLLCTRL_POSTDIV2_MASK, ctrl->postdiv2) |
	       FIELD_PREP(PLLCTRL_POSTDIV1_MASK, ctrl->postdiv1) |
	       FIELD_PREP(PLLCTRL_REFDIV_MASK, ctrl->refdiv);
}

static inline void sg2042_pll_ctrl_decode(unsigned int reg_value,
					  struct sg2042_pll_ctrl *ctrl)
{
	ctrl->fbdiv = FIELD_GET(PLLCTRL_FBDIV_MASK, reg_value);
	ctrl->refdiv = FIELD_GET(PLLCTRL_REFDIV_MASK, reg_value);
	ctrl->postdiv1 = FIELD_GET(PLLCTRL_POSTDIV1_MASK, reg_value);
	ctrl->postdiv2 = FIELD_GET(PLLCTRL_POSTDIV2_MASK, reg_value);
}

static inline void sg2042_pll_enable(struct sg2042_pll_clock *pll, bool en)
{
	u32 value;

	if (en) {
		/* wait pll lock */
		if (readl_poll_timeout_atomic(pll->base + R_PLL_STAT,
					      value,
					      ((value >> pll->shift_status_lock) & 0x1),
					      0,
					      100000))
			pr_warn("%s not locked\n", pll->hw.init->name);

		/* wait pll updating */
		if (readl_poll_timeout_atomic(pll->base + R_PLL_STAT,
					      value,
					      !((value >> pll->shift_status_updating) & 0x1),
					      0,
					      100000))
			pr_warn("%s still updating\n", pll->hw.init->name);

		/* enable pll */
		value = readl(pll->base + R_PLL_CLKEN_CONTROL);
		writel(value | (1 << pll->shift_enable), pll->base + R_PLL_CLKEN_CONTROL);
	} else {
		/* disable pll */
		value = readl(pll->base + R_PLL_CLKEN_CONTROL);
		writel(value & (~(1 << pll->shift_enable)), pll->base + R_PLL_CLKEN_CONTROL);

Annotation

Implementation Notes