1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/slab.h> 4 #include <linux/bitops.h> 5 #include <linux/regmap.h> 6 #include <linux/clk.h> 7 #include <linux/clk-provider.h> 8 #include "clk.h" 9 10 struct rockchip_muxgrf_clock { 11 struct clk_hw hw; 12 struct regmap *regmap; 13 u32 reg; 14 u32 shift; 15 u32 width; 16 int flags; 17 }; 18 19 #define to_muxgrf_clock(_hw) container_of(_hw, struct rockchip_muxgrf_clock, hw) 20 21 static u8 rockchip_muxgrf_get_parent(struct clk_hw *hw) 22 { 23 struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw); 24 unsigned int mask = GENMASK(mux->width - 1, 0); 25 unsigned int val; 26 27 regmap_read(mux->regmap, mux->reg, &val); 28 29 val >>= mux->shift; 30 val &= mask; 31 32 return val; 33 } 34 35 static int rockchip_muxgrf_set_parent(struct clk_hw *hw, u8 index) 36 { 37 struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw); 38 unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift); 39 unsigned int val; 40 41 val = index; 42 val <<= mux->shift; 43 44 if (mux->flags & CLK_MUX_HIWORD_MASK) 45 return regmap_write(mux->regmap, mux->reg, val | (mask << 16)); 46 else 47 return regmap_update_bits(mux->regmap, mux->reg, mask, val); 48 } 49 50 static const struct clk_ops rockchip_muxgrf_clk_ops = { 51 .get_parent = rockchip_muxgrf_get_parent, 52 .set_parent = rockchip_muxgrf_set_parent, 53 .determine_rate = __clk_mux_determine_rate, 54 }; 55 56 struct clk *rockchip_clk_register_muxgrf(const char *name, 57 const char *const *parent_names, u8 num_parents, 58 int flags, struct regmap *regmap, int reg, 59 int shift, int width, int mux_flags) 60 { 61 struct rockchip_muxgrf_clock *muxgrf_clock; 62 struct clk_init_data init; 63 struct clk *clk; 64 65 if (IS_ERR(regmap)) { 66 pr_err("%s: regmap not available\n", __func__); 67 return ERR_PTR(-ENOTSUPP); 68 } 69 70 muxgrf_clock = kmalloc(sizeof(*muxgrf_clock), GFP_KERNEL); 71 if (!muxgrf_clock) 72 return ERR_PTR(-ENOMEM); 73 74 init.name = name; 75 init.flags = flags; 76 init.num_parents = num_parents; 77 init.parent_names = parent_names; 78 init.ops = &rockchip_muxgrf_clk_ops; 79 80 muxgrf_clock->hw.init = &init; 81 muxgrf_clock->regmap = regmap; 82 muxgrf_clock->reg = reg; 83 muxgrf_clock->shift = shift; 84 muxgrf_clock->width = width; 85 muxgrf_clock->flags = mux_flags; 86 87 clk = clk_register(NULL, &muxgrf_clock->hw); 88 if (IS_ERR(clk)) 89 kfree(muxgrf_clock); 90 91 return clk; 92 } 93