xref: /openbmc/linux/drivers/clk/clk-axm5516.c (revision 495093ef)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * drivers/clk/clk-axm5516.c
4  *
5  * Provides clock implementations for three different types of clock devices on
6  * the Axxia device: PLL clock, a clock divider and a clock mux.
7  *
8  * Copyright (C) 2014 LSI Corporation
9  */
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/slab.h>
13 #include <linux/platform_device.h>
14 #include <linux/of.h>
15 #include <linux/of_address.h>
16 #include <linux/clk-provider.h>
17 #include <linux/regmap.h>
18 #include <dt-bindings/clock/lsi,axm5516-clks.h>
19 
20 
21 /**
22  * struct axxia_clk - Common struct to all Axxia clocks.
23  * @hw: clk_hw for the common clk framework
24  * @regmap: Regmap for the clock control registers
25  */
26 struct axxia_clk {
27 	struct clk_hw hw;
28 	struct regmap *regmap;
29 };
30 #define to_axxia_clk(_hw) container_of(_hw, struct axxia_clk, hw)
31 
32 /**
33  * struct axxia_pllclk - Axxia PLL generated clock.
34  * @aclk: Common struct
35  * @reg: Offset into regmap for PLL control register
36  */
37 struct axxia_pllclk {
38 	struct axxia_clk aclk;
39 	u32 reg;
40 };
41 #define to_axxia_pllclk(_aclk) container_of(_aclk, struct axxia_pllclk, aclk)
42 
43 /**
44  * axxia_pllclk_recalc - Calculate the PLL generated clock rate given the
45  * parent clock rate.
46  */
47 static unsigned long
axxia_pllclk_recalc(struct clk_hw * hw,unsigned long parent_rate)48 axxia_pllclk_recalc(struct clk_hw *hw, unsigned long parent_rate)
49 {
50 	struct axxia_clk *aclk = to_axxia_clk(hw);
51 	struct axxia_pllclk *pll = to_axxia_pllclk(aclk);
52 	unsigned long rate, fbdiv, refdiv, postdiv;
53 	u32 control;
54 
55 	regmap_read(aclk->regmap, pll->reg, &control);
56 	postdiv = ((control >> 0) & 0xf) + 1;
57 	fbdiv   = ((control >> 4) & 0xfff) + 3;
58 	refdiv  = ((control >> 16) & 0x1f) + 1;
59 	rate = (parent_rate / (refdiv * postdiv)) * fbdiv;
60 
61 	return rate;
62 }
63 
64 static const struct clk_ops axxia_pllclk_ops = {
65 	.recalc_rate = axxia_pllclk_recalc,
66 };
67 
68 /**
69  * struct axxia_divclk - Axxia clock divider
70  * @aclk: Common struct
71  * @reg: Offset into regmap for PLL control register
72  * @shift: Bit position for divider value
73  * @width: Number of bits in divider value
74  */
75 struct axxia_divclk {
76 	struct axxia_clk aclk;
77 	u32 reg;
78 	u32 shift;
79 	u32 width;
80 };
81 #define to_axxia_divclk(_aclk) container_of(_aclk, struct axxia_divclk, aclk)
82 
83 /**
84  * axxia_divclk_recalc_rate - Calculate clock divider output rage
85  */
86 static unsigned long
axxia_divclk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)87 axxia_divclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
88 {
89 	struct axxia_clk *aclk = to_axxia_clk(hw);
90 	struct axxia_divclk *divclk = to_axxia_divclk(aclk);
91 	u32 ctrl, div;
92 
93 	regmap_read(aclk->regmap, divclk->reg, &ctrl);
94 	div = 1 + ((ctrl >> divclk->shift) & ((1 << divclk->width)-1));
95 
96 	return parent_rate / div;
97 }
98 
99 static const struct clk_ops axxia_divclk_ops = {
100 	.recalc_rate = axxia_divclk_recalc_rate,
101 };
102 
103 /**
104  * struct axxia_clkmux - Axxia clock mux
105  * @aclk: Common struct
106  * @reg: Offset into regmap for PLL control register
107  * @shift: Bit position for selection value
108  * @width: Number of bits in selection value
109  */
110 struct axxia_clkmux {
111 	struct axxia_clk aclk;
112 	u32 reg;
113 	u32 shift;
114 	u32 width;
115 };
116 #define to_axxia_clkmux(_aclk) container_of(_aclk, struct axxia_clkmux, aclk)
117 
118 /**
119  * axxia_clkmux_get_parent - Return the index of selected parent clock
120  */
axxia_clkmux_get_parent(struct clk_hw * hw)121 static u8 axxia_clkmux_get_parent(struct clk_hw *hw)
122 {
123 	struct axxia_clk *aclk = to_axxia_clk(hw);
124 	struct axxia_clkmux *mux = to_axxia_clkmux(aclk);
125 	u32 ctrl, parent;
126 
127 	regmap_read(aclk->regmap, mux->reg, &ctrl);
128 	parent = (ctrl >> mux->shift) & ((1 << mux->width) - 1);
129 
130 	return (u8) parent;
131 }
132 
133 static const struct clk_ops axxia_clkmux_ops = {
134 	.get_parent = axxia_clkmux_get_parent,
135 };
136 
137 
138 /*
139  * PLLs
140  */
141 
142 static struct axxia_pllclk clk_fab_pll = {
143 	.aclk.hw.init = &(struct clk_init_data){
144 		.name = "clk_fab_pll",
145 		.parent_names = (const char *[]){
146 			"clk_ref0"
147 		},
148 		.num_parents = 1,
149 		.ops = &axxia_pllclk_ops,
150 	},
151 	.reg   = 0x01800,
152 };
153 
154 static struct axxia_pllclk clk_cpu_pll = {
155 	.aclk.hw.init = &(struct clk_init_data){
156 		.name = "clk_cpu_pll",
157 		.parent_names = (const char *[]){
158 			"clk_ref0"
159 		},
160 		.num_parents = 1,
161 		.ops = &axxia_pllclk_ops,
162 	},
163 	.reg   = 0x02000,
164 };
165 
166 static struct axxia_pllclk clk_sys_pll = {
167 	.aclk.hw.init = &(struct clk_init_data){
168 		.name = "clk_sys_pll",
169 		.parent_names = (const char *[]){
170 			"clk_ref0"
171 		},
172 		.num_parents = 1,
173 		.ops = &axxia_pllclk_ops,
174 	},
175 	.reg   = 0x02800,
176 };
177 
178 static struct axxia_pllclk clk_sm0_pll = {
179 	.aclk.hw.init = &(struct clk_init_data){
180 		.name = "clk_sm0_pll",
181 		.parent_names = (const char *[]){
182 			"clk_ref2"
183 		},
184 		.num_parents = 1,
185 		.ops = &axxia_pllclk_ops,
186 	},
187 	.reg   = 0x03000,
188 };
189 
190 static struct axxia_pllclk clk_sm1_pll = {
191 	.aclk.hw.init = &(struct clk_init_data){
192 		.name = "clk_sm1_pll",
193 		.parent_names = (const char *[]){
194 			"clk_ref1"
195 		},
196 		.num_parents = 1,
197 		.ops = &axxia_pllclk_ops,
198 	},
199 	.reg   = 0x03800,
200 };
201 
202 /*
203  * Clock dividers
204  */
205 
206 static struct axxia_divclk clk_cpu0_div = {
207 	.aclk.hw.init = &(struct clk_init_data){
208 		.name = "clk_cpu0_div",
209 		.parent_names = (const char *[]){
210 			"clk_cpu_pll"
211 		},
212 		.num_parents = 1,
213 		.ops = &axxia_divclk_ops,
214 	},
215 	.reg   = 0x10008,
216 	.shift = 0,
217 	.width = 4,
218 };
219 
220 static struct axxia_divclk clk_cpu1_div = {
221 	.aclk.hw.init = &(struct clk_init_data){
222 		.name = "clk_cpu1_div",
223 		.parent_names = (const char *[]){
224 			"clk_cpu_pll"
225 		},
226 		.num_parents = 1,
227 		.ops = &axxia_divclk_ops,
228 	},
229 	.reg   = 0x10008,
230 	.shift = 4,
231 	.width = 4,
232 };
233 
234 static struct axxia_divclk clk_cpu2_div = {
235 	.aclk.hw.init = &(struct clk_init_data){
236 		.name = "clk_cpu2_div",
237 		.parent_names = (const char *[]){
238 			"clk_cpu_pll"
239 		},
240 		.num_parents = 1,
241 		.ops = &axxia_divclk_ops,
242 	},
243 	.reg   = 0x10008,
244 	.shift = 8,
245 	.width = 4,
246 };
247 
248 static struct axxia_divclk clk_cpu3_div = {
249 	.aclk.hw.init = &(struct clk_init_data){
250 		.name = "clk_cpu3_div",
251 		.parent_names = (const char *[]){
252 			"clk_cpu_pll"
253 		},
254 		.num_parents = 1,
255 		.ops = &axxia_divclk_ops,
256 	},
257 	.reg   = 0x10008,
258 	.shift = 12,
259 	.width = 4,
260 };
261 
262 static struct axxia_divclk clk_nrcp_div = {
263 	.aclk.hw.init = &(struct clk_init_data){
264 		.name = "clk_nrcp_div",
265 		.parent_names = (const char *[]){
266 			"clk_sys_pll"
267 		},
268 		.num_parents = 1,
269 		.ops = &axxia_divclk_ops,
270 	},
271 	.reg   = 0x1000c,
272 	.shift = 0,
273 	.width = 4,
274 };
275 
276 static struct axxia_divclk clk_sys_div = {
277 	.aclk.hw.init = &(struct clk_init_data){
278 		.name = "clk_sys_div",
279 		.parent_names = (const char *[]){
280 			"clk_sys_pll"
281 		},
282 		.num_parents = 1,
283 		.ops = &axxia_divclk_ops,
284 	},
285 	.reg   = 0x1000c,
286 	.shift = 4,
287 	.width = 4,
288 };
289 
290 static struct axxia_divclk clk_fab_div = {
291 	.aclk.hw.init = &(struct clk_init_data){
292 		.name = "clk_fab_div",
293 		.parent_names = (const char *[]){
294 			"clk_fab_pll"
295 		},
296 		.num_parents = 1,
297 		.ops = &axxia_divclk_ops,
298 	},
299 	.reg   = 0x1000c,
300 	.shift = 8,
301 	.width = 4,
302 };
303 
304 static struct axxia_divclk clk_per_div = {
305 	.aclk.hw.init = &(struct clk_init_data){
306 		.name = "clk_per_div",
307 		.parent_names = (const char *[]){
308 			"clk_sm1_pll"
309 		},
310 		.num_parents = 1,
311 		.ops = &axxia_divclk_ops,
312 	},
313 	.reg   = 0x1000c,
314 	.shift = 12,
315 	.width = 4,
316 };
317 
318 static struct axxia_divclk clk_mmc_div = {
319 	.aclk.hw.init = &(struct clk_init_data){
320 		.name = "clk_mmc_div",
321 		.parent_names = (const char *[]){
322 			"clk_sm1_pll"
323 		},
324 		.num_parents = 1,
325 		.ops = &axxia_divclk_ops,
326 	},
327 	.reg   = 0x1000c,
328 	.shift = 16,
329 	.width = 4,
330 };
331 
332 /*
333  * Clock MUXes
334  */
335 
336 static struct axxia_clkmux clk_cpu0_mux = {
337 	.aclk.hw.init = &(struct clk_init_data){
338 		.name = "clk_cpu0",
339 		.parent_names = (const char *[]){
340 			"clk_ref0",
341 			"clk_cpu_pll",
342 			"clk_cpu0_div",
343 			"clk_cpu0_div"
344 		},
345 		.num_parents = 4,
346 		.ops = &axxia_clkmux_ops,
347 	},
348 	.reg   = 0x10000,
349 	.shift = 0,
350 	.width = 2,
351 };
352 
353 static struct axxia_clkmux clk_cpu1_mux = {
354 	.aclk.hw.init = &(struct clk_init_data){
355 		.name = "clk_cpu1",
356 		.parent_names = (const char *[]){
357 			"clk_ref0",
358 			"clk_cpu_pll",
359 			"clk_cpu1_div",
360 			"clk_cpu1_div"
361 		},
362 		.num_parents = 4,
363 		.ops = &axxia_clkmux_ops,
364 	},
365 	.reg   = 0x10000,
366 	.shift = 2,
367 	.width = 2,
368 };
369 
370 static struct axxia_clkmux clk_cpu2_mux = {
371 	.aclk.hw.init = &(struct clk_init_data){
372 		.name = "clk_cpu2",
373 		.parent_names = (const char *[]){
374 			"clk_ref0",
375 			"clk_cpu_pll",
376 			"clk_cpu2_div",
377 			"clk_cpu2_div"
378 		},
379 		.num_parents = 4,
380 		.ops = &axxia_clkmux_ops,
381 	},
382 	.reg   = 0x10000,
383 	.shift = 4,
384 	.width = 2,
385 };
386 
387 static struct axxia_clkmux clk_cpu3_mux = {
388 	.aclk.hw.init = &(struct clk_init_data){
389 		.name = "clk_cpu3",
390 		.parent_names = (const char *[]){
391 			"clk_ref0",
392 			"clk_cpu_pll",
393 			"clk_cpu3_div",
394 			"clk_cpu3_div"
395 		},
396 		.num_parents = 4,
397 		.ops = &axxia_clkmux_ops,
398 	},
399 	.reg   = 0x10000,
400 	.shift = 6,
401 	.width = 2,
402 };
403 
404 static struct axxia_clkmux clk_nrcp_mux = {
405 	.aclk.hw.init = &(struct clk_init_data){
406 		.name = "clk_nrcp",
407 		.parent_names = (const char *[]){
408 			"clk_ref0",
409 			"clk_sys_pll",
410 			"clk_nrcp_div",
411 			"clk_nrcp_div"
412 		},
413 		.num_parents = 4,
414 		.ops = &axxia_clkmux_ops,
415 	},
416 	.reg   = 0x10004,
417 	.shift = 0,
418 	.width = 2,
419 };
420 
421 static struct axxia_clkmux clk_sys_mux = {
422 	.aclk.hw.init = &(struct clk_init_data){
423 		.name = "clk_sys",
424 		.parent_names = (const char *[]){
425 			"clk_ref0",
426 			"clk_sys_pll",
427 			"clk_sys_div",
428 			"clk_sys_div"
429 		},
430 		.num_parents = 4,
431 		.ops = &axxia_clkmux_ops,
432 	},
433 	.reg   = 0x10004,
434 	.shift = 2,
435 	.width = 2,
436 };
437 
438 static struct axxia_clkmux clk_fab_mux = {
439 	.aclk.hw.init = &(struct clk_init_data){
440 		.name = "clk_fab",
441 		.parent_names = (const char *[]){
442 			"clk_ref0",
443 			"clk_fab_pll",
444 			"clk_fab_div",
445 			"clk_fab_div"
446 		},
447 		.num_parents = 4,
448 		.ops = &axxia_clkmux_ops,
449 	},
450 	.reg   = 0x10004,
451 	.shift = 4,
452 	.width = 2,
453 };
454 
455 static struct axxia_clkmux clk_per_mux = {
456 	.aclk.hw.init = &(struct clk_init_data){
457 		.name = "clk_per",
458 		.parent_names = (const char *[]){
459 			"clk_ref1",
460 			"clk_per_div"
461 		},
462 		.num_parents = 2,
463 		.ops = &axxia_clkmux_ops,
464 	},
465 	.reg   = 0x10004,
466 	.shift = 6,
467 	.width = 1,
468 };
469 
470 static struct axxia_clkmux clk_mmc_mux = {
471 	.aclk.hw.init = &(struct clk_init_data){
472 		.name = "clk_mmc",
473 		.parent_names = (const char *[]){
474 			"clk_ref1",
475 			"clk_mmc_div"
476 		},
477 		.num_parents = 2,
478 		.ops = &axxia_clkmux_ops,
479 	},
480 	.reg   = 0x10004,
481 	.shift = 9,
482 	.width = 1,
483 };
484 
485 /* Table of all supported clocks indexed by the clock identifiers from the
486  * device tree binding
487  */
488 static struct axxia_clk *axmclk_clocks[] = {
489 	[AXXIA_CLK_FAB_PLL]  = &clk_fab_pll.aclk,
490 	[AXXIA_CLK_CPU_PLL]  = &clk_cpu_pll.aclk,
491 	[AXXIA_CLK_SYS_PLL]  = &clk_sys_pll.aclk,
492 	[AXXIA_CLK_SM0_PLL]  = &clk_sm0_pll.aclk,
493 	[AXXIA_CLK_SM1_PLL]  = &clk_sm1_pll.aclk,
494 	[AXXIA_CLK_FAB_DIV]  = &clk_fab_div.aclk,
495 	[AXXIA_CLK_SYS_DIV]  = &clk_sys_div.aclk,
496 	[AXXIA_CLK_NRCP_DIV] = &clk_nrcp_div.aclk,
497 	[AXXIA_CLK_CPU0_DIV] = &clk_cpu0_div.aclk,
498 	[AXXIA_CLK_CPU1_DIV] = &clk_cpu1_div.aclk,
499 	[AXXIA_CLK_CPU2_DIV] = &clk_cpu2_div.aclk,
500 	[AXXIA_CLK_CPU3_DIV] = &clk_cpu3_div.aclk,
501 	[AXXIA_CLK_PER_DIV]  = &clk_per_div.aclk,
502 	[AXXIA_CLK_MMC_DIV]  = &clk_mmc_div.aclk,
503 	[AXXIA_CLK_FAB]      = &clk_fab_mux.aclk,
504 	[AXXIA_CLK_SYS]      = &clk_sys_mux.aclk,
505 	[AXXIA_CLK_NRCP]     = &clk_nrcp_mux.aclk,
506 	[AXXIA_CLK_CPU0]     = &clk_cpu0_mux.aclk,
507 	[AXXIA_CLK_CPU1]     = &clk_cpu1_mux.aclk,
508 	[AXXIA_CLK_CPU2]     = &clk_cpu2_mux.aclk,
509 	[AXXIA_CLK_CPU3]     = &clk_cpu3_mux.aclk,
510 	[AXXIA_CLK_PER]      = &clk_per_mux.aclk,
511 	[AXXIA_CLK_MMC]      = &clk_mmc_mux.aclk,
512 };
513 
514 static struct clk_hw *
of_clk_axmclk_get(struct of_phandle_args * clkspec,void * unused)515 of_clk_axmclk_get(struct of_phandle_args *clkspec, void *unused)
516 {
517 	unsigned int idx = clkspec->args[0];
518 
519 	if (idx >= ARRAY_SIZE(axmclk_clocks)) {
520 		pr_err("%s: invalid index %u\n", __func__, idx);
521 		return ERR_PTR(-EINVAL);
522 	}
523 
524 	return &axmclk_clocks[idx]->hw;
525 }
526 
527 static const struct regmap_config axmclk_regmap_config = {
528 	.reg_bits	= 32,
529 	.reg_stride	= 4,
530 	.val_bits	= 32,
531 	.max_register	= 0x1fffc,
532 	.fast_io	= true,
533 };
534 
535 static const struct of_device_id axmclk_match_table[] = {
536 	{ .compatible = "lsi,axm5516-clks" },
537 	{ }
538 };
539 MODULE_DEVICE_TABLE(of, axmclk_match_table);
540 
axmclk_probe(struct platform_device * pdev)541 static int axmclk_probe(struct platform_device *pdev)
542 {
543 	void __iomem *base;
544 	int i, ret;
545 	struct device *dev = &pdev->dev;
546 	struct regmap *regmap;
547 	size_t num_clks;
548 
549 	base = devm_platform_ioremap_resource(pdev, 0);
550 	if (IS_ERR(base))
551 		return PTR_ERR(base);
552 
553 	regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config);
554 	if (IS_ERR(regmap))
555 		return PTR_ERR(regmap);
556 
557 	num_clks = ARRAY_SIZE(axmclk_clocks);
558 	pr_info("axmclk: supporting %zu clocks\n", num_clks);
559 
560 	/* Update each entry with the allocated regmap and register the clock
561 	 * with the common clock framework
562 	 */
563 	for (i = 0; i < num_clks; i++) {
564 		axmclk_clocks[i]->regmap = regmap;
565 		ret = devm_clk_hw_register(dev, &axmclk_clocks[i]->hw);
566 		if (ret)
567 			return ret;
568 	}
569 
570 	return devm_of_clk_add_hw_provider(dev, of_clk_axmclk_get, NULL);
571 }
572 
573 static struct platform_driver axmclk_driver = {
574 	.probe		= axmclk_probe,
575 	.driver		= {
576 		.name	= "clk-axm5516",
577 		.of_match_table = axmclk_match_table,
578 	},
579 };
580 
axmclk_init(void)581 static int __init axmclk_init(void)
582 {
583 	return platform_driver_register(&axmclk_driver);
584 }
585 core_initcall(axmclk_init);
586 
axmclk_exit(void)587 static void __exit axmclk_exit(void)
588 {
589 	platform_driver_unregister(&axmclk_driver);
590 }
591 module_exit(axmclk_exit);
592 
593 MODULE_DESCRIPTION("AXM5516 clock driver");
594 MODULE_LICENSE("GPL v2");
595 MODULE_ALIAS("platform:clk-axm5516");
596