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 | const struct clk_ops clk_fixed_factor_ops = { |
61 | .round_rate = clk_factor_round_rate, |
62 | .set_rate = clk_factor_set_rate, |
63 | .recalc_rate = clk_factor_recalc_rate, |
64 | }; |
65 | EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); |
66 | |
67 | static void devm_clk_hw_register_fixed_factor_release(struct device *dev, void *res) |
68 | { |
69 | struct clk_fixed_factor *fix = res; |
70 | |
71 | /* |
72 | * We can not use clk_hw_unregister_fixed_factor, since it will kfree() |
73 | * the hw, resulting in double free. Just unregister the hw and let |
74 | * devres code kfree() it. |
75 | */ |
76 | clk_hw_unregister(hw: &fix->hw); |
77 | } |
78 | |
79 | static struct clk_hw * |
80 | __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, |
81 | const char *name, const char *parent_name, |
82 | const struct clk_hw *parent_hw, int index, |
83 | unsigned long flags, unsigned int mult, unsigned int div, |
84 | bool devm) |
85 | { |
86 | struct clk_fixed_factor *fix; |
87 | struct clk_init_data init = { }; |
88 | struct clk_parent_data pdata = { .index = index }; |
89 | struct clk_hw *hw; |
90 | int ret; |
91 | |
92 | /* You can't use devm without a dev */ |
93 | if (devm && !dev) |
94 | return ERR_PTR(error: -EINVAL); |
95 | |
96 | if (devm) |
97 | fix = devres_alloc(devm_clk_hw_register_fixed_factor_release, |
98 | sizeof(*fix), GFP_KERNEL); |
99 | else |
100 | fix = kmalloc(size: sizeof(*fix), GFP_KERNEL); |
101 | if (!fix) |
102 | return ERR_PTR(error: -ENOMEM); |
103 | |
104 | /* struct clk_fixed_factor assignments */ |
105 | fix->mult = mult; |
106 | fix->div = div; |
107 | fix->hw.init = &init; |
108 | |
109 | init.name = name; |
110 | init.ops = &clk_fixed_factor_ops; |
111 | init.flags = flags; |
112 | if (parent_name) |
113 | init.parent_names = &parent_name; |
114 | else if (parent_hw) |
115 | init.parent_hws = &parent_hw; |
116 | else |
117 | init.parent_data = &pdata; |
118 | init.num_parents = 1; |
119 | |
120 | hw = &fix->hw; |
121 | if (dev) |
122 | ret = clk_hw_register(dev, hw); |
123 | else |
124 | ret = of_clk_hw_register(node: np, hw); |
125 | if (ret) { |
126 | if (devm) |
127 | devres_free(res: fix); |
128 | else |
129 | kfree(objp: fix); |
130 | hw = ERR_PTR(error: ret); |
131 | } else if (devm) |
132 | devres_add(dev, res: fix); |
133 | |
134 | return hw; |
135 | } |
136 | |
137 | /** |
138 | * devm_clk_hw_register_fixed_factor_index - Register a fixed factor clock with |
139 | * parent from DT index |
140 | * @dev: device that is registering this clock |
141 | * @name: name of this clock |
142 | * @index: index of phandle in @dev 'clocks' property |
143 | * @flags: fixed factor flags |
144 | * @mult: multiplier |
145 | * @div: divider |
146 | * |
147 | * Return: Pointer to fixed factor clk_hw structure that was registered or |
148 | * an error pointer. |
149 | */ |
150 | struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev, |
151 | const char *name, unsigned int index, unsigned long flags, |
152 | unsigned int mult, unsigned int div) |
153 | { |
154 | return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, index, |
155 | flags, mult, div, devm: true); |
156 | } |
157 | EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index); |
158 | |
159 | /** |
160 | * devm_clk_hw_register_fixed_factor_parent_hw - Register a fixed factor clock with |
161 | * pointer to parent clock |
162 | * @dev: device that is registering this clock |
163 | * @name: name of this clock |
164 | * @parent_hw: pointer to parent clk |
165 | * @flags: fixed factor flags |
166 | * @mult: multiplier |
167 | * @div: divider |
168 | * |
169 | * Return: Pointer to fixed factor clk_hw structure that was registered or |
170 | * an error pointer. |
171 | */ |
172 | struct clk_hw *devm_clk_hw_register_fixed_factor_parent_hw(struct device *dev, |
173 | const char *name, const struct clk_hw *parent_hw, |
174 | unsigned long flags, unsigned int mult, unsigned int div) |
175 | { |
176 | return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, parent_hw, |
177 | index: -1, flags, mult, div, devm: true); |
178 | } |
179 | EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_parent_hw); |
180 | |
181 | struct clk_hw *clk_hw_register_fixed_factor_parent_hw(struct device *dev, |
182 | const char *name, const struct clk_hw *parent_hw, |
183 | unsigned long flags, unsigned int mult, unsigned int div) |
184 | { |
185 | return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, |
186 | parent_hw, index: -1, flags, mult, div, |
187 | devm: false); |
188 | } |
189 | EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_parent_hw); |
190 | |
191 | struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, |
192 | const char *name, const char *parent_name, unsigned long flags, |
193 | unsigned int mult, unsigned int div) |
194 | { |
195 | return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, index: -1, |
196 | flags, mult, div, devm: false); |
197 | } |
198 | EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor); |
199 | |
200 | struct clk *clk_register_fixed_factor(struct device *dev, const char *name, |
201 | const char *parent_name, unsigned long flags, |
202 | unsigned int mult, unsigned int div) |
203 | { |
204 | struct clk_hw *hw; |
205 | |
206 | hw = clk_hw_register_fixed_factor(dev, name, parent_name, flags, mult, |
207 | div); |
208 | if (IS_ERR(ptr: hw)) |
209 | return ERR_CAST(ptr: hw); |
210 | return hw->clk; |
211 | } |
212 | EXPORT_SYMBOL_GPL(clk_register_fixed_factor); |
213 | |
214 | void clk_unregister_fixed_factor(struct clk *clk) |
215 | { |
216 | struct clk_hw *hw; |
217 | |
218 | hw = __clk_get_hw(clk); |
219 | if (!hw) |
220 | return; |
221 | |
222 | clk_unregister(clk); |
223 | kfree(to_clk_fixed_factor(hw)); |
224 | } |
225 | EXPORT_SYMBOL_GPL(clk_unregister_fixed_factor); |
226 | |
227 | void clk_hw_unregister_fixed_factor(struct clk_hw *hw) |
228 | { |
229 | struct clk_fixed_factor *fix; |
230 | |
231 | fix = to_clk_fixed_factor(hw); |
232 | |
233 | clk_hw_unregister(hw); |
234 | kfree(objp: fix); |
235 | } |
236 | EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_factor); |
237 | |
238 | struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev, |
239 | const char *name, const char *parent_name, unsigned long flags, |
240 | unsigned int mult, unsigned int div) |
241 | { |
242 | return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, index: -1, |
243 | flags, mult, div, devm: true); |
244 | } |
245 | EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor); |
246 | |
247 | #ifdef CONFIG_OF |
248 | static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node) |
249 | { |
250 | struct clk_hw *hw; |
251 | const char *clk_name = node->name; |
252 | u32 div, mult; |
253 | int ret; |
254 | |
255 | if (of_property_read_u32(np: node, propname: "clock-div" , out_value: &div)) { |
256 | pr_err("%s Fixed factor clock <%pOFn> must have a clock-div property\n" , |
257 | __func__, node); |
258 | return ERR_PTR(error: -EIO); |
259 | } |
260 | |
261 | if (of_property_read_u32(np: node, propname: "clock-mult" , out_value: &mult)) { |
262 | pr_err("%s Fixed factor clock <%pOFn> must have a clock-mult property\n" , |
263 | __func__, node); |
264 | return ERR_PTR(error: -EIO); |
265 | } |
266 | |
267 | of_property_read_string(np: node, propname: "clock-output-names" , out_string: &clk_name); |
268 | |
269 | hw = __clk_hw_register_fixed_factor(NULL, np: node, name: clk_name, NULL, NULL, index: 0, |
270 | flags: 0, mult, div, devm: false); |
271 | if (IS_ERR(ptr: hw)) { |
272 | /* |
273 | * Clear OF_POPULATED flag so that clock registration can be |
274 | * attempted again from probe function. |
275 | */ |
276 | of_node_clear_flag(n: node, OF_POPULATED); |
277 | return ERR_CAST(ptr: hw); |
278 | } |
279 | |
280 | ret = of_clk_add_hw_provider(np: node, get: of_clk_hw_simple_get, data: hw); |
281 | if (ret) { |
282 | clk_hw_unregister_fixed_factor(hw); |
283 | return ERR_PTR(error: ret); |
284 | } |
285 | |
286 | return hw; |
287 | } |
288 | |
289 | /** |
290 | * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock |
291 | * @node: device node for the clock |
292 | */ |
293 | void __init of_fixed_factor_clk_setup(struct device_node *node) |
294 | { |
295 | _of_fixed_factor_clk_setup(node); |
296 | } |
297 | CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock" , |
298 | of_fixed_factor_clk_setup); |
299 | |
300 | static void of_fixed_factor_clk_remove(struct platform_device *pdev) |
301 | { |
302 | struct clk_hw *clk = platform_get_drvdata(pdev); |
303 | |
304 | of_clk_del_provider(np: pdev->dev.of_node); |
305 | clk_hw_unregister_fixed_factor(clk); |
306 | } |
307 | |
308 | static int of_fixed_factor_clk_probe(struct platform_device *pdev) |
309 | { |
310 | struct clk_hw *clk; |
311 | |
312 | /* |
313 | * This function is not executed when of_fixed_factor_clk_setup |
314 | * succeeded. |
315 | */ |
316 | clk = _of_fixed_factor_clk_setup(node: pdev->dev.of_node); |
317 | if (IS_ERR(ptr: clk)) |
318 | return PTR_ERR(ptr: clk); |
319 | |
320 | platform_set_drvdata(pdev, data: clk); |
321 | |
322 | return 0; |
323 | } |
324 | |
325 | static const struct of_device_id of_fixed_factor_clk_ids[] = { |
326 | { .compatible = "fixed-factor-clock" }, |
327 | { } |
328 | }; |
329 | MODULE_DEVICE_TABLE(of, of_fixed_factor_clk_ids); |
330 | |
331 | static struct platform_driver of_fixed_factor_clk_driver = { |
332 | .driver = { |
333 | .name = "of_fixed_factor_clk" , |
334 | .of_match_table = of_fixed_factor_clk_ids, |
335 | }, |
336 | .probe = of_fixed_factor_clk_probe, |
337 | .remove_new = of_fixed_factor_clk_remove, |
338 | }; |
339 | builtin_platform_driver(of_fixed_factor_clk_driver); |
340 | #endif |
341 | |