drivers/clk/zynqmp/pll.c

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

File Facts

System
Linux kernel
Corpus path
drivers/clk/zynqmp/pll.c
Extension
.c
Size
8480 bytes
Lines
345
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 zynqmp_pll {
	struct clk_hw hw;
	u32 clk_id;
	bool set_pll_mode;
};

#define to_zynqmp_pll(_hw)	container_of(_hw, struct zynqmp_pll, hw)

#define PLL_FBDIV_MIN	25
#define PLL_FBDIV_MAX	125

#define PS_PLL_VCO_MIN 1500000000
#define PS_PLL_VCO_MAX 3000000000UL

enum pll_mode {
	PLL_MODE_INT = 0,
	PLL_MODE_FRAC = 1,
	PLL_MODE_ERROR = 2,
};

#define FRAC_OFFSET 0x8
#define PLLFCFG_FRAC_EN	BIT(31)
#define FRAC_DIV  BIT(16)  /* 2^16 */

/**
 * zynqmp_pll_get_mode() - Get mode of PLL
 * @hw:		Handle between common and hardware-specific interfaces
 *
 * Return: Mode of PLL
 */
static inline enum pll_mode zynqmp_pll_get_mode(struct clk_hw *hw)
{
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
	u32 clk_id = clk->clk_id;
	const char *clk_name = clk_hw_get_name(hw);
	u32 ret_payload[PAYLOAD_ARG_CNT];
	int ret;

	ret = zynqmp_pm_get_pll_frac_mode(clk_id, ret_payload);
	if (ret) {
		pr_debug("%s() PLL get frac mode failed for %s, ret = %d\n",
			 __func__, clk_name, ret);
		return PLL_MODE_ERROR;
	}

	return ret_payload[1];
}

/**
 * zynqmp_pll_set_mode() - Set the PLL mode
 * @hw:		Handle between common and hardware-specific interfaces
 * @on:		Flag to determine the mode
 */
static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on)
{
	struct zynqmp_pll *clk = to_zynqmp_pll(hw);
	u32 clk_id = clk->clk_id;
	const char *clk_name = clk_hw_get_name(hw);
	int ret;
	u32 mode;

	if (on)
		mode = PLL_MODE_FRAC;
	else
		mode = PLL_MODE_INT;

	ret = zynqmp_pm_set_pll_frac_mode(clk_id, mode);
	if (ret)
		pr_debug("%s() PLL set frac mode failed for %s, ret = %d\n",
			 __func__, clk_name, ret);
	else
		clk->set_pll_mode = true;
}

/**
 * zynqmp_pll_determine_rate() - Round a clock frequency
 * @hw:		Handle between common and hardware-specific interfaces
 * @req:	Desired clock frequency
 *
 * Return: Frequency closest to @rate the hardware can generate
 */
static int zynqmp_pll_determine_rate(struct clk_hw *hw,
				     struct clk_rate_request *req)
{
	u32 fbdiv;
	u32 mult, div;

	/* Let rate fall inside the range PS_PLL_VCO_MIN ~ PS_PLL_VCO_MAX */
	if (req->rate > PS_PLL_VCO_MAX) {
		div = DIV_ROUND_UP(req->rate, PS_PLL_VCO_MAX);

Annotation

Implementation Notes