1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022, Linaro Ltd. 4 */ 5 6 #include <linux/clk-provider.h> 7 #include <linux/bitfield.h> 8 #include <linux/regmap.h> 9 #include <linux/export.h> 10 11 #include "clk-regmap.h" 12 #include "clk-regmap-phy-mux.h" 13 14 #define PHY_MUX_MASK GENMASK(1, 0) 15 #define PHY_MUX_PHY_SRC 0 16 #define PHY_MUX_REF_SRC 2 17 18 #define XO_RATE 19200000UL 19 20 static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_regmap *clkr) 21 { 22 return container_of(clkr, struct clk_regmap_phy_mux, clkr); 23 } 24 25 static unsigned long phy_mux_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 26 { 27 struct clk_regmap *clkr = to_clk_regmap(hw); 28 struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr); 29 u32 val; 30 31 regmap_read(clkr->regmap, phy_mux->reg, &val); 32 33 switch (FIELD_GET(PHY_MUX_MASK, val)) { 34 case PHY_MUX_PHY_SRC: 35 return ULONG_MAX; 36 case PHY_MUX_REF_SRC: 37 return XO_RATE; 38 default: 39 return 0; 40 } 41 } 42 43 static int phy_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) 44 { 45 if (req->rate == XO_RATE || req->rate == ULONG_MAX) 46 return 0; 47 48 return -EINVAL; 49 } 50 51 static int phy_mux_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) 52 { 53 struct clk_regmap *clkr = to_clk_regmap(hw); 54 struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr); 55 u32 val; 56 57 switch (rate) { 58 case XO_RATE: 59 val = PHY_MUX_REF_SRC; 60 break; 61 case ULONG_MAX: 62 val = PHY_MUX_PHY_SRC; 63 break; 64 default: 65 return -EINVAL; 66 } 67 68 regmap_update_bits(clkr->regmap, phy_mux->reg, 69 PHY_MUX_MASK, 70 FIELD_PREP(PHY_MUX_MASK, val)); 71 72 return 0; 73 } 74 75 const struct clk_ops clk_regmap_phy_mux_ops = { 76 .recalc_rate = phy_mux_recalc_rate, 77 .determine_rate = phy_mux_determine_rate, 78 .set_rate = phy_mux_set_rate, 79 }; 80 EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops); 81