xref: /openbmc/linux/drivers/clk/mediatek/clk-mtk.c (revision 8dd3cdea)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2014 MediaTek Inc.
4  * Author: James Liao <jamesjj.liao@mediatek.com>
5  */
6 
7 #include <linux/bitops.h>
8 #include <linux/clk-provider.h>
9 #include <linux/err.h>
10 #include <linux/io.h>
11 #include <linux/mfd/syscon.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/of_device.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
17 
18 #include "clk-mtk.h"
19 #include "clk-gate.h"
20 
21 struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num)
22 {
23 	int i;
24 	struct clk_onecell_data *clk_data;
25 
26 	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
27 	if (!clk_data)
28 		return NULL;
29 
30 	clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL);
31 	if (!clk_data->clks)
32 		goto err_out;
33 
34 	clk_data->clk_num = clk_num;
35 
36 	for (i = 0; i < clk_num; i++)
37 		clk_data->clks[i] = ERR_PTR(-ENOENT);
38 
39 	return clk_data;
40 err_out:
41 	kfree(clk_data);
42 
43 	return NULL;
44 }
45 EXPORT_SYMBOL_GPL(mtk_alloc_clk_data);
46 
47 void mtk_free_clk_data(struct clk_onecell_data *clk_data)
48 {
49 	if (!clk_data)
50 		return;
51 
52 	kfree(clk_data->clks);
53 	kfree(clk_data);
54 }
55 
56 int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num,
57 				struct clk_onecell_data *clk_data)
58 {
59 	int i;
60 	struct clk *clk;
61 
62 	if (!clk_data)
63 		return -ENOMEM;
64 
65 	for (i = 0; i < num; i++) {
66 		const struct mtk_fixed_clk *rc = &clks[i];
67 
68 		if (!IS_ERR_OR_NULL(clk_data->clks[rc->id])) {
69 			pr_warn("Trying to register duplicate clock ID: %d\n", rc->id);
70 			continue;
71 		}
72 
73 		clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
74 					      rc->rate);
75 
76 		if (IS_ERR(clk)) {
77 			pr_err("Failed to register clk %s: %pe\n", rc->name, clk);
78 			goto err;
79 		}
80 
81 		clk_data->clks[rc->id] = clk;
82 	}
83 
84 	return 0;
85 
86 err:
87 	while (--i >= 0) {
88 		const struct mtk_fixed_clk *rc = &clks[i];
89 
90 		if (IS_ERR_OR_NULL(clk_data->clks[rc->id]))
91 			continue;
92 
93 		clk_unregister_fixed_rate(clk_data->clks[rc->id]);
94 		clk_data->clks[rc->id] = ERR_PTR(-ENOENT);
95 	}
96 
97 	return PTR_ERR(clk);
98 }
99 EXPORT_SYMBOL_GPL(mtk_clk_register_fixed_clks);
100 
101 void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num,
102 				   struct clk_onecell_data *clk_data)
103 {
104 	int i;
105 
106 	if (!clk_data)
107 		return;
108 
109 	for (i = num; i > 0; i--) {
110 		const struct mtk_fixed_clk *rc = &clks[i - 1];
111 
112 		if (IS_ERR_OR_NULL(clk_data->clks[rc->id]))
113 			continue;
114 
115 		clk_unregister_fixed_rate(clk_data->clks[rc->id]);
116 		clk_data->clks[rc->id] = ERR_PTR(-ENOENT);
117 	}
118 }
119 EXPORT_SYMBOL_GPL(mtk_clk_unregister_fixed_clks);
120 
121 int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
122 			     struct clk_onecell_data *clk_data)
123 {
124 	int i;
125 	struct clk *clk;
126 
127 	if (!clk_data)
128 		return -ENOMEM;
129 
130 	for (i = 0; i < num; i++) {
131 		const struct mtk_fixed_factor *ff = &clks[i];
132 
133 		if (!IS_ERR_OR_NULL(clk_data->clks[ff->id])) {
134 			pr_warn("Trying to register duplicate clock ID: %d\n", ff->id);
135 			continue;
136 		}
137 
138 		clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
139 				CLK_SET_RATE_PARENT, ff->mult, ff->div);
140 
141 		if (IS_ERR(clk)) {
142 			pr_err("Failed to register clk %s: %pe\n", ff->name, clk);
143 			goto err;
144 		}
145 
146 		clk_data->clks[ff->id] = clk;
147 	}
148 
149 	return 0;
150 
151 err:
152 	while (--i >= 0) {
153 		const struct mtk_fixed_factor *ff = &clks[i];
154 
155 		if (IS_ERR_OR_NULL(clk_data->clks[ff->id]))
156 			continue;
157 
158 		clk_unregister_fixed_factor(clk_data->clks[ff->id]);
159 		clk_data->clks[ff->id] = ERR_PTR(-ENOENT);
160 	}
161 
162 	return PTR_ERR(clk);
163 }
164 EXPORT_SYMBOL_GPL(mtk_clk_register_factors);
165 
166 void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
167 				struct clk_onecell_data *clk_data)
168 {
169 	int i;
170 
171 	if (!clk_data)
172 		return;
173 
174 	for (i = num; i > 0; i--) {
175 		const struct mtk_fixed_factor *ff = &clks[i - 1];
176 
177 		if (IS_ERR_OR_NULL(clk_data->clks[ff->id]))
178 			continue;
179 
180 		clk_unregister_fixed_factor(clk_data->clks[ff->id]);
181 		clk_data->clks[ff->id] = ERR_PTR(-ENOENT);
182 	}
183 }
184 EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors);
185 
186 struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
187 		void __iomem *base, spinlock_t *lock)
188 {
189 	struct clk *clk;
190 	struct clk_mux *mux = NULL;
191 	struct clk_gate *gate = NULL;
192 	struct clk_divider *div = NULL;
193 	struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
194 	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
195 	const char * const *parent_names;
196 	const char *parent;
197 	int num_parents;
198 	int ret;
199 
200 	if (mc->mux_shift >= 0) {
201 		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
202 		if (!mux)
203 			return ERR_PTR(-ENOMEM);
204 
205 		mux->reg = base + mc->mux_reg;
206 		mux->mask = BIT(mc->mux_width) - 1;
207 		mux->shift = mc->mux_shift;
208 		mux->lock = lock;
209 		mux->flags = mc->mux_flags;
210 		mux_hw = &mux->hw;
211 		mux_ops = &clk_mux_ops;
212 
213 		parent_names = mc->parent_names;
214 		num_parents = mc->num_parents;
215 	} else {
216 		parent = mc->parent;
217 		parent_names = &parent;
218 		num_parents = 1;
219 	}
220 
221 	if (mc->gate_shift >= 0) {
222 		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
223 		if (!gate) {
224 			ret = -ENOMEM;
225 			goto err_out;
226 		}
227 
228 		gate->reg = base + mc->gate_reg;
229 		gate->bit_idx = mc->gate_shift;
230 		gate->flags = CLK_GATE_SET_TO_DISABLE;
231 		gate->lock = lock;
232 
233 		gate_hw = &gate->hw;
234 		gate_ops = &clk_gate_ops;
235 	}
236 
237 	if (mc->divider_shift >= 0) {
238 		div = kzalloc(sizeof(*div), GFP_KERNEL);
239 		if (!div) {
240 			ret = -ENOMEM;
241 			goto err_out;
242 		}
243 
244 		div->reg = base + mc->divider_reg;
245 		div->shift = mc->divider_shift;
246 		div->width = mc->divider_width;
247 		div->lock = lock;
248 
249 		div_hw = &div->hw;
250 		div_ops = &clk_divider_ops;
251 	}
252 
253 	clk = clk_register_composite(NULL, mc->name, parent_names, num_parents,
254 		mux_hw, mux_ops,
255 		div_hw, div_ops,
256 		gate_hw, gate_ops,
257 		mc->flags);
258 
259 	if (IS_ERR(clk)) {
260 		ret = PTR_ERR(clk);
261 		goto err_out;
262 	}
263 
264 	return clk;
265 err_out:
266 	kfree(div);
267 	kfree(gate);
268 	kfree(mux);
269 
270 	return ERR_PTR(ret);
271 }
272 
273 static void mtk_clk_unregister_composite(struct clk *clk)
274 {
275 	struct clk_hw *hw;
276 	struct clk_composite *composite;
277 	struct clk_mux *mux = NULL;
278 	struct clk_gate *gate = NULL;
279 	struct clk_divider *div = NULL;
280 
281 	hw = __clk_get_hw(clk);
282 	if (!hw)
283 		return;
284 
285 	composite = to_clk_composite(hw);
286 	if (composite->mux_hw)
287 		mux = to_clk_mux(composite->mux_hw);
288 	if (composite->gate_hw)
289 		gate = to_clk_gate(composite->gate_hw);
290 	if (composite->rate_hw)
291 		div = to_clk_divider(composite->rate_hw);
292 
293 	clk_unregister_composite(clk);
294 	kfree(div);
295 	kfree(gate);
296 	kfree(mux);
297 }
298 
299 int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
300 				void __iomem *base, spinlock_t *lock,
301 				struct clk_onecell_data *clk_data)
302 {
303 	struct clk *clk;
304 	int i;
305 
306 	if (!clk_data)
307 		return -ENOMEM;
308 
309 	for (i = 0; i < num; i++) {
310 		const struct mtk_composite *mc = &mcs[i];
311 
312 		if (!IS_ERR_OR_NULL(clk_data->clks[mc->id])) {
313 			pr_warn("Trying to register duplicate clock ID: %d\n",
314 				mc->id);
315 			continue;
316 		}
317 
318 		clk = mtk_clk_register_composite(mc, base, lock);
319 
320 		if (IS_ERR(clk)) {
321 			pr_err("Failed to register clk %s: %pe\n", mc->name, clk);
322 			goto err;
323 		}
324 
325 		clk_data->clks[mc->id] = clk;
326 	}
327 
328 	return 0;
329 
330 err:
331 	while (--i >= 0) {
332 		const struct mtk_composite *mc = &mcs[i];
333 
334 		if (IS_ERR_OR_NULL(clk_data->clks[mcs->id]))
335 			continue;
336 
337 		mtk_clk_unregister_composite(clk_data->clks[mc->id]);
338 		clk_data->clks[mc->id] = ERR_PTR(-ENOENT);
339 	}
340 
341 	return PTR_ERR(clk);
342 }
343 EXPORT_SYMBOL_GPL(mtk_clk_register_composites);
344 
345 void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
346 				   struct clk_onecell_data *clk_data)
347 {
348 	int i;
349 
350 	if (!clk_data)
351 		return;
352 
353 	for (i = num; i > 0; i--) {
354 		const struct mtk_composite *mc = &mcs[i - 1];
355 
356 		if (IS_ERR_OR_NULL(clk_data->clks[mc->id]))
357 			continue;
358 
359 		mtk_clk_unregister_composite(clk_data->clks[mc->id]);
360 		clk_data->clks[mc->id] = ERR_PTR(-ENOENT);
361 	}
362 }
363 EXPORT_SYMBOL_GPL(mtk_clk_unregister_composites);
364 
365 int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num,
366 			      void __iomem *base, spinlock_t *lock,
367 			      struct clk_onecell_data *clk_data)
368 {
369 	struct clk *clk;
370 	int i;
371 
372 	if (!clk_data)
373 		return -ENOMEM;
374 
375 	for (i = 0; i <  num; i++) {
376 		const struct mtk_clk_divider *mcd = &mcds[i];
377 
378 		if (!IS_ERR_OR_NULL(clk_data->clks[mcd->id])) {
379 			pr_warn("Trying to register duplicate clock ID: %d\n",
380 				mcd->id);
381 			continue;
382 		}
383 
384 		clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
385 			mcd->flags, base +  mcd->div_reg, mcd->div_shift,
386 			mcd->div_width, mcd->clk_divider_flags, lock);
387 
388 		if (IS_ERR(clk)) {
389 			pr_err("Failed to register clk %s: %pe\n", mcd->name, clk);
390 			goto err;
391 		}
392 
393 		clk_data->clks[mcd->id] = clk;
394 	}
395 
396 	return 0;
397 
398 err:
399 	while (--i >= 0) {
400 		const struct mtk_clk_divider *mcd = &mcds[i];
401 
402 		if (IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
403 			continue;
404 
405 		mtk_clk_unregister_composite(clk_data->clks[mcd->id]);
406 		clk_data->clks[mcd->id] = ERR_PTR(-ENOENT);
407 	}
408 
409 	return PTR_ERR(clk);
410 }
411 
412 void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num,
413 				 struct clk_onecell_data *clk_data)
414 {
415 	int i;
416 
417 	if (!clk_data)
418 		return;
419 
420 	for (i = num; i > 0; i--) {
421 		const struct mtk_clk_divider *mcd = &mcds[i - 1];
422 
423 		if (IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
424 			continue;
425 
426 		clk_unregister_divider(clk_data->clks[mcd->id]);
427 		clk_data->clks[mcd->id] = ERR_PTR(-ENOENT);
428 	}
429 }
430 
431 int mtk_clk_simple_probe(struct platform_device *pdev)
432 {
433 	const struct mtk_clk_desc *mcd;
434 	struct clk_onecell_data *clk_data;
435 	struct device_node *node = pdev->dev.of_node;
436 	int r;
437 
438 	mcd = of_device_get_match_data(&pdev->dev);
439 	if (!mcd)
440 		return -EINVAL;
441 
442 	clk_data = mtk_alloc_clk_data(mcd->num_clks);
443 	if (!clk_data)
444 		return -ENOMEM;
445 
446 	r = mtk_clk_register_gates(node, mcd->clks, mcd->num_clks, clk_data);
447 	if (r)
448 		goto free_data;
449 
450 	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
451 	if (r)
452 		goto unregister_clks;
453 
454 	platform_set_drvdata(pdev, clk_data);
455 
456 	return r;
457 
458 unregister_clks:
459 	mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
460 free_data:
461 	mtk_free_clk_data(clk_data);
462 	return r;
463 }
464 
465 int mtk_clk_simple_remove(struct platform_device *pdev)
466 {
467 	const struct mtk_clk_desc *mcd = of_device_get_match_data(&pdev->dev);
468 	struct clk_onecell_data *clk_data = platform_get_drvdata(pdev);
469 	struct device_node *node = pdev->dev.of_node;
470 
471 	of_clk_del_provider(node);
472 	mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
473 	mtk_free_clk_data(clk_data);
474 
475 	return 0;
476 }
477 
478 MODULE_LICENSE("GPL");
479