xref: /linux/drivers/clk/clk-axm5516.c (revision b7019ac550eb3916f34d79db583e9b7ea2524afa)
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 		.ops = &axxia_divclk_ops,
315 	},
316 	.reg   = 0x1000c,
317 	.shift = 12,
318 	.width = 4,
319 };
320 
321 static struct axxia_divclk clk_mmc_div = {
322 	.aclk.hw.init = &(struct clk_init_data){
323 		.name = "clk_mmc_div",
324 		.parent_names = (const char *[]){
325 			"clk_sm1_pll"
326 		},
327 		.num_parents = 1,
328 		.ops = &axxia_divclk_ops,
329 	},
330 	.reg   = 0x1000c,
331 	.shift = 16,
332 	.width = 4,
333 };
334 
335 /*
336  * Clock MUXes
337  */
338 
339 static struct axxia_clkmux clk_cpu0_mux = {
340 	.aclk.hw.init = &(struct clk_init_data){
341 		.name = "clk_cpu0",
342 		.parent_names = (const char *[]){
343 			"clk_ref0",
344 			"clk_cpu_pll",
345 			"clk_cpu0_div",
346 			"clk_cpu0_div"
347 		},
348 		.num_parents = 4,
349 		.ops = &axxia_clkmux_ops,
350 	},
351 	.reg   = 0x10000,
352 	.shift = 0,
353 	.width = 2,
354 };
355 
356 static struct axxia_clkmux clk_cpu1_mux = {
357 	.aclk.hw.init = &(struct clk_init_data){
358 		.name = "clk_cpu1",
359 		.parent_names = (const char *[]){
360 			"clk_ref0",
361 			"clk_cpu_pll",
362 			"clk_cpu1_div",
363 			"clk_cpu1_div"
364 		},
365 		.num_parents = 4,
366 		.ops = &axxia_clkmux_ops,
367 	},
368 	.reg   = 0x10000,
369 	.shift = 2,
370 	.width = 2,
371 };
372 
373 static struct axxia_clkmux clk_cpu2_mux = {
374 	.aclk.hw.init = &(struct clk_init_data){
375 		.name = "clk_cpu2",
376 		.parent_names = (const char *[]){
377 			"clk_ref0",
378 			"clk_cpu_pll",
379 			"clk_cpu2_div",
380 			"clk_cpu2_div"
381 		},
382 		.num_parents = 4,
383 		.ops = &axxia_clkmux_ops,
384 	},
385 	.reg   = 0x10000,
386 	.shift = 4,
387 	.width = 2,
388 };
389 
390 static struct axxia_clkmux clk_cpu3_mux = {
391 	.aclk.hw.init = &(struct clk_init_data){
392 		.name = "clk_cpu3",
393 		.parent_names = (const char *[]){
394 			"clk_ref0",
395 			"clk_cpu_pll",
396 			"clk_cpu3_div",
397 			"clk_cpu3_div"
398 		},
399 		.num_parents = 4,
400 		.ops = &axxia_clkmux_ops,
401 	},
402 	.reg   = 0x10000,
403 	.shift = 6,
404 	.width = 2,
405 };
406 
407 static struct axxia_clkmux clk_nrcp_mux = {
408 	.aclk.hw.init = &(struct clk_init_data){
409 		.name = "clk_nrcp",
410 		.parent_names = (const char *[]){
411 			"clk_ref0",
412 			"clk_sys_pll",
413 			"clk_nrcp_div",
414 			"clk_nrcp_div"
415 		},
416 		.num_parents = 4,
417 		.ops = &axxia_clkmux_ops,
418 	},
419 	.reg   = 0x10004,
420 	.shift = 0,
421 	.width = 2,
422 };
423 
424 static struct axxia_clkmux clk_sys_mux = {
425 	.aclk.hw.init = &(struct clk_init_data){
426 		.name = "clk_sys",
427 		.parent_names = (const char *[]){
428 			"clk_ref0",
429 			"clk_sys_pll",
430 			"clk_sys_div",
431 			"clk_sys_div"
432 		},
433 		.num_parents = 4,
434 		.ops = &axxia_clkmux_ops,
435 	},
436 	.reg   = 0x10004,
437 	.shift = 2,
438 	.width = 2,
439 };
440 
441 static struct axxia_clkmux clk_fab_mux = {
442 	.aclk.hw.init = &(struct clk_init_data){
443 		.name = "clk_fab",
444 		.parent_names = (const char *[]){
445 			"clk_ref0",
446 			"clk_fab_pll",
447 			"clk_fab_div",
448 			"clk_fab_div"
449 		},
450 		.num_parents = 4,
451 		.ops = &axxia_clkmux_ops,
452 	},
453 	.reg   = 0x10004,
454 	.shift = 4,
455 	.width = 2,
456 };
457 
458 static struct axxia_clkmux clk_per_mux = {
459 	.aclk.hw.init = &(struct clk_init_data){
460 		.name = "clk_per",
461 		.parent_names = (const char *[]){
462 			"clk_ref1",
463 			"clk_per_div"
464 		},
465 		.num_parents = 2,
466 		.ops = &axxia_clkmux_ops,
467 	},
468 	.reg   = 0x10004,
469 	.shift = 6,
470 	.width = 1,
471 };
472 
473 static struct axxia_clkmux clk_mmc_mux = {
474 	.aclk.hw.init = &(struct clk_init_data){
475 		.name = "clk_mmc",
476 		.parent_names = (const char *[]){
477 			"clk_ref1",
478 			"clk_mmc_div"
479 		},
480 		.num_parents = 2,
481 		.ops = &axxia_clkmux_ops,
482 	},
483 	.reg   = 0x10004,
484 	.shift = 9,
485 	.width = 1,
486 };
487 
488 /* Table of all supported clocks indexed by the clock identifiers from the
489  * device tree binding
490  */
491 static struct axxia_clk *axmclk_clocks[] = {
492 	[AXXIA_CLK_FAB_PLL]  = &clk_fab_pll.aclk,
493 	[AXXIA_CLK_CPU_PLL]  = &clk_cpu_pll.aclk,
494 	[AXXIA_CLK_SYS_PLL]  = &clk_sys_pll.aclk,
495 	[AXXIA_CLK_SM0_PLL]  = &clk_sm0_pll.aclk,
496 	[AXXIA_CLK_SM1_PLL]  = &clk_sm1_pll.aclk,
497 	[AXXIA_CLK_FAB_DIV]  = &clk_fab_div.aclk,
498 	[AXXIA_CLK_SYS_DIV]  = &clk_sys_div.aclk,
499 	[AXXIA_CLK_NRCP_DIV] = &clk_nrcp_div.aclk,
500 	[AXXIA_CLK_CPU0_DIV] = &clk_cpu0_div.aclk,
501 	[AXXIA_CLK_CPU1_DIV] = &clk_cpu1_div.aclk,
502 	[AXXIA_CLK_CPU2_DIV] = &clk_cpu2_div.aclk,
503 	[AXXIA_CLK_CPU3_DIV] = &clk_cpu3_div.aclk,
504 	[AXXIA_CLK_PER_DIV]  = &clk_per_div.aclk,
505 	[AXXIA_CLK_MMC_DIV]  = &clk_mmc_div.aclk,
506 	[AXXIA_CLK_FAB]      = &clk_fab_mux.aclk,
507 	[AXXIA_CLK_SYS]      = &clk_sys_mux.aclk,
508 	[AXXIA_CLK_NRCP]     = &clk_nrcp_mux.aclk,
509 	[AXXIA_CLK_CPU0]     = &clk_cpu0_mux.aclk,
510 	[AXXIA_CLK_CPU1]     = &clk_cpu1_mux.aclk,
511 	[AXXIA_CLK_CPU2]     = &clk_cpu2_mux.aclk,
512 	[AXXIA_CLK_CPU3]     = &clk_cpu3_mux.aclk,
513 	[AXXIA_CLK_PER]      = &clk_per_mux.aclk,
514 	[AXXIA_CLK_MMC]      = &clk_mmc_mux.aclk,
515 };
516 
517 static struct clk_hw *
518 of_clk_axmclk_get(struct of_phandle_args *clkspec, void *unused)
519 {
520 	unsigned int idx = clkspec->args[0];
521 
522 	if (idx >= ARRAY_SIZE(axmclk_clocks)) {
523 		pr_err("%s: invalid index %u\n", __func__, idx);
524 		return ERR_PTR(-EINVAL);
525 	}
526 
527 	return &axmclk_clocks[idx]->hw;
528 }
529 
530 static const struct regmap_config axmclk_regmap_config = {
531 	.reg_bits	= 32,
532 	.reg_stride	= 4,
533 	.val_bits	= 32,
534 	.max_register	= 0x1fffc,
535 	.fast_io	= true,
536 };
537 
538 static const struct of_device_id axmclk_match_table[] = {
539 	{ .compatible = "lsi,axm5516-clks" },
540 	{ }
541 };
542 MODULE_DEVICE_TABLE(of, axmclk_match_table);
543 
544 static int axmclk_probe(struct platform_device *pdev)
545 {
546 	void __iomem *base;
547 	struct resource *res;
548 	int i, ret;
549 	struct device *dev = &pdev->dev;
550 	struct regmap *regmap;
551 	size_t num_clks;
552 
553 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
554 	base = devm_ioremap_resource(dev, res);
555 	if (IS_ERR(base))
556 		return PTR_ERR(base);
557 
558 	regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config);
559 	if (IS_ERR(regmap))
560 		return PTR_ERR(regmap);
561 
562 	num_clks = ARRAY_SIZE(axmclk_clocks);
563 	pr_info("axmclk: supporting %zu clocks\n", num_clks);
564 
565 	/* Update each entry with the allocated regmap and register the clock
566 	 * with the common clock framework
567 	 */
568 	for (i = 0; i < num_clks; i++) {
569 		axmclk_clocks[i]->regmap = regmap;
570 		ret = devm_clk_hw_register(dev, &axmclk_clocks[i]->hw);
571 		if (ret)
572 			return ret;
573 	}
574 
575 	return of_clk_add_hw_provider(dev->of_node, of_clk_axmclk_get, NULL);
576 }
577 
578 static int axmclk_remove(struct platform_device *pdev)
579 {
580 	of_clk_del_provider(pdev->dev.of_node);
581 	return 0;
582 }
583 
584 static struct platform_driver axmclk_driver = {
585 	.probe		= axmclk_probe,
586 	.remove		= axmclk_remove,
587 	.driver		= {
588 		.name	= "clk-axm5516",
589 		.of_match_table = axmclk_match_table,
590 	},
591 };
592 
593 static int __init axmclk_init(void)
594 {
595 	return platform_driver_register(&axmclk_driver);
596 }
597 core_initcall(axmclk_init);
598 
599 static void __exit axmclk_exit(void)
600 {
601 	platform_driver_unregister(&axmclk_driver);
602 }
603 module_exit(axmclk_exit);
604 
605 MODULE_DESCRIPTION("AXM5516 clock driver");
606 MODULE_LICENSE("GPL v2");
607 MODULE_ALIAS("platform:clk-axm5516");
608