blob: d1fd28175ba309a5328a543f377b19467237140d [file] [log] [blame]
Sean Anderson1a198cf2020-06-24 06:41:10 -04001// 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
57static 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
97static 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
117static 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
128static 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
149static 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 */
165static 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
185static 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
201static 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
209int 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
227struct 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
244struct 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
266U_BOOT_DRIVER(k210_bypass) = {
267 .name = CLK_K210_BYPASS,
268 .id = UCLASS_CLK,
269 .ops = &k210_bypass_ops,
270};