1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> |
4 | */ |
5 | #include <linux/module.h> |
6 | #include <linux/clk-provider.h> |
7 | #include <linux/slab.h> |
8 | #include <linux/err.h> |
9 | #include <linux/of.h> |
10 | #include <linux/platform_device.h> |
11 | |
12 | /* |
13 | * DOC: basic fixed multiplier and divider clock that cannot gate |
14 | * |
15 | * Traits of this clock: |
16 | * prepare - clk_prepare only ensures that parents are prepared |
17 | * enable - clk_enable only ensures that parents are enabled |
18 | * rate - rate is fixed. clk->rate = parent->rate / div * mult |
19 | * parent - fixed parent. No clk_set_parent support |
20 | */ |
21 | |
22 | static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, |
23 | unsigned long parent_rate) |
24 | { |
25 | struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); |
26 | unsigned long long int rate; |
27 | |
28 | rate = (unsigned long long int)parent_rate * fix->mult; |
29 | do_div(rate, fix->div); |
30 | return (unsigned long)rate; |
31 | } |
32 | |
33 | static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate, |
34 | unsigned long *prate) |
35 | { |
36 | struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); |
37 | |
38 | if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { |
39 | unsigned long best_parent; |
40 | |
41 | best_parent = (rate / fix->mult) * fix->div; |
42 | *prate = clk_hw_round_rate(hw: clk_hw_get_parent(hw), rate: best_parent); |
43 | } |
44 | |
45 | return (*prate / fix->div) * fix->mult; |
46 | } |
47 | |
48 | static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate, |
49 | unsigned long parent_rate) |
50 | { |
51 | /* |
52 | * We must report success but we can do so unconditionally because |
53 | * clk_factor_round_rate returns values that ensure this call is a |
54 | * nop. |
55 | */ |
56 | |
57 | return 0; |
58 | } |
59 | |
60 | static unsigned long clk_factor_recalc_accuracy(struct clk_hw *hw, |
61 | unsigned long parent_accuracy) |
62 | { |
63 | struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); |
64 | |
65 | if (fix->flags & CLK_FIXED_FACTOR_FIXED_ACCURACY) |
66 | return fix->acc; |
67 | |
68 | return parent_accuracy; |
69 | } |
70 | |
71 | const struct clk_ops clk_fixed_factor_ops = { |
72 | .round_rate = clk_factor_round_rate, |
73 | .set_rate = clk_factor_set_rate, |
74 | .recalc_rate = clk_factor_recalc_rate, |
75 | .recalc_accuracy = clk_factor_recalc_accuracy, |
76 | }; |
77 | EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); |
78 | |
79 | static void devm_clk_hw_register_fixed_factor_release(struct device *dev, void *res) |
80 | { |
81 | struct clk_fixed_factor *fix = res; |
82 | |
83 | /* |
84 | * We can not use clk_hw_unregister_fixed_factor, since it will kfree() |
85 | * the hw, resulting in double free. Just unregister the hw and let |
86 | * devres code kfree() it. |
87 | */ |
88 | clk_hw_unregister(hw: &fix->hw); |
89 | } |
90 | |
91 | static struct clk_hw * |
92 | __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, |
93 | const char *name, const char *parent_name, |
94 | const struct clk_hw *parent_hw, const struct clk_parent_data *pdata, |
95 | unsigned long flags, unsigned int mult, unsigned int div, |
96 | unsigned long acc, unsigned int fixflags, bool devm) |
97 | { |
98 | struct clk_fixed_factor *fix; |
99 | struct clk_init_data init = { }; |
100 | struct clk_hw *hw; |
101 | int ret; |
102 | |
103 | /* You can't use devm without a dev */ |
104 | if (devm && !dev) |
105 | return ERR_PTR(error: -EINVAL); |
106 | |
107 | if (devm) |
108 | fix = devres_alloc(devm_clk_hw_register_fixed_factor_release, |
109 | sizeof(*fix), GFP_KERNEL); |
110 | else |
111 | fix = kmalloc(size: sizeof(*fix), GFP_KERNEL); |
112 | if (!fix) |
113 | return ERR_PTR(error: -ENOMEM); |
114 | |
115 | /* struct clk_fixed_factor assignments */ |
116 | fix->mult = mult; |
117 | fix->div = div; |
118 | fix->hw.init = &init; |
119 | fix->acc = acc; |
120 | fix->flags = fixflags; |
121 | |
122 | init.name = name; |
123 | init.ops = &clk_fixed_factor_ops; |
124 | init.flags = flags; |
125 | if (parent_name) |
126 | init.parent_names = &parent_name; |
127 | else if (parent_hw) |
128 | init.parent_hws = &parent_hw; |
129 | else |
130 | init.parent_data = pdata; |
131 | init.num_parents = 1; |
132 | |
133 | hw = &fix->hw; |
134 | if (dev) |
135 | ret = clk_hw_register(dev, hw); |
136 | else |
137 | ret = of_clk_hw_register(node: np, hw); |
138 | if (ret) { |
139 | if (devm) |
140 | devres_free(res: fix); |
141 | else |
142 | kfree(objp: fix); |
143 | hw = ERR_PTR(error: ret); |
144 | } else if (devm) |
145 | devres_add(dev, res: fix); |
146 | |
147 | return hw; |
148 | } |
149 | |
150 | /** |
151 | * devm_clk_hw_register_fixed_factor_index - Register a fixed factor clock with |
152 | * parent from DT index |
153 | * @dev: device that is registering this clock |
154 | * @name: name of this clock |
155 | * @index: index of phandle in @dev 'clocks' property |
156 | * @flags: fixed factor flags |
157 | * @mult: multiplier |
158 | * @div: divider |
159 | * |
160 | * Return: Pointer to fixed factor clk_hw structure that was registered or |
161 | * an error pointer. |
162 | */ |
163 | struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev, |
164 | const char *name, unsigned int index, unsigned long flags, |
165 | unsigned int mult, unsigned int div) |
166 | { |
167 | const struct clk_parent_data pdata = { .index = index }; |
168 | |
169 | return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, pdata: &pdata, |
170 | flags, mult, div, acc: 0, fixflags: 0, devm: true); |
171 | } |
172 | EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index); |
173 | |
174 | /** |
175 | * devm_clk_hw_register_fixed_factor_parent_hw - Register a fixed factor clock with |
176 | * pointer to parent clock |
177 | * @dev: device that is registering this clock |
178 | * @name: name of this clock |
179 | * @parent_hw: pointer to parent clk |
180 | * @flags: fixed factor flags |
181 | * @mult: multiplier |
182 | * @div: divider |
183 | * |
184 | * Return: Pointer to fixed factor clk_hw structure that was registered or |
185 | * an error pointer. |
186 | */ |
187 | struct clk_hw *devm_clk_hw_register_fixed_factor_parent_hw(struct device *dev, |
188 | const char *name, const struct clk_hw *parent_hw, |
189 | unsigned long flags, unsigned int mult, unsigned int div) |
190 | { |
191 | const struct clk_parent_data pdata = { .index = -1 }; |
192 | |
193 | return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, parent_hw, |
194 | pdata: &pdata, flags, mult, div, acc: 0, fixflags: 0, devm: true); |
195 | } |
196 | EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_parent_hw); |
197 | |
198 | struct clk_hw *clk_hw_register_fixed_factor_parent_hw(struct device *dev, |
199 | const char *name, const struct clk_hw *parent_hw, |
200 | unsigned long flags, unsigned int mult, unsigned int div) |
201 | { |
202 | const struct clk_parent_data pdata = { .index = -1 }; |
203 | |
204 | return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, parent_hw, |
205 | pdata: &pdata, flags, mult, div, acc: 0, fixflags: 0, devm: false); |
206 | } |
207 | EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_parent_hw); |
208 | |
209 | struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, |
210 | const char *name, const char *parent_name, unsigned long flags, |
211 | unsigned int mult, unsigned int div) |
212 | { |
213 | const struct clk_parent_data pdata = { .index = -1 }; |
214 | |
215 | return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, |
216 | pdata: &pdata, flags, mult, div, acc: 0, fixflags: 0, devm: false); |
217 | } |
218 | EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor); |
219 | |
220 | struct clk_hw *clk_hw_register_fixed_factor_fwname(struct device *dev, |
221 | struct device_node *np, const char *name, const char *fw_name, |
222 | unsigned long flags, unsigned int mult, unsigned int div) |
223 | { |
224 | const struct clk_parent_data pdata = { .index = -1, .fw_name = fw_name }; |
225 | |
226 | return __clk_hw_register_fixed_factor(dev, np, name, NULL, NULL, |
227 | pdata: &pdata, flags, mult, div, acc: 0, fixflags: 0, devm: false); |
228 | } |
229 | EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_fwname); |
230 | |
231 | struct clk_hw *clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *dev, |
232 | struct device_node *np, const char *name, const char *fw_name, |
233 | unsigned long flags, unsigned int mult, unsigned int div, |
234 | unsigned long acc) |
235 | { |
236 | const struct clk_parent_data pdata = { .index = -1, .fw_name = fw_name }; |
237 | |
238 | return __clk_hw_register_fixed_factor(dev, np, name, NULL, NULL, |
239 | pdata: &pdata, flags, mult, div, acc, |
240 | CLK_FIXED_FACTOR_FIXED_ACCURACY, devm: false); |
241 | } |
242 | EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_with_accuracy_fwname); |
243 | |
244 | struct clk *clk_register_fixed_factor(struct device *dev, const char *name, |
245 | const char *parent_name, unsigned long flags, |
246 | unsigned int mult, unsigned int div) |
247 | { |
248 | struct clk_hw *hw; |
249 | |
250 | hw = clk_hw_register_fixed_factor(dev, name, parent_name, flags, mult, |
251 | div); |
252 | if (IS_ERR(ptr: hw)) |
253 | return ERR_CAST(ptr: hw); |
254 | return hw->clk; |
255 | } |
256 | EXPORT_SYMBOL_GPL(clk_register_fixed_factor); |
257 | |
258 | void clk_unregister_fixed_factor(struct clk *clk) |
259 | { |
260 | struct clk_hw *hw; |
261 | |
262 | hw = __clk_get_hw(clk); |
263 | if (!hw) |
264 | return; |
265 | |
266 | clk_unregister(clk); |
267 | kfree(to_clk_fixed_factor(hw)); |
268 | } |
269 | EXPORT_SYMBOL_GPL(clk_unregister_fixed_factor); |
270 | |
271 | void clk_hw_unregister_fixed_factor(struct clk_hw *hw) |
272 | { |
273 | struct clk_fixed_factor *fix; |
274 | |
275 | fix = to_clk_fixed_factor(hw); |
276 | |
277 | clk_hw_unregister(hw); |
278 | kfree(objp: fix); |
279 | } |
280 | EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_factor); |
281 | |
282 | struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev, |
283 | const char *name, const char *parent_name, unsigned long flags, |
284 | unsigned int mult, unsigned int div) |
285 | { |
286 | const struct clk_parent_data pdata = { .index = -1 }; |
287 | |
288 | return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, |
289 | pdata: &pdata, flags, mult, div, acc: 0, fixflags: 0, devm: true); |
290 | } |
291 | EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor); |
292 | |
293 | struct clk_hw *devm_clk_hw_register_fixed_factor_fwname(struct device *dev, |
294 | struct device_node *np, const char *name, const char *fw_name, |
295 | unsigned long flags, unsigned int mult, unsigned int div) |
296 | { |
297 | const struct clk_parent_data pdata = { .index = -1, .fw_name = fw_name }; |
298 | |
299 | return __clk_hw_register_fixed_factor(dev, np, name, NULL, NULL, |
300 | pdata: &pdata, flags, mult, div, acc: 0, fixflags: 0, devm: true); |
301 | } |
302 | EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_fwname); |
303 | |
304 | struct clk_hw *devm_clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *dev, |
305 | struct device_node *np, const char *name, const char *fw_name, |
306 | unsigned long flags, unsigned int mult, unsigned int div, |
307 | unsigned long acc) |
308 | { |
309 | const struct clk_parent_data pdata = { .index = -1, .fw_name = fw_name }; |
310 | |
311 | return __clk_hw_register_fixed_factor(dev, np, name, NULL, NULL, |
312 | pdata: &pdata, flags, mult, div, acc, |
313 | CLK_FIXED_FACTOR_FIXED_ACCURACY, devm: true); |
314 | } |
315 | EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_with_accuracy_fwname); |
316 | |
317 | #ifdef CONFIG_OF |
318 | static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node) |
319 | { |
320 | struct clk_hw *hw; |
321 | const char *clk_name = node->name; |
322 | const struct clk_parent_data pdata = { .index = 0 }; |
323 | u32 div, mult; |
324 | int ret; |
325 | |
326 | if (of_property_read_u32(np: node, propname: "clock-div" , out_value: &div)) { |
327 | pr_err("%s Fixed factor clock <%pOFn> must have a clock-div property\n" , |
328 | __func__, node); |
329 | return ERR_PTR(error: -EIO); |
330 | } |
331 | |
332 | if (of_property_read_u32(np: node, propname: "clock-mult" , out_value: &mult)) { |
333 | pr_err("%s Fixed factor clock <%pOFn> must have a clock-mult property\n" , |
334 | __func__, node); |
335 | return ERR_PTR(error: -EIO); |
336 | } |
337 | |
338 | of_property_read_string(np: node, propname: "clock-output-names" , out_string: &clk_name); |
339 | |
340 | hw = __clk_hw_register_fixed_factor(NULL, np: node, name: clk_name, NULL, NULL, |
341 | pdata: &pdata, flags: 0, mult, div, acc: 0, fixflags: 0, devm: false); |
342 | if (IS_ERR(ptr: hw)) { |
343 | /* |
344 | * Clear OF_POPULATED flag so that clock registration can be |
345 | * attempted again from probe function. |
346 | */ |
347 | of_node_clear_flag(n: node, OF_POPULATED); |
348 | return ERR_CAST(ptr: hw); |
349 | } |
350 | |
351 | ret = of_clk_add_hw_provider(np: node, get: of_clk_hw_simple_get, data: hw); |
352 | if (ret) { |
353 | clk_hw_unregister_fixed_factor(hw); |
354 | return ERR_PTR(error: ret); |
355 | } |
356 | |
357 | return hw; |
358 | } |
359 | |
360 | /** |
361 | * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock |
362 | * @node: device node for the clock |
363 | */ |
364 | void __init of_fixed_factor_clk_setup(struct device_node *node) |
365 | { |
366 | _of_fixed_factor_clk_setup(node); |
367 | } |
368 | CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock" , |
369 | of_fixed_factor_clk_setup); |
370 | |
371 | static void of_fixed_factor_clk_remove(struct platform_device *pdev) |
372 | { |
373 | struct clk_hw *clk = platform_get_drvdata(pdev); |
374 | |
375 | of_clk_del_provider(np: pdev->dev.of_node); |
376 | clk_hw_unregister_fixed_factor(clk); |
377 | } |
378 | |
379 | static int of_fixed_factor_clk_probe(struct platform_device *pdev) |
380 | { |
381 | struct clk_hw *clk; |
382 | |
383 | /* |
384 | * This function is not executed when of_fixed_factor_clk_setup |
385 | * succeeded. |
386 | */ |
387 | clk = _of_fixed_factor_clk_setup(node: pdev->dev.of_node); |
388 | if (IS_ERR(ptr: clk)) |
389 | return PTR_ERR(ptr: clk); |
390 | |
391 | platform_set_drvdata(pdev, data: clk); |
392 | |
393 | return 0; |
394 | } |
395 | |
396 | static const struct of_device_id of_fixed_factor_clk_ids[] = { |
397 | { .compatible = "fixed-factor-clock" }, |
398 | { } |
399 | }; |
400 | MODULE_DEVICE_TABLE(of, of_fixed_factor_clk_ids); |
401 | |
402 | static struct platform_driver of_fixed_factor_clk_driver = { |
403 | .driver = { |
404 | .name = "of_fixed_factor_clk" , |
405 | .of_match_table = of_fixed_factor_clk_ids, |
406 | }, |
407 | .probe = of_fixed_factor_clk_probe, |
408 | .remove_new = of_fixed_factor_clk_remove, |
409 | }; |
410 | builtin_platform_driver(of_fixed_factor_clk_driver); |
411 | #endif |
412 | |