Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / clk / mediatek / clk-mux.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2018 MediaTek Inc.
4  * Author: Owen Chen <owen.chen@mediatek.com>
5  */
6
7 #include <linux/of.h>
8 #include <linux/of_address.h>
9 #include <linux/slab.h>
10 #include <linux/mfd/syscon.h>
11
12 #include "clk-mtk.h"
13 #include "clk-mux.h"
14
15 static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw)
16 {
17         return container_of(hw, struct mtk_clk_mux, hw);
18 }
19
20 static int mtk_clk_mux_enable(struct clk_hw *hw)
21 {
22         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
23         u32 mask = BIT(mux->data->gate_shift);
24
25         return regmap_update_bits(mux->regmap, mux->data->mux_ofs,
26                         mask, ~mask);
27 }
28
29 static void mtk_clk_mux_disable(struct clk_hw *hw)
30 {
31         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
32         u32 mask = BIT(mux->data->gate_shift);
33
34         regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask, mask);
35 }
36
37 static int mtk_clk_mux_enable_setclr(struct clk_hw *hw)
38 {
39         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
40
41         return regmap_write(mux->regmap, mux->data->clr_ofs,
42                         BIT(mux->data->gate_shift));
43 }
44
45 static void mtk_clk_mux_disable_setclr(struct clk_hw *hw)
46 {
47         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
48
49         regmap_write(mux->regmap, mux->data->set_ofs,
50                         BIT(mux->data->gate_shift));
51 }
52
53 static int mtk_clk_mux_is_enabled(struct clk_hw *hw)
54 {
55         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
56         u32 val;
57
58         regmap_read(mux->regmap, mux->data->mux_ofs, &val);
59
60         return (val & BIT(mux->data->gate_shift)) == 0;
61 }
62
63 static u8 mtk_clk_mux_get_parent(struct clk_hw *hw)
64 {
65         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
66         u32 mask = GENMASK(mux->data->mux_width - 1, 0);
67         u32 val;
68
69         regmap_read(mux->regmap, mux->data->mux_ofs, &val);
70         val = (val >> mux->data->mux_shift) & mask;
71
72         return val;
73 }
74
75 static int mtk_clk_mux_set_parent_lock(struct clk_hw *hw, u8 index)
76 {
77         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
78         u32 mask = GENMASK(mux->data->mux_width - 1, 0);
79         unsigned long flags = 0;
80
81         if (mux->lock)
82                 spin_lock_irqsave(mux->lock, flags);
83         else
84                 __acquire(mux->lock);
85
86         regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask,
87                 index << mux->data->mux_shift);
88
89         if (mux->lock)
90                 spin_unlock_irqrestore(mux->lock, flags);
91         else
92                 __release(mux->lock);
93
94         return 0;
95 }
96
97 static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index)
98 {
99         struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
100         u32 mask = GENMASK(mux->data->mux_width - 1, 0);
101         u32 val, orig;
102         unsigned long flags = 0;
103
104         if (mux->lock)
105                 spin_lock_irqsave(mux->lock, flags);
106         else
107                 __acquire(mux->lock);
108
109         regmap_read(mux->regmap, mux->data->mux_ofs, &orig);
110         val = (orig & ~(mask << mux->data->mux_shift))
111                         | (index << mux->data->mux_shift);
112
113         if (val != orig) {
114                 regmap_write(mux->regmap, mux->data->clr_ofs,
115                                 mask << mux->data->mux_shift);
116                 regmap_write(mux->regmap, mux->data->set_ofs,
117                                 index << mux->data->mux_shift);
118
119                 if (mux->data->upd_shift >= 0)
120                         regmap_write(mux->regmap, mux->data->upd_ofs,
121                                         BIT(mux->data->upd_shift));
122         }
123
124         if (mux->lock)
125                 spin_unlock_irqrestore(mux->lock, flags);
126         else
127                 __release(mux->lock);
128
129         return 0;
130 }
131
132 const struct clk_ops mtk_mux_ops = {
133         .get_parent = mtk_clk_mux_get_parent,
134         .set_parent = mtk_clk_mux_set_parent_lock,
135 };
136
137 const struct clk_ops mtk_mux_clr_set_upd_ops = {
138         .get_parent = mtk_clk_mux_get_parent,
139         .set_parent = mtk_clk_mux_set_parent_setclr_lock,
140 };
141
142 const struct clk_ops mtk_mux_gate_ops = {
143         .enable = mtk_clk_mux_enable,
144         .disable = mtk_clk_mux_disable,
145         .is_enabled = mtk_clk_mux_is_enabled,
146         .get_parent = mtk_clk_mux_get_parent,
147         .set_parent = mtk_clk_mux_set_parent_lock,
148 };
149
150 const struct clk_ops mtk_mux_gate_clr_set_upd_ops = {
151         .enable = mtk_clk_mux_enable_setclr,
152         .disable = mtk_clk_mux_disable_setclr,
153         .is_enabled = mtk_clk_mux_is_enabled,
154         .get_parent = mtk_clk_mux_get_parent,
155         .set_parent = mtk_clk_mux_set_parent_setclr_lock,
156 };
157
158 struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
159                                  struct regmap *regmap,
160                                  spinlock_t *lock)
161 {
162         struct mtk_clk_mux *clk_mux;
163         struct clk_init_data init;
164         struct clk *clk;
165
166         clk_mux = kzalloc(sizeof(*clk_mux), GFP_KERNEL);
167         if (!clk_mux)
168                 return ERR_PTR(-ENOMEM);
169
170         init.name = mux->name;
171         init.flags = mux->flags | CLK_SET_RATE_PARENT;
172         init.parent_names = mux->parent_names;
173         init.num_parents = mux->num_parents;
174         init.ops = mux->ops;
175
176         clk_mux->regmap = regmap;
177         clk_mux->data = mux;
178         clk_mux->lock = lock;
179         clk_mux->hw.init = &init;
180
181         clk = clk_register(NULL, &clk_mux->hw);
182         if (IS_ERR(clk)) {
183                 kfree(clk_mux);
184                 return clk;
185         }
186
187         return clk;
188 }
189
190 int mtk_clk_register_muxes(const struct mtk_mux *muxes,
191                            int num, struct device_node *node,
192                            spinlock_t *lock,
193                            struct clk_onecell_data *clk_data)
194 {
195         struct regmap *regmap;
196         struct clk *clk;
197         int i;
198
199         regmap = syscon_node_to_regmap(node);
200         if (IS_ERR(regmap)) {
201                 pr_err("Cannot find regmap for %pOF: %ld\n", node,
202                        PTR_ERR(regmap));
203                 return PTR_ERR(regmap);
204         }
205
206         for (i = 0; i < num; i++) {
207                 const struct mtk_mux *mux = &muxes[i];
208
209                 if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
210                         clk = mtk_clk_register_mux(mux, regmap, lock);
211
212                         if (IS_ERR(clk)) {
213                                 pr_err("Failed to register clk %s: %ld\n",
214                                        mux->name, PTR_ERR(clk));
215                                 continue;
216                         }
217
218                         clk_data->clks[mux->id] = clk;
219                 }
220         }
221
222         return 0;
223 }