[PATCH 07/12] clk: qcom: ipq-cmn-pll: Add EPHY-RAW clock support
Luo Jie <[email protected]>
| 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 | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c index 1ae32052b563..dfc28c12468b 100644 --- a/drivers/clk/qcom/ipq-cmn-pll.c +++ b/drivers/clk/qcom/ipq-cmn-pll.c @@ -76,6 +76,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) @@ -694,6 +695,87 @@ 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; + + regmap_read(ephy_raw_clk->regmap, CMN_PLL_PON_CONFIG, &val); + + 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) +{ + if (req->rate <= 125000000UL) + req->rate = 125000000UL; + else + req->rate = 312500000UL; + + 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); + + return regmap_set_bits(ephy_raw_clk->regmap, + CMN_PLL_PON_CONFIG, + CMN_PLL_GEPHY_312P5M_125M_SEL); +} + +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) +{ + 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 = "ephy-raw"; + 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; @@ -747,6 +829,10 @@ static int ipq_cmn_pll_register_clks(struct platform_device *pdev) hw = ipq_cmn_pll_pon_refclk_register(pdev, cmn_pll->regmap, cmn_pll_hw); + } else if (!strcmp(fixed_clk[i].name, "ephy-raw")) { + hw = ipq_cmn_pll_ephy_raw_register(pdev, + cmn_pll->regmap, + cmn_pll_hw); } else { continue; } -- 2.43.0