]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
clk: qcom: regmap-phy-mux: Rework the implementation
authorKonrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Thu, 9 Apr 2026 11:57:45 +0000 (13:57 +0200)
committerBjorn Andersson <andersson@kernel.org>
Mon, 8 Jun 2026 14:17:24 +0000 (09:17 -0500)
The sole reason this hw exists is to let the branch clock downstream of
it keep running, with the PHY disengaged. This is not possible with the
current implementation, as the enabled status is hijacked to mean
"enabled" = "use fast/PHY source" and "disabled" = "use XO source".

This is an issue, since the mux enable state follows that of the child
branch, making the desired "child enabled, MUX @ XO" combination
impossible.

Solve that by implementing ratesetting. Because PHY clock rates may
change at runtime and aren't really deterministic from Linux, assume
ULONG_MAX as "fast clock" and 19.2 MHz as XO. All the branches in
question already set CLK_SET_RATE_PARENT, so everything works out.

Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20260409-topic-phy_fastclk-v1-1-6b4aaee56b90@oss.qualcomm.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
drivers/clk/qcom/clk-regmap-phy-mux.c

index 7b7243b7107dcd72eefdee972152181942631a8b..b7d1c69d62f7f49239707843450aa14091e4e759 100644 (file)
 #define PHY_MUX_PHY_SRC                0
 #define PHY_MUX_REF_SRC                2
 
+#define XO_RATE                        19200000UL
+
 static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_regmap *clkr)
 {
        return container_of(clkr, struct clk_regmap_phy_mux, clkr);
 }
 
-static int phy_mux_is_enabled(struct clk_hw *hw)
+static unsigned long phy_mux_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 {
        struct clk_regmap *clkr = to_clk_regmap(hw);
        struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
-       unsigned int val;
+       u32 val;
 
        regmap_read(clkr->regmap, phy_mux->reg, &val);
-       val = FIELD_GET(PHY_MUX_MASK, val);
-
-       WARN_ON(val != PHY_MUX_PHY_SRC && val != PHY_MUX_REF_SRC);
 
-       return val == PHY_MUX_PHY_SRC;
+       switch (FIELD_GET(PHY_MUX_MASK, val)) {
+       case PHY_MUX_PHY_SRC:
+               return ULONG_MAX;
+       case PHY_MUX_REF_SRC:
+               return XO_RATE;
+       default:
+               return 0;
+       }
 }
 
-static int phy_mux_enable(struct clk_hw *hw)
+static int phy_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
 {
-       struct clk_regmap *clkr = to_clk_regmap(hw);
-       struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
+       if (req->rate == XO_RATE || req->rate == ULONG_MAX)
+               return 0;
 
-       return regmap_update_bits(clkr->regmap, phy_mux->reg,
-                                 PHY_MUX_MASK,
-                                 FIELD_PREP(PHY_MUX_MASK, PHY_MUX_PHY_SRC));
+       return -EINVAL;
 }
 
-static void phy_mux_disable(struct clk_hw *hw)
+static int phy_mux_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
 {
        struct clk_regmap *clkr = to_clk_regmap(hw);
        struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
+       u32 val;
+
+       switch (rate) {
+       case XO_RATE:
+               val = PHY_MUX_REF_SRC;
+               break;
+       case ULONG_MAX:
+               val = PHY_MUX_PHY_SRC;
+               break;
+       default:
+               return -EINVAL;
+       }
 
        regmap_update_bits(clkr->regmap, phy_mux->reg,
                           PHY_MUX_MASK,
-                          FIELD_PREP(PHY_MUX_MASK, PHY_MUX_REF_SRC));
+                          FIELD_PREP(PHY_MUX_MASK, val));
+
+       return 0;
 }
 
 const struct clk_ops clk_regmap_phy_mux_ops = {
-       .enable = phy_mux_enable,
-       .disable = phy_mux_disable,
-       .is_enabled = phy_mux_is_enabled,
+       .recalc_rate = phy_mux_recalc_rate,
+       .determine_rate = phy_mux_determine_rate,
+       .set_rate = phy_mux_set_rate,
 };
 EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);