[PATCH v2 08/12] clk: qcom: ipq-cmn-pll: Add EPHY-RAW clock support
Luo Jie <[email protected]> Thu, 06 Aug 2026 23:53:12 -0700
| Newsgroups | org.kernel.vger.linux-clk,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
The EPHY-RAW clock is an IPQ5210-specific output from the CMN PLL that provides the raw reference clock to the SoC-integrated Ethernet PHY (EPHY), which supports up to 2.5G link speed. The output frequency is selected via bit 10 (CMN_PLL_GEPHY_312P5M_125M_SEL) of the CMN_PLL_PON_CONFIG register: - 0: 125 MHz - for 1G/100M/10M link speed - 1: 312.5 MHz - for 2.5G link speed Signed-off-by: Luo Jie <[email protected]> --- drivers/clk/qcom/ipq-cmn-pll.c | 98 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c index 356988c03a7a..586f9c620e7e 100644 --- a/drivers/clk/qcom/ipq-cmn-pll.c +++ b/drivers/clk/qcom/ipq-cmn-pll.c @@ -77,6 +77,7 @@ #define CMN_PLL_PON_MODE_SEL BIT(9) #define CMN_PLL_PON_EN BIT(8) #define CMN_PLL_PON_DIV_CTRL GENMASK(7, 0) +#define CMN_PLL_GEPHY_312P5M_125M_SEL BIT(10) #define CMN_PLL_POWER_ON_AND_RESET 0x780 #define CMN_ANA_EN_SW_RSTN BIT(6) @@ -98,12 +99,14 @@ * @CMN_PLL_CLK_NSS: NSS clock with configurable divider * @CMN_PLL_CLK_PPE: PPE clock with configurable divider * @CMN_PLL_CLK_PON: PON reference clock + * @CMN_PLL_CLK_EPHY_RAW: EPHY-RAW clock */ enum cmn_pll_clk_type { CMN_PLL_CLK_FIXED_RATE, CMN_PLL_CLK_NSS, CMN_PLL_CLK_PPE, CMN_PLL_CLK_PON, + CMN_PLL_CLK_EPHY_RAW, }; /** @@ -578,6 +581,95 @@ static struct clk_hw *ipq_cmn_pll_pon_refclk_register(struct platform_device *pd return &pon_clk->hw; } +/* + * EPHY-RAW clock operations for IPQ5210. + * The output clock rate is selected via bit 10 of CMN_PLL_PON_CONFIG: + * 0: 125 MHz (for 1G link speed) + * 1: 312.5 MHz (for 2.5G link speed) + */ +static unsigned long clk_ephy_raw_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_cmn_pll *ephy_raw_clk = to_clk_cmn_pll(hw); + u32 val; + int ret; + + ret = regmap_read(ephy_raw_clk->regmap, CMN_PLL_PON_CONFIG, &val); + if (WARN_ON_ONCE(ret)) + return 0; + + if (val & CMN_PLL_GEPHY_312P5M_125M_SEL) + return 312500000UL; + + return 125000000UL; +} + +static int clk_ephy_raw_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + unsigned long rate_125m = 125000000UL, rate_312p5m = 312500000UL; + + /* Pick whichever of the two supported rates is closer to the request */ + req->rate = abs_diff(req->rate, rate_125m) < abs_diff(req->rate, rate_312p5m) ? + rate_125m : rate_312p5m; + + return 0; +} + +static int clk_ephy_raw_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_cmn_pll *ephy_raw_clk = to_clk_cmn_pll(hw); + + if (rate == 125000000UL) + return regmap_clear_bits(ephy_raw_clk->regmap, + CMN_PLL_PON_CONFIG, + CMN_PLL_GEPHY_312P5M_125M_SEL); + + if (rate == 312500000UL) + return regmap_set_bits(ephy_raw_clk->regmap, + CMN_PLL_PON_CONFIG, + CMN_PLL_GEPHY_312P5M_125M_SEL); + + return -EINVAL; +} + +static const struct clk_ops clk_ephy_raw_ops = { + .recalc_rate = clk_ephy_raw_recalc_rate, + .determine_rate = clk_ephy_raw_determine_rate, + .set_rate = clk_ephy_raw_set_rate, +}; + +static struct clk_hw *ipq_cmn_pll_ephy_raw_register(struct platform_device *pdev, + struct regmap *regmap, + struct clk_hw *cmn_pll_hw, + const char *name) +{ + struct clk_parent_data pdata = { .hw = cmn_pll_hw }; + struct clk_cmn_pll *ephy_raw_clk; + struct device *dev = &pdev->dev; + struct clk_init_data init = {}; + int ret; + + ephy_raw_clk = devm_kzalloc(dev, sizeof(*ephy_raw_clk), GFP_KERNEL); + if (!ephy_raw_clk) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.parent_data = &pdata; + init.num_parents = 1; + init.ops = &clk_ephy_raw_ops; + + ephy_raw_clk->hw.init = &init; + ephy_raw_clk->regmap = regmap; + + ret = devm_clk_hw_register(dev, &ephy_raw_clk->hw); + if (ret) + return ERR_PTR(ret); + + return &ephy_raw_clk->hw; +} + static int ipq_cmn_pll_register_clks(struct platform_device *pdev) { const struct cmn_pll_fixed_output_clk *p, *fixed_clk; @@ -644,6 +736,12 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev) cmn_pll_hw, fixed_clk[i].name); break; + case CMN_PLL_CLK_EPHY_RAW: + hw = ipq_cmn_pll_ephy_raw_register(pdev, + cmn_pll->regmap, + cmn_pll_hw, + fixed_clk[i].name); + break; } if (IS_ERR(hw)) -- 2.43.0