clk: Add a bypass clock for K210
[platform/kernel/u-boot.git] / drivers / clk / kendryte / bypass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
4  */
5
6 #define LOG_CATEGORY UCLASS_CLK
7 #include <kendryte/bypass.h>
8
9 #include <clk-uclass.h>
10 #include <linux/clk-provider.h>
11 #include <linux/err.h>
12 #include <log.h>
13
14 #define CLK_K210_BYPASS "k210_clk_bypass"
15
16 /*
17  * This is a small driver to do a software bypass of a clock if hardware bypass
18  * is not working. I have tried to write this in a generic fashion, so that it
19  * could be potentially broken out of the kendryte code at some future date.
20  *
21  * Say you have the following clock configuration
22  *
23  * +---+ +---+
24  * |osc| |pll|
25  * +---+ +---+
26  *         ^
27  *        /|
28  *       / |
29  *      /  |
30  *     /   |
31  *    /    |
32  * +---+ +---+
33  * |clk| |clk|
34  * +---+ +---+
35  *
36  * But the pll does not have a bypass, so when you configure the pll, the
37  * configuration needs to change to look like
38  *
39  * +---+ +---+
40  * |osc| |pll|
41  * +---+ +---+
42  *   ^
43  *   |\
44  *   | \
45  *   |  \
46  *   |   \
47  *   |    \
48  * +---+ +---+
49  * |clk| |clk|
50  * +---+ +---+
51  *
52  * To set this up, create a bypass clock with bypassee=pll and alt=osc. When
53  * creating the child clocks, set their parent to the bypass clock. After
54  * creating all the children, call k210_bypass_setchildren().
55  */
56
57 static int k210_bypass_dobypass(struct k210_bypass *bypass)
58 {
59         int ret, i;
60
61         /*
62          * If we already have saved parents, then the children are already
63          * bypassed
64          */
65         if (bypass->child_count && bypass->saved_parents[0])
66                 return 0;
67
68         for (i = 0; i < bypass->child_count; i++) {
69                 struct clk *child = bypass->children[i];
70                 struct clk *parent = clk_get_parent(child);
71
72                 if (IS_ERR(parent)) {
73                         for (; i; i--)
74                                 bypass->saved_parents[i] = NULL;
75                         return PTR_ERR(parent);
76                 }
77                 bypass->saved_parents[i] = parent;
78         }
79
80         for (i = 0; i < bypass->child_count; i++) {
81                 struct clk *child = bypass->children[i];
82
83                 ret = clk_set_parent(child, bypass->alt);
84                 if (ret) {
85                         for (; i; i--)
86                                 clk_set_parent(bypass->children[i],
87                                                bypass->saved_parents[i]);
88                         for (i = 0; i < bypass->child_count; i++)
89                                 bypass->saved_parents[i] = NULL;
90                         return ret;
91                 }
92         }
93
94         return 0;
95 }
96
97 static int k210_bypass_unbypass(struct k210_bypass *bypass)
98 {
99         int err, ret, i;
100
101         if (!bypass->child_count && !bypass->saved_parents[0]) {
102                 log_warning("Cannot unbypass children; dobypass not called first\n");
103                 return 0;
104         }
105
106         ret = 0;
107         for (i = 0; i < bypass->child_count; i++) {
108                 err = clk_set_parent(bypass->children[i],
109                                      bypass->saved_parents[i]);
110                 if (err)
111                         ret = err;
112                 bypass->saved_parents[i] = NULL;
113         }
114         return ret;
115 }
116
117 static ulong k210_bypass_get_rate(struct clk *clk)
118 {
119         struct k210_bypass *bypass = to_k210_bypass(clk);
120         const struct clk_ops *ops = bypass->bypassee_ops;
121
122         if (ops->get_rate)
123                 return ops->get_rate(bypass->bypassee);
124         else
125                 return clk_get_parent_rate(bypass->bypassee);
126 }
127
128 static ulong k210_bypass_set_rate(struct clk *clk, unsigned long rate)
129 {
130         int ret;
131         struct k210_bypass *bypass = to_k210_bypass(clk);
132         const struct clk_ops *ops = bypass->bypassee_ops;
133
134         /* Don't bother bypassing if we aren't going to set the rate */
135         if (!ops->set_rate)
136                 return k210_bypass_get_rate(clk);
137
138         ret = k210_bypass_dobypass(bypass);
139         if (ret)
140                 return ret;
141
142         ret = ops->set_rate(bypass->bypassee, rate);
143         if (ret < 0)
144                 return ret;
145
146         return k210_bypass_unbypass(bypass);
147 }
148
149 static int k210_bypass_set_parent(struct clk *clk, struct clk *parent)
150 {
151         struct k210_bypass *bypass = to_k210_bypass(clk);
152         const struct clk_ops *ops = bypass->bypassee_ops;
153
154         if (ops->set_parent)
155                 return ops->set_parent(bypass->bypassee, parent);
156         else
157                 return -ENOTSUPP;
158 }
159
160 /*
161  * For these next two functions, do the bypassing even if there is no
162  * en-/-disable function, since the bypassing itself can be observed in between
163  * calls.
164  */
165 static int k210_bypass_enable(struct clk *clk)
166 {
167         int ret;
168         struct k210_bypass *bypass = to_k210_bypass(clk);
169         const struct clk_ops *ops = bypass->bypassee_ops;
170
171         ret = k210_bypass_dobypass(bypass);
172         if (ret)
173                 return ret;
174
175         if (ops->enable)
176                 ret = ops->enable(bypass->bypassee);
177         else
178                 ret = 0;
179         if (ret)
180                 return ret;
181
182         return k210_bypass_unbypass(bypass);
183 }
184
185 static int k210_bypass_disable(struct clk *clk)
186 {
187         int ret;
188         struct k210_bypass *bypass = to_k210_bypass(clk);
189         const struct clk_ops *ops = bypass->bypassee_ops;
190
191         ret = k210_bypass_dobypass(bypass);
192         if (ret)
193                 return ret;
194
195         if (ops->disable)
196                 return ops->disable(bypass->bypassee);
197         else
198                 return 0;
199 }
200
201 static const struct clk_ops k210_bypass_ops = {
202         .get_rate = k210_bypass_get_rate,
203         .set_rate = k210_bypass_set_rate,
204         .set_parent = k210_bypass_set_parent,
205         .enable = k210_bypass_enable,
206         .disable = k210_bypass_disable,
207 };
208
209 int k210_bypass_set_children(struct clk *clk, struct clk **children,
210                              size_t child_count)
211 {
212         struct k210_bypass *bypass = to_k210_bypass(clk);
213
214         kfree(bypass->saved_parents);
215         if (child_count) {
216                 bypass->saved_parents =
217                         kcalloc(child_count, sizeof(struct clk *), GFP_KERNEL);
218                 if (!bypass->saved_parents)
219                         return -ENOMEM;
220         }
221         bypass->child_count = child_count;
222         bypass->children = children;
223
224         return 0;
225 }
226
227 struct clk *k210_register_bypass_struct(const char *name,
228                                         const char *parent_name,
229                                         struct k210_bypass *bypass)
230 {
231         int ret;
232         struct clk *clk;
233
234         clk = &bypass->clk;
235
236         ret = clk_register(clk, CLK_K210_BYPASS, name, parent_name);
237         if (ret)
238                 return ERR_PTR(ret);
239
240         bypass->bypassee->dev = clk->dev;
241         return clk;
242 }
243
244 struct clk *k210_register_bypass(const char *name, const char *parent_name,
245                                  struct clk *bypassee,
246                                  const struct clk_ops *bypassee_ops,
247                                  struct clk *alt)
248 {
249         struct clk *clk;
250         struct k210_bypass *bypass;
251
252         bypass = kzalloc(sizeof(*bypass), GFP_KERNEL);
253         if (!bypass)
254                 return ERR_PTR(-ENOMEM);
255
256         bypass->bypassee = bypassee;
257         bypass->bypassee_ops = bypassee_ops;
258         bypass->alt = alt;
259
260         clk = k210_register_bypass_struct(name, parent_name, bypass);
261         if (IS_ERR(clk))
262                 kfree(bypass);
263         return clk;
264 }
265
266 U_BOOT_DRIVER(k210_bypass) = {
267         .name   = CLK_K210_BYPASS,
268         .id     = UCLASS_CLK,
269         .ops    = &k210_bypass_ops,
270 };