Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved.
4 */
5
6#include <linux/clk-provider.h>
7#include <linux/device.h>
8#include <linux/err.h>
9#include <linux/slab.h>
10
11static u8 clk_composite_get_parent(struct clk_hw *hw)
12{
13 struct clk_composite *composite = to_clk_composite(hw);
14 const struct clk_ops *mux_ops = composite->mux_ops;
15 struct clk_hw *mux_hw = composite->mux_hw;
16
17 __clk_hw_set_clk(mux_hw, hw);
18
19 return mux_ops->get_parent(mux_hw);
20}
21
22static int clk_composite_set_parent(struct clk_hw *hw, u8 index)
23{
24 struct clk_composite *composite = to_clk_composite(hw);
25 const struct clk_ops *mux_ops = composite->mux_ops;
26 struct clk_hw *mux_hw = composite->mux_hw;
27
28 __clk_hw_set_clk(mux_hw, hw);
29
30 return mux_ops->set_parent(mux_hw, index);
31}
32
33static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
34 unsigned long parent_rate)
35{
36 struct clk_composite *composite = to_clk_composite(hw);
37 const struct clk_ops *rate_ops = composite->rate_ops;
38 struct clk_hw *rate_hw = composite->rate_hw;
39
40 __clk_hw_set_clk(rate_hw, hw);
41
42 return rate_ops->recalc_rate(rate_hw, parent_rate);
43}
44
45static int clk_composite_determine_rate_for_parent(struct clk_hw *rate_hw,
46 struct clk_rate_request *req,
47 struct clk_hw *parent_hw,
48 const struct clk_ops *rate_ops)
49{
50 req->best_parent_hw = parent_hw;
51 req->best_parent_rate = clk_hw_get_rate(parent_hw);
52
53 return rate_ops->determine_rate(rate_hw, req);
54}
55
56static int clk_composite_determine_rate(struct clk_hw *hw,
57 struct clk_rate_request *req)
58{
59 struct clk_composite *composite = to_clk_composite(hw);
60 const struct clk_ops *rate_ops = composite->rate_ops;
61 const struct clk_ops *mux_ops = composite->mux_ops;
62 struct clk_hw *rate_hw = composite->rate_hw;
63 struct clk_hw *mux_hw = composite->mux_hw;
64 struct clk_hw *parent;
65 unsigned long rate_diff;
66 unsigned long best_rate_diff = ULONG_MAX;
67 unsigned long best_rate = 0;
68 int i, ret;
69
70 if (rate_hw && rate_ops && rate_ops->determine_rate &&
71 mux_hw && mux_ops && mux_ops->set_parent) {
72 req->best_parent_hw = NULL;
73
74 if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
75 struct clk_rate_request tmp_req;
76
77 parent = clk_hw_get_parent(mux_hw);
78
79 clk_hw_forward_rate_request(hw, req, parent, &tmp_req, req->rate);
80 ret = clk_composite_determine_rate_for_parent(rate_hw,
81 &tmp_req,
82 parent,
83 rate_ops);
84 if (ret)
85 return ret;
86
87 req->rate = tmp_req.rate;
88 req->best_parent_hw = tmp_req.best_parent_hw;
89 req->best_parent_rate = tmp_req.best_parent_rate;
90
91 return 0;
92 }
93
94 for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) {
95 struct clk_rate_request tmp_req;
96
97 parent = clk_hw_get_parent_by_index(mux_hw, i);
98 if (!parent)
99 continue;
100
101 clk_hw_forward_rate_request(hw, req, parent, &tmp_req, req->rate);
102 ret = clk_composite_determine_rate_for_parent(rate_hw,
103 &tmp_req,
104 parent,
105 rate_ops);
106 if (ret)
107 continue;
108
109 if (req->rate >= tmp_req.rate)
110 rate_diff = req->rate - tmp_req.rate;
111 else
112 rate_diff = tmp_req.rate - req->rate;
113
114 if (!rate_diff || !req->best_parent_hw
115 || best_rate_diff > rate_diff) {
116 req->best_parent_hw = parent;
117 req->best_parent_rate = tmp_req.best_parent_rate;
118 best_rate_diff = rate_diff;
119 best_rate = tmp_req.rate;
120 }
121
122 if (!rate_diff)
123 return 0;
124 }
125
126 req->rate = best_rate;
127 return 0;
128 } else if (rate_hw && rate_ops && rate_ops->determine_rate) {
129 __clk_hw_set_clk(rate_hw, hw);
130 return rate_ops->determine_rate(rate_hw, req);
131 } else if (mux_hw && mux_ops && mux_ops->determine_rate) {
132 __clk_hw_set_clk(mux_hw, hw);
133 return mux_ops->determine_rate(mux_hw, req);
134 } else {
135 pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
136 return -EINVAL;
137 }
138}
139
140static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
141 unsigned long parent_rate)
142{
143 struct clk_composite *composite = to_clk_composite(hw);
144 const struct clk_ops *rate_ops = composite->rate_ops;
145 struct clk_hw *rate_hw = composite->rate_hw;
146
147 __clk_hw_set_clk(rate_hw, hw);
148
149 return rate_ops->set_rate(rate_hw, rate, parent_rate);
150}
151
152static int clk_composite_set_rate_and_parent(struct clk_hw *hw,
153 unsigned long rate,
154 unsigned long parent_rate,
155 u8 index)
156{
157 struct clk_composite *composite = to_clk_composite(hw);
158 const struct clk_ops *rate_ops = composite->rate_ops;
159 const struct clk_ops *mux_ops = composite->mux_ops;
160 struct clk_hw *rate_hw = composite->rate_hw;
161 struct clk_hw *mux_hw = composite->mux_hw;
162 unsigned long temp_rate;
163
164 __clk_hw_set_clk(rate_hw, hw);
165 __clk_hw_set_clk(mux_hw, hw);
166
167 temp_rate = rate_ops->recalc_rate(rate_hw, parent_rate);
168 if (temp_rate > rate) {
169 rate_ops->set_rate(rate_hw, rate, parent_rate);
170 mux_ops->set_parent(mux_hw, index);
171 } else {
172 mux_ops->set_parent(mux_hw, index);
173 rate_ops->set_rate(rate_hw, rate, parent_rate);
174 }
175
176 return 0;
177}
178
179static int clk_composite_is_enabled(struct clk_hw *hw)
180{
181 struct clk_composite *composite = to_clk_composite(hw);
182 const struct clk_ops *gate_ops = composite->gate_ops;
183 struct clk_hw *gate_hw = composite->gate_hw;
184
185 __clk_hw_set_clk(gate_hw, hw);
186
187 return gate_ops->is_enabled(gate_hw);
188}
189
190static int clk_composite_enable(struct clk_hw *hw)
191{
192 struct clk_composite *composite = to_clk_composite(hw);
193 const struct clk_ops *gate_ops = composite->gate_ops;
194 struct clk_hw *gate_hw = composite->gate_hw;
195
196 __clk_hw_set_clk(gate_hw, hw);
197
198 return gate_ops->enable(gate_hw);
199}
200
201static void clk_composite_disable(struct clk_hw *hw)
202{
203 struct clk_composite *composite = to_clk_composite(hw);
204 const struct clk_ops *gate_ops = composite->gate_ops;
205 struct clk_hw *gate_hw = composite->gate_hw;
206
207 __clk_hw_set_clk(gate_hw, hw);
208
209 gate_ops->disable(gate_hw);
210}
211
212static struct clk_hw *__clk_hw_register_composite(struct device *dev,
213 const char *name, const char * const *parent_names,
214 const struct clk_parent_data *pdata, int num_parents,
215 struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
216 struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
217 struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
218 unsigned long flags)
219{
220 struct clk_hw *hw;
221 struct clk_init_data init = {};
222 struct clk_composite *composite;
223 struct clk_ops *clk_composite_ops;
224 int ret;
225
226 composite = kzalloc_obj(*composite);
227 if (!composite)
228 return ERR_PTR(-ENOMEM);
229
230 init.name = name;
231 init.flags = flags;
232 if (parent_names)
233 init.parent_names = parent_names;
234 else
235 init.parent_data = pdata;
236 init.num_parents = num_parents;
237 hw = &composite->hw;
238
239 clk_composite_ops = &composite->ops;
240
241 if (mux_hw && mux_ops) {
242 if (!mux_ops->get_parent) {
243 hw = ERR_PTR(-EINVAL);
244 goto err;
245 }
246
247 composite->mux_hw = mux_hw;
248 composite->mux_ops = mux_ops;
249 clk_composite_ops->get_parent = clk_composite_get_parent;
250 if (mux_ops->set_parent)
251 clk_composite_ops->set_parent = clk_composite_set_parent;
252 if (mux_ops->determine_rate)
253 clk_composite_ops->determine_rate = clk_composite_determine_rate;
254 }
255
256 if (rate_hw && rate_ops) {
257 if (!rate_ops->recalc_rate) {
258 hw = ERR_PTR(-EINVAL);
259 goto err;
260 }
261 clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
262
263 if (rate_ops->determine_rate)
264 clk_composite_ops->determine_rate =
265 clk_composite_determine_rate;
266
267 /* .set_rate requires .determine_rate */
268 if (rate_ops->set_rate) {
269 if (rate_ops->determine_rate)
270 clk_composite_ops->set_rate =
271 clk_composite_set_rate;
272 else
273 WARN(1, "%s: missing determine_rate op is required\n",
274 __func__);
275 }
276
277 composite->rate_hw = rate_hw;
278 composite->rate_ops = rate_ops;
279 }
280
281 if (mux_hw && mux_ops && rate_hw && rate_ops) {
282 if (mux_ops->set_parent && rate_ops->set_rate)
283 clk_composite_ops->set_rate_and_parent =
284 clk_composite_set_rate_and_parent;
285 }
286
287 if (gate_hw && gate_ops) {
288 if (!gate_ops->is_enabled || !gate_ops->enable ||
289 !gate_ops->disable) {
290 hw = ERR_PTR(-EINVAL);
291 goto err;
292 }
293
294 composite->gate_hw = gate_hw;
295 composite->gate_ops = gate_ops;
296 clk_composite_ops->is_enabled = clk_composite_is_enabled;
297 clk_composite_ops->enable = clk_composite_enable;
298 clk_composite_ops->disable = clk_composite_disable;
299 }
300
301 init.ops = clk_composite_ops;
302 composite->hw.init = &init;
303
304 ret = clk_hw_register(dev, hw);
305 if (ret) {
306 hw = ERR_PTR(ret);
307 goto err;
308 }
309
310 if (composite->mux_hw)
311 composite->mux_hw->clk = hw->clk;
312
313 if (composite->rate_hw)
314 composite->rate_hw->clk = hw->clk;
315
316 if (composite->gate_hw)
317 composite->gate_hw->clk = hw->clk;
318
319 return hw;
320
321err:
322 kfree(composite);
323 return hw;
324}
325
326struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name,
327 const char * const *parent_names, int num_parents,
328 struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
329 struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
330 struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
331 unsigned long flags)
332{
333 return __clk_hw_register_composite(dev, name, parent_names, NULL,
334 num_parents, mux_hw, mux_ops,
335 rate_hw, rate_ops, gate_hw,
336 gate_ops, flags);
337}
338EXPORT_SYMBOL_GPL(clk_hw_register_composite);
339
340struct clk_hw *clk_hw_register_composite_pdata(struct device *dev,
341 const char *name,
342 const struct clk_parent_data *parent_data,
343 int num_parents,
344 struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
345 struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
346 struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
347 unsigned long flags)
348{
349 return __clk_hw_register_composite(dev, name, NULL, parent_data,
350 num_parents, mux_hw, mux_ops,
351 rate_hw, rate_ops, gate_hw,
352 gate_ops, flags);
353}
354
355struct clk *clk_register_composite(struct device *dev, const char *name,
356 const char * const *parent_names, int num_parents,
357 struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
358 struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
359 struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
360 unsigned long flags)
361{
362 struct clk_hw *hw;
363
364 hw = clk_hw_register_composite(dev, name, parent_names, num_parents,
365 mux_hw, mux_ops, rate_hw, rate_ops, gate_hw, gate_ops,
366 flags);
367 if (IS_ERR(hw))
368 return ERR_CAST(hw);
369 return hw->clk;
370}
371EXPORT_SYMBOL_GPL(clk_register_composite);
372
373struct clk *clk_register_composite_pdata(struct device *dev, const char *name,
374 const struct clk_parent_data *parent_data,
375 int num_parents,
376 struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
377 struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
378 struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
379 unsigned long flags)
380{
381 struct clk_hw *hw;
382
383 hw = clk_hw_register_composite_pdata(dev, name, parent_data,
384 num_parents, mux_hw, mux_ops, rate_hw, rate_ops,
385 gate_hw, gate_ops, flags);
386 if (IS_ERR(hw))
387 return ERR_CAST(hw);
388 return hw->clk;
389}
390
391void clk_unregister_composite(struct clk *clk)
392{
393 struct clk_composite *composite;
394 struct clk_hw *hw;
395
396 hw = __clk_get_hw(clk);
397 if (!hw)
398 return;
399
400 composite = to_clk_composite(hw);
401
402 clk_unregister(clk);
403 kfree(composite);
404}
405
406void clk_hw_unregister_composite(struct clk_hw *hw)
407{
408 struct clk_composite *composite;
409
410 composite = to_clk_composite(hw);
411
412 clk_hw_unregister(hw);
413 kfree(composite);
414}
415EXPORT_SYMBOL_GPL(clk_hw_unregister_composite);
416
417static void devm_clk_hw_release_composite(struct device *dev, void *res)
418{
419 clk_hw_unregister_composite(*(struct clk_hw **)res);
420}
421
422static struct clk_hw *__devm_clk_hw_register_composite(struct device *dev,
423 const char *name, const char * const *parent_names,
424 const struct clk_parent_data *pdata, int num_parents,
425 struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
426 struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
427 struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
428 unsigned long flags)
429{
430 struct clk_hw **ptr, *hw;
431
432 ptr = devres_alloc(devm_clk_hw_release_composite, sizeof(*ptr),
433 GFP_KERNEL);
434 if (!ptr)
435 return ERR_PTR(-ENOMEM);
436
437 hw = __clk_hw_register_composite(dev, name, parent_names, pdata,
438 num_parents, mux_hw, mux_ops, rate_hw,
439 rate_ops, gate_hw, gate_ops, flags);
440
441 if (!IS_ERR(hw)) {
442 *ptr = hw;
443 devres_add(dev, ptr);
444 } else {
445 devres_free(ptr);
446 }
447
448 return hw;
449}
450
451struct clk_hw *devm_clk_hw_register_composite_pdata(struct device *dev,
452 const char *name,
453 const struct clk_parent_data *parent_data,
454 int num_parents,
455 struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
456 struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
457 struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
458 unsigned long flags)
459{
460 return __devm_clk_hw_register_composite(dev, name, NULL, parent_data,
461 num_parents, mux_hw, mux_ops,
462 rate_hw, rate_ops, gate_hw,
463 gate_ops, flags);
464}