Warning: That file was not part of the compilation database. It may have many parsing errors.

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 */
29struct 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 */
40struct 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 */
50static unsigned long
51axxia_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
67static 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 */
78struct 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 */
89static unsigned long
90axxia_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
102static 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 */
113struct 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 */
124static 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
136static const struct clk_ops axxia_clkmux_ops = {
137 .get_parent = axxia_clkmux_get_parent,
138};
139
140
141/*
142 * PLLs
143 */
144
145static 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
157static 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
169static 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
181static 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
193static 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
209static 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
223static 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
237static 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
251static 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
265static 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
279static 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
293static 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
307static 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
321static 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
339static 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
356static 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
373static 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
390static 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
407static 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
424static 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
441static 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
458static 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
473static 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 */
491static 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
517static struct clk_hw *
518of_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
530static 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
538static const struct of_device_id axmclk_match_table[] = {
539 { .compatible = "lsi,axm5516-clks" },
540 { }
541};
542MODULE_DEVICE_TABLE(of, axmclk_match_table);
543
544static 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
578static int axmclk_remove(struct platform_device *pdev)
579{
580 of_clk_del_provider(pdev->dev.of_node);
581 return 0;
582}
583
584static 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
593static int __init axmclk_init(void)
594{
595 return platform_driver_register(&axmclk_driver);
596}
597core_initcall(axmclk_init);
598
599static void __exit axmclk_exit(void)
600{
601 platform_driver_unregister(&axmclk_driver);
602}
603module_exit(axmclk_exit);
604
605MODULE_DESCRIPTION("AXM5516 clock driver");
606MODULE_LICENSE("GPL v2");
607MODULE_ALIAS("platform:clk-axm5516");
608

Warning: That file was not part of the compilation database. It may have many parsing errors.