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(map: mux->regmap, reg: mux->reg, val: &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(map: mux->regmap, reg: mux->reg, val: val | (mask << 16)); |
46 | else |
47 | return regmap_update_bits(map: mux->regmap, reg: 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(ptr: regmap)) { |
66 | pr_err("%s: regmap not available\n" , __func__); |
67 | return ERR_PTR(error: -ENOTSUPP); |
68 | } |
69 | |
70 | muxgrf_clock = kmalloc(size: sizeof(*muxgrf_clock), GFP_KERNEL); |
71 | if (!muxgrf_clock) |
72 | return ERR_PTR(error: -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, hw: &muxgrf_clock->hw); |
88 | if (IS_ERR(ptr: clk)) |
89 | kfree(objp: muxgrf_clock); |
90 | |
91 | return clk; |
92 | } |
93 | |