GNU Linux-libre 4.14.332-gnu1
[releases.git] / drivers / clk / rockchip / clk-muxgrf.c
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 }