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