1 /* 2 * 3 * This software is licensed under the terms of the GNU General Public 4 * License version 2, as published by the Free Software Foundation, and 5 * may be copied, distributed, and modified under those terms. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 */ 12 13 #include <linux/slab.h> 14 #include <linux/bitops.h> 15 #include <linux/regmap.h> 16 #include <linux/clk.h> 17 #include <linux/clk-provider.h> 18 #include "clk.h" 19 20 struct rockchip_muxgrf_clock { 21 struct clk_hw hw; 22 struct regmap *regmap; 23 u32 reg; 24 u32 shift; 25 u32 width; 26 int flags; 27 }; 28 29 #define to_muxgrf_clock(_hw) container_of(_hw, struct rockchip_muxgrf_clock, hw) 30 31 static u8 rockchip_muxgrf_get_parent(struct clk_hw *hw) 32 { 33 struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw); 34 unsigned int mask = GENMASK(mux->width - 1, 0); 35 unsigned int val; 36 37 regmap_read(mux->regmap, mux->reg, &val); 38 39 val >>= mux->shift; 40 val &= mask; 41 42 return val; 43 } 44 45 static int rockchip_muxgrf_set_parent(struct clk_hw *hw, u8 index) 46 { 47 struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw); 48 unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift); 49 unsigned int val; 50 51 val = index; 52 val <<= mux->shift; 53 54 if (mux->flags & CLK_MUX_HIWORD_MASK) 55 return regmap_write(mux->regmap, mux->reg, val | (mask << 16)); 56 else 57 return regmap_update_bits(mux->regmap, mux->reg, mask, val); 58 } 59 60 static const struct clk_ops rockchip_muxgrf_clk_ops = { 61 .get_parent = rockchip_muxgrf_get_parent, 62 .set_parent = rockchip_muxgrf_set_parent, 63 .determine_rate = __clk_mux_determine_rate, 64 }; 65 66 struct clk *rockchip_clk_register_muxgrf(const char *name, 67 const char *const *parent_names, u8 num_parents, 68 int flags, struct regmap *regmap, int reg, 69 int shift, int width, int mux_flags) 70 { 71 struct rockchip_muxgrf_clock *muxgrf_clock; 72 struct clk_init_data init; 73 struct clk *clk; 74 75 if (IS_ERR(regmap)) { 76 pr_err("%s: regmap not available\n", __func__); 77 return ERR_PTR(-ENOTSUPP); 78 } 79 80 muxgrf_clock = kmalloc(sizeof(*muxgrf_clock), GFP_KERNEL); 81 if (!muxgrf_clock) 82 return ERR_PTR(-ENOMEM); 83 84 init.name = name; 85 init.flags = flags; 86 init.num_parents = num_parents; 87 init.parent_names = parent_names; 88 init.ops = &rockchip_muxgrf_clk_ops; 89 90 muxgrf_clock->hw.init = &init; 91 muxgrf_clock->regmap = regmap; 92 muxgrf_clock->reg = reg; 93 muxgrf_clock->shift = shift; 94 muxgrf_clock->width = width; 95 muxgrf_clock->flags = mux_flags; 96 97 clk = clk_register(NULL, &muxgrf_clock->hw); 98 if (IS_ERR(clk)) 99 kfree(muxgrf_clock); 100 101 return clk; 102 } 103