Commit | Line | Data |
---|---|---|
9c92ab61 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
cb1d9f6d HS |
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 | } |