diff options
author | Stephen Boyd <sboyd@kernel.org> | 2018-07-09 12:47:55 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2018-07-09 12:47:55 -0400 |
commit | 166f3a8ad67738061d6deada4d71019240bdbdaf (patch) | |
tree | 6a95385f018bca6963984ef1252fc3edc7f32ade | |
parent | ce397d215ccd07b8ae3f71db689aedb85d56ab40 (diff) | |
parent | 7df533a7e3d2216e860ecf147ae8cee49bf133e9 (diff) |
Merge tag 'meson-clk-4.19-1' of https://github.com/BayLibre/clk-meson into clk-meson
Pull first round of updates for meson clocks from Jerome Brunet:
- Remove legacy register access (finish moving to syscon)
- Clean up configuration flags
- Add axg PCIe clocks
- Add GEN CLK on gxbb, gxl and axg
- Remove clk_audio_divider driver
- Add axg audio clock controller
* tag 'meson-clk-4.19-1' of https://github.com/BayLibre/clk-meson:
clk: meson: add gen_clk
clk: meson: gxbb: remove HHI_GEN_CLK_CTNL duplicate definition
clk: meson-axg: add clocks required by pcie driver
clk: meson: remove unused clk-audio-divider driver
clk: meson: stop rate propagation for audio clocks
clk: meson: axg: add the audio clock controller driver
clk: meson: add axg audio sclk divider driver
clk: meson: add triple phase clock driver
clk: meson: add clk-phase clock driver
clk: meson: clean-up meson clock configuration
clk: meson: remove obsolete register access
clk: meson: expose GEN_CLK clkid
clk: meson-axg: add pcie and mipi clock bindings
dt-bindings: clock: add meson axg audio clock controller bindings
clk: meson: audio-divider is one based
clk: add duty cycle support
clk: meson-gxbb: set fclk_div2 as CLK_IS_CRITICAL
-rw-r--r-- | Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt | 56 | ||||
-rw-r--r-- | drivers/clk/clk.c | 199 | ||||
-rw-r--r-- | drivers/clk/meson/Kconfig | 28 | ||||
-rw-r--r-- | drivers/clk/meson/Makefile | 4 | ||||
-rw-r--r-- | drivers/clk/meson/axg-audio.c | 845 | ||||
-rw-r--r-- | drivers/clk/meson/axg-audio.h | 127 | ||||
-rw-r--r-- | drivers/clk/meson/axg.c | 244 | ||||
-rw-r--r-- | drivers/clk/meson/axg.h | 8 | ||||
-rw-r--r-- | drivers/clk/meson/clk-audio-divider.c | 110 | ||||
-rw-r--r-- | drivers/clk/meson/clk-phase.c | 63 | ||||
-rw-r--r-- | drivers/clk/meson/clk-triphase.c | 68 | ||||
-rw-r--r-- | drivers/clk/meson/clkc-audio.h | 28 | ||||
-rw-r--r-- | drivers/clk/meson/clkc.h | 11 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.c | 119 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.h | 5 | ||||
-rw-r--r-- | drivers/clk/meson/sclk-div.c | 243 | ||||
-rw-r--r-- | include/dt-bindings/clock/axg-audio-clkc.h | 94 | ||||
-rw-r--r-- | include/dt-bindings/clock/axg-clkc.h | 4 | ||||
-rw-r--r-- | include/dt-bindings/clock/gxbb-clkc.h | 1 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 26 | ||||
-rw-r--r-- | include/linux/clk.h | 33 | ||||
-rw-r--r-- | include/trace/events/clk.h | 36 |
22 files changed, 2141 insertions, 211 deletions
diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt new file mode 100644 index 000000000000..61777ad24f61 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt | |||
@@ -0,0 +1,56 @@ | |||
1 | * Amlogic AXG Audio Clock Controllers | ||
2 | |||
3 | The Amlogic AXG audio clock controller generates and supplies clock to the | ||
4 | other elements of the audio subsystem, such as fifos, i2s, spdif and pdm | ||
5 | devices. | ||
6 | |||
7 | Required Properties: | ||
8 | |||
9 | - compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D | ||
10 | - reg : physical base address of the clock controller and length of | ||
11 | memory mapped region. | ||
12 | - clocks : a list of phandle + clock-specifier pairs for the clocks listed | ||
13 | in clock-names. | ||
14 | - clock-names : must contain the following: | ||
15 | * "pclk" - Main peripheral bus clock | ||
16 | may contain the following: | ||
17 | * "mst_in[0-7]" - 8 input plls to generate clock signals | ||
18 | * "slv_sclk[0-9]" - 10 slave bit clocks provided by external | ||
19 | components. | ||
20 | * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external | ||
21 | components. | ||
22 | - resets : phandle of the internal reset line | ||
23 | - #clock-cells : should be 1. | ||
24 | |||
25 | Each clock is assigned an identifier and client nodes can use this identifier | ||
26 | to specify the clock which they consume. All available clocks are defined as | ||
27 | preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be | ||
28 | used in device tree sources. | ||
29 | |||
30 | Example: | ||
31 | |||
32 | clkc_audio: clock-controller@0 { | ||
33 | compatible = "amlogic,axg-audio-clkc"; | ||
34 | reg = <0x0 0x0 0x0 0xb4>; | ||
35 | #clock-cells = <1>; | ||
36 | |||
37 | clocks = <&clkc CLKID_AUDIO>, | ||
38 | <&clkc CLKID_MPLL0>, | ||
39 | <&clkc CLKID_MPLL1>, | ||
40 | <&clkc CLKID_MPLL2>, | ||
41 | <&clkc CLKID_MPLL3>, | ||
42 | <&clkc CLKID_HIFI_PLL>, | ||
43 | <&clkc CLKID_FCLK_DIV3>, | ||
44 | <&clkc CLKID_FCLK_DIV4>, | ||
45 | <&clkc CLKID_GP0_PLL>; | ||
46 | clock-names = "pclk", | ||
47 | "mst_in0", | ||
48 | "mst_in1", | ||
49 | "mst_in2", | ||
50 | "mst_in3", | ||
51 | "mst_in4", | ||
52 | "mst_in5", | ||
53 | "mst_in6", | ||
54 | "mst_in7"; | ||
55 | resets = <&reset RESET_AUDIO>; | ||
56 | }; | ||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9760b526ca31..b0a2719d86f3 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -68,6 +68,7 @@ struct clk_core { | |||
68 | unsigned long max_rate; | 68 | unsigned long max_rate; |
69 | unsigned long accuracy; | 69 | unsigned long accuracy; |
70 | int phase; | 70 | int phase; |
71 | struct clk_duty duty; | ||
71 | struct hlist_head children; | 72 | struct hlist_head children; |
72 | struct hlist_node child_node; | 73 | struct hlist_node child_node; |
73 | struct hlist_head clks; | 74 | struct hlist_head clks; |
@@ -2402,6 +2403,172 @@ int clk_get_phase(struct clk *clk) | |||
2402 | } | 2403 | } |
2403 | EXPORT_SYMBOL_GPL(clk_get_phase); | 2404 | EXPORT_SYMBOL_GPL(clk_get_phase); |
2404 | 2405 | ||
2406 | static void clk_core_reset_duty_cycle_nolock(struct clk_core *core) | ||
2407 | { | ||
2408 | /* Assume a default value of 50% */ | ||
2409 | core->duty.num = 1; | ||
2410 | core->duty.den = 2; | ||
2411 | } | ||
2412 | |||
2413 | static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core); | ||
2414 | |||
2415 | static int clk_core_update_duty_cycle_nolock(struct clk_core *core) | ||
2416 | { | ||
2417 | struct clk_duty *duty = &core->duty; | ||
2418 | int ret = 0; | ||
2419 | |||
2420 | if (!core->ops->get_duty_cycle) | ||
2421 | return clk_core_update_duty_cycle_parent_nolock(core); | ||
2422 | |||
2423 | ret = core->ops->get_duty_cycle(core->hw, duty); | ||
2424 | if (ret) | ||
2425 | goto reset; | ||
2426 | |||
2427 | /* Don't trust the clock provider too much */ | ||
2428 | if (duty->den == 0 || duty->num > duty->den) { | ||
2429 | ret = -EINVAL; | ||
2430 | goto reset; | ||
2431 | } | ||
2432 | |||
2433 | return 0; | ||
2434 | |||
2435 | reset: | ||
2436 | clk_core_reset_duty_cycle_nolock(core); | ||
2437 | return ret; | ||
2438 | } | ||
2439 | |||
2440 | static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core) | ||
2441 | { | ||
2442 | int ret = 0; | ||
2443 | |||
2444 | if (core->parent && | ||
2445 | core->flags & CLK_DUTY_CYCLE_PARENT) { | ||
2446 | ret = clk_core_update_duty_cycle_nolock(core->parent); | ||
2447 | memcpy(&core->duty, &core->parent->duty, sizeof(core->duty)); | ||
2448 | } else { | ||
2449 | clk_core_reset_duty_cycle_nolock(core); | ||
2450 | } | ||
2451 | |||
2452 | return ret; | ||
2453 | } | ||
2454 | |||
2455 | static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core, | ||
2456 | struct clk_duty *duty); | ||
2457 | |||
2458 | static int clk_core_set_duty_cycle_nolock(struct clk_core *core, | ||
2459 | struct clk_duty *duty) | ||
2460 | { | ||
2461 | int ret; | ||
2462 | |||
2463 | lockdep_assert_held(&prepare_lock); | ||
2464 | |||
2465 | if (clk_core_rate_is_protected(core)) | ||
2466 | return -EBUSY; | ||
2467 | |||
2468 | trace_clk_set_duty_cycle(core, duty); | ||
2469 | |||
2470 | if (!core->ops->set_duty_cycle) | ||
2471 | return clk_core_set_duty_cycle_parent_nolock(core, duty); | ||
2472 | |||
2473 | ret = core->ops->set_duty_cycle(core->hw, duty); | ||
2474 | if (!ret) | ||
2475 | memcpy(&core->duty, duty, sizeof(*duty)); | ||
2476 | |||
2477 | trace_clk_set_duty_cycle_complete(core, duty); | ||
2478 | |||
2479 | return ret; | ||
2480 | } | ||
2481 | |||
2482 | static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core, | ||
2483 | struct clk_duty *duty) | ||
2484 | { | ||
2485 | int ret = 0; | ||
2486 | |||
2487 | if (core->parent && | ||
2488 | core->flags & (CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)) { | ||
2489 | ret = clk_core_set_duty_cycle_nolock(core->parent, duty); | ||
2490 | memcpy(&core->duty, &core->parent->duty, sizeof(core->duty)); | ||
2491 | } | ||
2492 | |||
2493 | return ret; | ||
2494 | } | ||
2495 | |||
2496 | /** | ||
2497 | * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal | ||
2498 | * @clk: clock signal source | ||
2499 | * @num: numerator of the duty cycle ratio to be applied | ||
2500 | * @den: denominator of the duty cycle ratio to be applied | ||
2501 | * | ||
2502 | * Apply the duty cycle ratio if the ratio is valid and the clock can | ||
2503 | * perform this operation | ||
2504 | * | ||
2505 | * Returns (0) on success, a negative errno otherwise. | ||
2506 | */ | ||
2507 | int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den) | ||
2508 | { | ||
2509 | int ret; | ||
2510 | struct clk_duty duty; | ||
2511 | |||
2512 | if (!clk) | ||
2513 | return 0; | ||
2514 | |||
2515 | /* sanity check the ratio */ | ||
2516 | if (den == 0 || num > den) | ||
2517 | return -EINVAL; | ||
2518 | |||
2519 | duty.num = num; | ||
2520 | duty.den = den; | ||
2521 | |||
2522 | clk_prepare_lock(); | ||
2523 | |||
2524 | if (clk->exclusive_count) | ||
2525 | clk_core_rate_unprotect(clk->core); | ||
2526 | |||
2527 | ret = clk_core_set_duty_cycle_nolock(clk->core, &duty); | ||
2528 | |||
2529 | if (clk->exclusive_count) | ||
2530 | clk_core_rate_protect(clk->core); | ||
2531 | |||
2532 | clk_prepare_unlock(); | ||
2533 | |||
2534 | return ret; | ||
2535 | } | ||
2536 | EXPORT_SYMBOL_GPL(clk_set_duty_cycle); | ||
2537 | |||
2538 | static int clk_core_get_scaled_duty_cycle(struct clk_core *core, | ||
2539 | unsigned int scale) | ||
2540 | { | ||
2541 | struct clk_duty *duty = &core->duty; | ||
2542 | int ret; | ||
2543 | |||
2544 | clk_prepare_lock(); | ||
2545 | |||
2546 | ret = clk_core_update_duty_cycle_nolock(core); | ||
2547 | if (!ret) | ||
2548 | ret = mult_frac(scale, duty->num, duty->den); | ||
2549 | |||
2550 | clk_prepare_unlock(); | ||
2551 | |||
2552 | return ret; | ||
2553 | } | ||
2554 | |||
2555 | /** | ||
2556 | * clk_get_scaled_duty_cycle - return the duty cycle ratio of a clock signal | ||
2557 | * @clk: clock signal source | ||
2558 | * @scale: scaling factor to be applied to represent the ratio as an integer | ||
2559 | * | ||
2560 | * Returns the duty cycle ratio of a clock node multiplied by the provided | ||
2561 | * scaling factor, or negative errno on error. | ||
2562 | */ | ||
2563 | int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale) | ||
2564 | { | ||
2565 | if (!clk) | ||
2566 | return 0; | ||
2567 | |||
2568 | return clk_core_get_scaled_duty_cycle(clk->core, scale); | ||
2569 | } | ||
2570 | EXPORT_SYMBOL_GPL(clk_get_scaled_duty_cycle); | ||
2571 | |||
2405 | /** | 2572 | /** |
2406 | * clk_is_match - check if two clk's point to the same hardware clock | 2573 | * clk_is_match - check if two clk's point to the same hardware clock |
2407 | * @p: clk compared against q | 2574 | * @p: clk compared against q |
@@ -2455,12 +2622,13 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, | |||
2455 | if (!c) | 2622 | if (!c) |
2456 | return; | 2623 | return; |
2457 | 2624 | ||
2458 | seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %-3d\n", | 2625 | seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n", |
2459 | level * 3 + 1, "", | 2626 | level * 3 + 1, "", |
2460 | 30 - level * 3, c->name, | 2627 | 30 - level * 3, c->name, |
2461 | c->enable_count, c->prepare_count, c->protect_count, | 2628 | c->enable_count, c->prepare_count, c->protect_count, |
2462 | clk_core_get_rate(c), clk_core_get_accuracy(c), | 2629 | clk_core_get_rate(c), clk_core_get_accuracy(c), |
2463 | clk_core_get_phase(c)); | 2630 | clk_core_get_phase(c), |
2631 | clk_core_get_scaled_duty_cycle(c, 100000)); | ||
2464 | } | 2632 | } |
2465 | 2633 | ||
2466 | static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, | 2634 | static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, |
@@ -2482,9 +2650,9 @@ static int clk_summary_show(struct seq_file *s, void *data) | |||
2482 | struct clk_core *c; | 2650 | struct clk_core *c; |
2483 | struct hlist_head **lists = (struct hlist_head **)s->private; | 2651 | struct hlist_head **lists = (struct hlist_head **)s->private; |
2484 | 2652 | ||
2485 | seq_puts(s, " enable prepare protect \n"); | 2653 | seq_puts(s, " enable prepare protect duty\n"); |
2486 | seq_puts(s, " clock count count count rate accuracy phase\n"); | 2654 | seq_puts(s, " clock count count count rate accuracy phase cycle\n"); |
2487 | seq_puts(s, "----------------------------------------------------------------------------------------\n"); | 2655 | seq_puts(s, "---------------------------------------------------------------------------------------------\n"); |
2488 | 2656 | ||
2489 | clk_prepare_lock(); | 2657 | clk_prepare_lock(); |
2490 | 2658 | ||
@@ -2511,6 +2679,8 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) | |||
2511 | seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c)); | 2679 | seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c)); |
2512 | seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); | 2680 | seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); |
2513 | seq_printf(s, "\"phase\": %d", clk_core_get_phase(c)); | 2681 | seq_printf(s, "\"phase\": %d", clk_core_get_phase(c)); |
2682 | seq_printf(s, "\"duty_cycle\": %u", | ||
2683 | clk_core_get_scaled_duty_cycle(c, 100000)); | ||
2514 | } | 2684 | } |
2515 | 2685 | ||
2516 | static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level) | 2686 | static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level) |
@@ -2572,6 +2742,7 @@ static const struct { | |||
2572 | ENTRY(CLK_SET_RATE_UNGATE), | 2742 | ENTRY(CLK_SET_RATE_UNGATE), |
2573 | ENTRY(CLK_IS_CRITICAL), | 2743 | ENTRY(CLK_IS_CRITICAL), |
2574 | ENTRY(CLK_OPS_PARENT_ENABLE), | 2744 | ENTRY(CLK_OPS_PARENT_ENABLE), |
2745 | ENTRY(CLK_DUTY_CYCLE_PARENT), | ||
2575 | #undef ENTRY | 2746 | #undef ENTRY |
2576 | }; | 2747 | }; |
2577 | 2748 | ||
@@ -2610,6 +2781,17 @@ static int possible_parents_show(struct seq_file *s, void *data) | |||
2610 | } | 2781 | } |
2611 | DEFINE_SHOW_ATTRIBUTE(possible_parents); | 2782 | DEFINE_SHOW_ATTRIBUTE(possible_parents); |
2612 | 2783 | ||
2784 | static int clk_duty_cycle_show(struct seq_file *s, void *data) | ||
2785 | { | ||
2786 | struct clk_core *core = s->private; | ||
2787 | struct clk_duty *duty = &core->duty; | ||
2788 | |||
2789 | seq_printf(s, "%u/%u\n", duty->num, duty->den); | ||
2790 | |||
2791 | return 0; | ||
2792 | } | ||
2793 | DEFINE_SHOW_ATTRIBUTE(clk_duty_cycle); | ||
2794 | |||
2613 | static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) | 2795 | static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) |
2614 | { | 2796 | { |
2615 | struct dentry *root; | 2797 | struct dentry *root; |
@@ -2628,6 +2810,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) | |||
2628 | debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count); | 2810 | debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count); |
2629 | debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count); | 2811 | debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count); |
2630 | debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count); | 2812 | debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count); |
2813 | debugfs_create_file("clk_duty_cycle", 0444, root, core, | ||
2814 | &clk_duty_cycle_fops); | ||
2631 | 2815 | ||
2632 | if (core->num_parents > 1) | 2816 | if (core->num_parents > 1) |
2633 | debugfs_create_file("clk_possible_parents", 0444, root, core, | 2817 | debugfs_create_file("clk_possible_parents", 0444, root, core, |
@@ -2846,6 +3030,11 @@ static int __clk_core_init(struct clk_core *core) | |||
2846 | core->phase = 0; | 3030 | core->phase = 0; |
2847 | 3031 | ||
2848 | /* | 3032 | /* |
3033 | * Set clk's duty cycle. | ||
3034 | */ | ||
3035 | clk_core_update_duty_cycle_nolock(core); | ||
3036 | |||
3037 | /* | ||
2849 | * Set clk's rate. The preferred method is to use .recalc_rate. For | 3038 | * Set clk's rate. The preferred method is to use .recalc_rate. For |
2850 | * simple clocks and lazy developers the default fallback is to use the | 3039 | * simple clocks and lazy developers the default fallback is to use the |
2851 | * parent's rate. If a clock doesn't have a parent (or is orphaned) | 3040 | * parent's rate. If a clock doesn't have a parent (or is orphaned) |
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 815659eebea3..efaa70f682b4 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig | |||
@@ -1,13 +1,19 @@ | |||
1 | config COMMON_CLK_AMLOGIC | 1 | config COMMON_CLK_AMLOGIC |
2 | bool | 2 | bool |
3 | depends on OF | ||
4 | depends on ARCH_MESON || COMPILE_TEST | 3 | depends on ARCH_MESON || COMPILE_TEST |
4 | select COMMON_CLK_REGMAP_MESON | ||
5 | |||
6 | config COMMON_CLK_AMLOGIC_AUDIO | ||
7 | bool | ||
8 | depends on ARCH_MESON || COMPILE_TEST | ||
9 | select COMMON_CLK_AMLOGIC | ||
5 | 10 | ||
6 | config COMMON_CLK_MESON_AO | 11 | config COMMON_CLK_MESON_AO |
7 | bool | 12 | bool |
8 | depends on OF | 13 | depends on OF |
9 | depends on ARCH_MESON || COMPILE_TEST | 14 | depends on ARCH_MESON || COMPILE_TEST |
10 | select COMMON_CLK_REGMAP_MESON | 15 | select COMMON_CLK_REGMAP_MESON |
16 | select RESET_CONTROLLER | ||
11 | 17 | ||
12 | config COMMON_CLK_REGMAP_MESON | 18 | config COMMON_CLK_REGMAP_MESON |
13 | bool | 19 | bool |
@@ -15,9 +21,8 @@ config COMMON_CLK_REGMAP_MESON | |||
15 | 21 | ||
16 | config COMMON_CLK_MESON8B | 22 | config COMMON_CLK_MESON8B |
17 | bool | 23 | bool |
18 | depends on COMMON_CLK_AMLOGIC | 24 | select COMMON_CLK_AMLOGIC |
19 | select RESET_CONTROLLER | 25 | select RESET_CONTROLLER |
20 | select COMMON_CLK_REGMAP_MESON | ||
21 | help | 26 | help |
22 | Support for the clock controller on AmLogic S802 (Meson8), | 27 | Support for the clock controller on AmLogic S802 (Meson8), |
23 | S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you | 28 | S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you |
@@ -25,10 +30,8 @@ config COMMON_CLK_MESON8B | |||
25 | 30 | ||
26 | config COMMON_CLK_GXBB | 31 | config COMMON_CLK_GXBB |
27 | bool | 32 | bool |
28 | depends on COMMON_CLK_AMLOGIC | 33 | select COMMON_CLK_AMLOGIC |
29 | select RESET_CONTROLLER | ||
30 | select COMMON_CLK_MESON_AO | 34 | select COMMON_CLK_MESON_AO |
31 | select COMMON_CLK_REGMAP_MESON | ||
32 | select MFD_SYSCON | 35 | select MFD_SYSCON |
33 | help | 36 | help |
34 | Support for the clock controller on AmLogic S905 devices, aka gxbb. | 37 | Support for the clock controller on AmLogic S905 devices, aka gxbb. |
@@ -36,11 +39,18 @@ config COMMON_CLK_GXBB | |||
36 | 39 | ||
37 | config COMMON_CLK_AXG | 40 | config COMMON_CLK_AXG |
38 | bool | 41 | bool |
39 | depends on COMMON_CLK_AMLOGIC | 42 | select COMMON_CLK_AMLOGIC |
40 | select RESET_CONTROLLER | ||
41 | select COMMON_CLK_MESON_AO | 43 | select COMMON_CLK_MESON_AO |
42 | select COMMON_CLK_REGMAP_MESON | ||
43 | select MFD_SYSCON | 44 | select MFD_SYSCON |
44 | help | 45 | help |
45 | Support for the clock controller on AmLogic A113D devices, aka axg. | 46 | Support for the clock controller on AmLogic A113D devices, aka axg. |
46 | Say Y if you want peripherals and CPU frequency scaling to work. | 47 | Say Y if you want peripherals and CPU frequency scaling to work. |
48 | |||
49 | config COMMON_CLK_AXG_AUDIO | ||
50 | tristate "Meson AXG Audio Clock Controller Driver" | ||
51 | depends on COMMON_CLK_AXG | ||
52 | select COMMON_CLK_AMLOGIC_AUDIO | ||
53 | select MFD_SYSCON | ||
54 | help | ||
55 | Support for the audio clock controller on AmLogic A113D devices, | ||
56 | aka axg, Say Y if you want audio subsystem to work. | ||
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index d0d13aeb369a..72ec8c40d848 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile | |||
@@ -2,9 +2,11 @@ | |||
2 | # Makefile for Meson specific clk | 2 | # Makefile for Meson specific clk |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o | 5 | obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o |
6 | obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o | ||
6 | obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o | 7 | obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o |
7 | obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o | 8 | obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o |
8 | obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o | 9 | obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o |
9 | obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o | 10 | obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o |
11 | obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o | ||
10 | obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o | 12 | obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o |
diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c new file mode 100644 index 000000000000..a0ed41e73bde --- /dev/null +++ b/drivers/clk/meson/axg-audio.c | |||
@@ -0,0 +1,845 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) | ||
2 | /* | ||
3 | * Copyright (c) 2018 BayLibre, SAS. | ||
4 | * Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | */ | ||
6 | |||
7 | #include <linux/clk.h> | ||
8 | #include <linux/clk-provider.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/of_device.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/regmap.h> | ||
14 | #include <linux/reset.h> | ||
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include "clkc-audio.h" | ||
18 | #include "axg-audio.h" | ||
19 | |||
20 | #define AXG_MST_IN_COUNT 8 | ||
21 | #define AXG_SLV_SCLK_COUNT 10 | ||
22 | #define AXG_SLV_LRCLK_COUNT 10 | ||
23 | |||
24 | #define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ | ||
25 | struct clk_regmap axg_##_name = { \ | ||
26 | .data = &(struct clk_regmap_gate_data){ \ | ||
27 | .offset = (_reg), \ | ||
28 | .bit_idx = (_bit), \ | ||
29 | }, \ | ||
30 | .hw.init = &(struct clk_init_data) { \ | ||
31 | .name = "axg_"#_name, \ | ||
32 | .ops = &clk_regmap_gate_ops, \ | ||
33 | .parent_names = (const char *[]){ _pname }, \ | ||
34 | .num_parents = 1, \ | ||
35 | .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ | ||
36 | }, \ | ||
37 | } | ||
38 | |||
39 | #define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ | ||
40 | struct clk_regmap axg_##_name = { \ | ||
41 | .data = &(struct clk_regmap_mux_data){ \ | ||
42 | .offset = (_reg), \ | ||
43 | .mask = (_mask), \ | ||
44 | .shift = (_shift), \ | ||
45 | .flags = (_dflags), \ | ||
46 | }, \ | ||
47 | .hw.init = &(struct clk_init_data){ \ | ||
48 | .name = "axg_"#_name, \ | ||
49 | .ops = &clk_regmap_mux_ops, \ | ||
50 | .parent_names = (_pnames), \ | ||
51 | .num_parents = ARRAY_SIZE(_pnames), \ | ||
52 | .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ | ||
53 | }, \ | ||
54 | } | ||
55 | |||
56 | #define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ | ||
57 | struct clk_regmap axg_##_name = { \ | ||
58 | .data = &(struct clk_regmap_div_data){ \ | ||
59 | .offset = (_reg), \ | ||
60 | .shift = (_shift), \ | ||
61 | .width = (_width), \ | ||
62 | .flags = (_dflags), \ | ||
63 | }, \ | ||
64 | .hw.init = &(struct clk_init_data){ \ | ||
65 | .name = "axg_"#_name, \ | ||
66 | .ops = &clk_regmap_divider_ops, \ | ||
67 | .parent_names = (const char *[]) { _pname }, \ | ||
68 | .num_parents = 1, \ | ||
69 | .flags = (_iflags), \ | ||
70 | }, \ | ||
71 | } | ||
72 | |||
73 | #define AXG_PCLK_GATE(_name, _bit) \ | ||
74 | AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0) | ||
75 | |||
76 | /* Audio peripheral clocks */ | ||
77 | static AXG_PCLK_GATE(ddr_arb, 0); | ||
78 | static AXG_PCLK_GATE(pdm, 1); | ||
79 | static AXG_PCLK_GATE(tdmin_a, 2); | ||
80 | static AXG_PCLK_GATE(tdmin_b, 3); | ||
81 | static AXG_PCLK_GATE(tdmin_c, 4); | ||
82 | static AXG_PCLK_GATE(tdmin_lb, 5); | ||
83 | static AXG_PCLK_GATE(tdmout_a, 6); | ||
84 | static AXG_PCLK_GATE(tdmout_b, 7); | ||
85 | static AXG_PCLK_GATE(tdmout_c, 8); | ||
86 | static AXG_PCLK_GATE(frddr_a, 9); | ||
87 | static AXG_PCLK_GATE(frddr_b, 10); | ||
88 | static AXG_PCLK_GATE(frddr_c, 11); | ||
89 | static AXG_PCLK_GATE(toddr_a, 12); | ||
90 | static AXG_PCLK_GATE(toddr_b, 13); | ||
91 | static AXG_PCLK_GATE(toddr_c, 14); | ||
92 | static AXG_PCLK_GATE(loopback, 15); | ||
93 | static AXG_PCLK_GATE(spdifin, 16); | ||
94 | static AXG_PCLK_GATE(spdifout, 17); | ||
95 | static AXG_PCLK_GATE(resample, 18); | ||
96 | static AXG_PCLK_GATE(power_detect, 19); | ||
97 | |||
98 | /* Audio Master Clocks */ | ||
99 | static const char * const mst_mux_parent_names[] = { | ||
100 | "axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3", | ||
101 | "axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7", | ||
102 | }; | ||
103 | |||
104 | #define AXG_MST_MCLK_MUX(_name, _reg) \ | ||
105 | AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \ | ||
106 | mst_mux_parent_names, CLK_SET_RATE_PARENT) | ||
107 | |||
108 | static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); | ||
109 | static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); | ||
110 | static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); | ||
111 | static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); | ||
112 | static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); | ||
113 | static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); | ||
114 | static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); | ||
115 | static AXG_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); | ||
116 | static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); | ||
117 | static AXG_MST_MCLK_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); | ||
118 | |||
119 | #define AXG_MST_MCLK_DIV(_name, _reg) \ | ||
120 | AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \ | ||
121 | "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ | ||
122 | |||
123 | static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); | ||
124 | static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); | ||
125 | static AXG_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL); | ||
126 | static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); | ||
127 | static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); | ||
128 | static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); | ||
129 | static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); | ||
130 | static AXG_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); | ||
131 | static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); | ||
132 | static AXG_MST_MCLK_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); | ||
133 | |||
134 | #define AXG_MST_MCLK_GATE(_name, _reg) \ | ||
135 | AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ | ||
136 | CLK_SET_RATE_PARENT) | ||
137 | |||
138 | static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); | ||
139 | static AXG_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL); | ||
140 | static AXG_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL); | ||
141 | static AXG_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL); | ||
142 | static AXG_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL); | ||
143 | static AXG_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL); | ||
144 | static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); | ||
145 | static AXG_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); | ||
146 | static AXG_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); | ||
147 | static AXG_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); | ||
148 | |||
149 | /* Sample Clocks */ | ||
150 | #define AXG_MST_SCLK_PRE_EN(_name, _reg) \ | ||
151 | AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ | ||
152 | "axg_mst_"#_name"_mclk", 0) | ||
153 | |||
154 | static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); | ||
155 | static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); | ||
156 | static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0); | ||
157 | static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0); | ||
158 | static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); | ||
159 | static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); | ||
160 | |||
161 | #define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ | ||
162 | _hi_shift, _hi_width, _pname, _iflags) \ | ||
163 | struct clk_regmap axg_##_name = { \ | ||
164 | .data = &(struct meson_sclk_div_data) { \ | ||
165 | .div = { \ | ||
166 | .reg_off = (_reg), \ | ||
167 | .shift = (_div_shift), \ | ||
168 | .width = (_div_width), \ | ||
169 | }, \ | ||
170 | .hi = { \ | ||
171 | .reg_off = (_reg), \ | ||
172 | .shift = (_hi_shift), \ | ||
173 | .width = (_hi_width), \ | ||
174 | }, \ | ||
175 | }, \ | ||
176 | .hw.init = &(struct clk_init_data) { \ | ||
177 | .name = "axg_"#_name, \ | ||
178 | .ops = &meson_sclk_div_ops, \ | ||
179 | .parent_names = (const char *[]) { _pname }, \ | ||
180 | .num_parents = 1, \ | ||
181 | .flags = (_iflags), \ | ||
182 | }, \ | ||
183 | } | ||
184 | |||
185 | #define AXG_MST_SCLK_DIV(_name, _reg) \ | ||
186 | AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ | ||
187 | "axg_mst_"#_name"_sclk_pre_en", \ | ||
188 | CLK_SET_RATE_PARENT) | ||
189 | |||
190 | static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); | ||
191 | static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); | ||
192 | static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); | ||
193 | static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); | ||
194 | static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); | ||
195 | static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); | ||
196 | |||
197 | #define AXG_MST_SCLK_POST_EN(_name, _reg) \ | ||
198 | AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ | ||
199 | "axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) | ||
200 | |||
201 | static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); | ||
202 | static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); | ||
203 | static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0); | ||
204 | static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); | ||
205 | static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); | ||
206 | static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); | ||
207 | |||
208 | #define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ | ||
209 | _pname, _iflags) \ | ||
210 | struct clk_regmap axg_##_name = { \ | ||
211 | .data = &(struct meson_clk_triphase_data) { \ | ||
212 | .ph0 = { \ | ||
213 | .reg_off = (_reg), \ | ||
214 | .shift = (_shift0), \ | ||
215 | .width = (_width), \ | ||
216 | }, \ | ||
217 | .ph1 = { \ | ||
218 | .reg_off = (_reg), \ | ||
219 | .shift = (_shift1), \ | ||
220 | .width = (_width), \ | ||
221 | }, \ | ||
222 | .ph2 = { \ | ||
223 | .reg_off = (_reg), \ | ||
224 | .shift = (_shift2), \ | ||
225 | .width = (_width), \ | ||
226 | }, \ | ||
227 | }, \ | ||
228 | .hw.init = &(struct clk_init_data) { \ | ||
229 | .name = "axg_"#_name, \ | ||
230 | .ops = &meson_clk_triphase_ops, \ | ||
231 | .parent_names = (const char *[]) { _pname }, \ | ||
232 | .num_parents = 1, \ | ||
233 | .flags = CLK_DUTY_CYCLE_PARENT | (_iflags), \ | ||
234 | }, \ | ||
235 | } | ||
236 | |||
237 | #define AXG_MST_SCLK(_name, _reg) \ | ||
238 | AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ | ||
239 | "axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) | ||
240 | |||
241 | static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); | ||
242 | static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); | ||
243 | static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1); | ||
244 | static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1); | ||
245 | static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1); | ||
246 | static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); | ||
247 | |||
248 | #define AXG_MST_LRCLK_DIV(_name, _reg) \ | ||
249 | AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ | ||
250 | "axg_mst_"#_name"_sclk_post_en", 0) \ | ||
251 | |||
252 | static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); | ||
253 | static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); | ||
254 | static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); | ||
255 | static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); | ||
256 | static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); | ||
257 | static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); | ||
258 | |||
259 | #define AXG_MST_LRCLK(_name, _reg) \ | ||
260 | AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ | ||
261 | "axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) | ||
262 | |||
263 | static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); | ||
264 | static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); | ||
265 | static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1); | ||
266 | static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); | ||
267 | static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); | ||
268 | static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); | ||
269 | |||
270 | static const char * const tdm_sclk_parent_names[] = { | ||
271 | "axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk", | ||
272 | "axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk", | ||
273 | "axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2", | ||
274 | "axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5", | ||
275 | "axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8", | ||
276 | "axg_slv_sclk9" | ||
277 | }; | ||
278 | |||
279 | #define AXG_TDM_SCLK_MUX(_name, _reg) \ | ||
280 | AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ | ||
281 | CLK_MUX_ROUND_CLOSEST, \ | ||
282 | tdm_sclk_parent_names, 0) | ||
283 | |||
284 | static AXG_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); | ||
285 | static AXG_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); | ||
286 | static AXG_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL); | ||
287 | static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); | ||
288 | static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL); | ||
289 | static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL); | ||
290 | static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); | ||
291 | |||
292 | #define AXG_TDM_SCLK_PRE_EN(_name, _reg) \ | ||
293 | AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ | ||
294 | "axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) | ||
295 | |||
296 | static AXG_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); | ||
297 | static AXG_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); | ||
298 | static AXG_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); | ||
299 | static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); | ||
300 | static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); | ||
301 | static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); | ||
302 | static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); | ||
303 | |||
304 | #define AXG_TDM_SCLK_POST_EN(_name, _reg) \ | ||
305 | AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ | ||
306 | "axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) | ||
307 | |||
308 | static AXG_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); | ||
309 | static AXG_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); | ||
310 | static AXG_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); | ||
311 | static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); | ||
312 | static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); | ||
313 | static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); | ||
314 | static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); | ||
315 | |||
316 | #define AXG_TDM_SCLK(_name, _reg) \ | ||
317 | struct clk_regmap axg_tdm##_name##_sclk = { \ | ||
318 | .data = &(struct meson_clk_phase_data) { \ | ||
319 | .ph = { \ | ||
320 | .reg_off = (_reg), \ | ||
321 | .shift = 29, \ | ||
322 | .width = 1, \ | ||
323 | }, \ | ||
324 | }, \ | ||
325 | .hw.init = &(struct clk_init_data) { \ | ||
326 | .name = "axg_tdm"#_name"_sclk", \ | ||
327 | .ops = &meson_clk_phase_ops, \ | ||
328 | .parent_names = (const char *[]) \ | ||
329 | { "axg_tdm"#_name"_sclk_post_en" }, \ | ||
330 | .num_parents = 1, \ | ||
331 | .flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT, \ | ||
332 | }, \ | ||
333 | } | ||
334 | |||
335 | static AXG_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL); | ||
336 | static AXG_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL); | ||
337 | static AXG_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); | ||
338 | static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); | ||
339 | static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); | ||
340 | static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); | ||
341 | static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); | ||
342 | |||
343 | static const char * const tdm_lrclk_parent_names[] = { | ||
344 | "axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk", | ||
345 | "axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk", | ||
346 | "axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2", | ||
347 | "axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5", | ||
348 | "axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8", | ||
349 | "axg_slv_lrclk9" | ||
350 | }; | ||
351 | |||
352 | #define AXG_TDM_LRLCK(_name, _reg) \ | ||
353 | AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ | ||
354 | CLK_MUX_ROUND_CLOSEST, \ | ||
355 | tdm_lrclk_parent_names, 0) | ||
356 | |||
357 | static AXG_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); | ||
358 | static AXG_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); | ||
359 | static AXG_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL); | ||
360 | static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); | ||
361 | static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); | ||
362 | static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); | ||
363 | static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); | ||
364 | |||
365 | /* | ||
366 | * Array of all clocks provided by this provider | ||
367 | * The input clocks of the controller will be populated at runtime | ||
368 | */ | ||
369 | static struct clk_hw_onecell_data axg_audio_hw_onecell_data = { | ||
370 | .hws = { | ||
371 | [AUD_CLKID_DDR_ARB] = &axg_ddr_arb.hw, | ||
372 | [AUD_CLKID_PDM] = &axg_pdm.hw, | ||
373 | [AUD_CLKID_TDMIN_A] = &axg_tdmin_a.hw, | ||
374 | [AUD_CLKID_TDMIN_B] = &axg_tdmin_b.hw, | ||
375 | [AUD_CLKID_TDMIN_C] = &axg_tdmin_c.hw, | ||
376 | [AUD_CLKID_TDMIN_LB] = &axg_tdmin_lb.hw, | ||
377 | [AUD_CLKID_TDMOUT_A] = &axg_tdmout_a.hw, | ||
378 | [AUD_CLKID_TDMOUT_B] = &axg_tdmout_b.hw, | ||
379 | [AUD_CLKID_TDMOUT_C] = &axg_tdmout_c.hw, | ||
380 | [AUD_CLKID_FRDDR_A] = &axg_frddr_a.hw, | ||
381 | [AUD_CLKID_FRDDR_B] = &axg_frddr_b.hw, | ||
382 | [AUD_CLKID_FRDDR_C] = &axg_frddr_c.hw, | ||
383 | [AUD_CLKID_TODDR_A] = &axg_toddr_a.hw, | ||
384 | [AUD_CLKID_TODDR_B] = &axg_toddr_b.hw, | ||
385 | [AUD_CLKID_TODDR_C] = &axg_toddr_c.hw, | ||
386 | [AUD_CLKID_LOOPBACK] = &axg_loopback.hw, | ||
387 | [AUD_CLKID_SPDIFIN] = &axg_spdifin.hw, | ||
388 | [AUD_CLKID_SPDIFOUT] = &axg_spdifout.hw, | ||
389 | [AUD_CLKID_RESAMPLE] = &axg_resample.hw, | ||
390 | [AUD_CLKID_POWER_DETECT] = &axg_power_detect.hw, | ||
391 | [AUD_CLKID_MST_A_MCLK_SEL] = &axg_mst_a_mclk_sel.hw, | ||
392 | [AUD_CLKID_MST_B_MCLK_SEL] = &axg_mst_b_mclk_sel.hw, | ||
393 | [AUD_CLKID_MST_C_MCLK_SEL] = &axg_mst_c_mclk_sel.hw, | ||
394 | [AUD_CLKID_MST_D_MCLK_SEL] = &axg_mst_d_mclk_sel.hw, | ||
395 | [AUD_CLKID_MST_E_MCLK_SEL] = &axg_mst_e_mclk_sel.hw, | ||
396 | [AUD_CLKID_MST_F_MCLK_SEL] = &axg_mst_f_mclk_sel.hw, | ||
397 | [AUD_CLKID_MST_A_MCLK_DIV] = &axg_mst_a_mclk_div.hw, | ||
398 | [AUD_CLKID_MST_B_MCLK_DIV] = &axg_mst_b_mclk_div.hw, | ||
399 | [AUD_CLKID_MST_C_MCLK_DIV] = &axg_mst_c_mclk_div.hw, | ||
400 | [AUD_CLKID_MST_D_MCLK_DIV] = &axg_mst_d_mclk_div.hw, | ||
401 | [AUD_CLKID_MST_E_MCLK_DIV] = &axg_mst_e_mclk_div.hw, | ||
402 | [AUD_CLKID_MST_F_MCLK_DIV] = &axg_mst_f_mclk_div.hw, | ||
403 | [AUD_CLKID_MST_A_MCLK] = &axg_mst_a_mclk.hw, | ||
404 | [AUD_CLKID_MST_B_MCLK] = &axg_mst_b_mclk.hw, | ||
405 | [AUD_CLKID_MST_C_MCLK] = &axg_mst_c_mclk.hw, | ||
406 | [AUD_CLKID_MST_D_MCLK] = &axg_mst_d_mclk.hw, | ||
407 | [AUD_CLKID_MST_E_MCLK] = &axg_mst_e_mclk.hw, | ||
408 | [AUD_CLKID_MST_F_MCLK] = &axg_mst_f_mclk.hw, | ||
409 | [AUD_CLKID_SPDIFOUT_CLK_SEL] = &axg_spdifout_clk_sel.hw, | ||
410 | [AUD_CLKID_SPDIFOUT_CLK_DIV] = &axg_spdifout_clk_div.hw, | ||
411 | [AUD_CLKID_SPDIFOUT_CLK] = &axg_spdifout_clk.hw, | ||
412 | [AUD_CLKID_SPDIFIN_CLK_SEL] = &axg_spdifin_clk_sel.hw, | ||
413 | [AUD_CLKID_SPDIFIN_CLK_DIV] = &axg_spdifin_clk_div.hw, | ||
414 | [AUD_CLKID_SPDIFIN_CLK] = &axg_spdifin_clk.hw, | ||
415 | [AUD_CLKID_PDM_DCLK_SEL] = &axg_pdm_dclk_sel.hw, | ||
416 | [AUD_CLKID_PDM_DCLK_DIV] = &axg_pdm_dclk_div.hw, | ||
417 | [AUD_CLKID_PDM_DCLK] = &axg_pdm_dclk.hw, | ||
418 | [AUD_CLKID_PDM_SYSCLK_SEL] = &axg_pdm_sysclk_sel.hw, | ||
419 | [AUD_CLKID_PDM_SYSCLK_DIV] = &axg_pdm_sysclk_div.hw, | ||
420 | [AUD_CLKID_PDM_SYSCLK] = &axg_pdm_sysclk.hw, | ||
421 | [AUD_CLKID_MST_A_SCLK_PRE_EN] = &axg_mst_a_sclk_pre_en.hw, | ||
422 | [AUD_CLKID_MST_B_SCLK_PRE_EN] = &axg_mst_b_sclk_pre_en.hw, | ||
423 | [AUD_CLKID_MST_C_SCLK_PRE_EN] = &axg_mst_c_sclk_pre_en.hw, | ||
424 | [AUD_CLKID_MST_D_SCLK_PRE_EN] = &axg_mst_d_sclk_pre_en.hw, | ||
425 | [AUD_CLKID_MST_E_SCLK_PRE_EN] = &axg_mst_e_sclk_pre_en.hw, | ||
426 | [AUD_CLKID_MST_F_SCLK_PRE_EN] = &axg_mst_f_sclk_pre_en.hw, | ||
427 | [AUD_CLKID_MST_A_SCLK_DIV] = &axg_mst_a_sclk_div.hw, | ||
428 | [AUD_CLKID_MST_B_SCLK_DIV] = &axg_mst_b_sclk_div.hw, | ||
429 | [AUD_CLKID_MST_C_SCLK_DIV] = &axg_mst_c_sclk_div.hw, | ||
430 | [AUD_CLKID_MST_D_SCLK_DIV] = &axg_mst_d_sclk_div.hw, | ||
431 | [AUD_CLKID_MST_E_SCLK_DIV] = &axg_mst_e_sclk_div.hw, | ||
432 | [AUD_CLKID_MST_F_SCLK_DIV] = &axg_mst_f_sclk_div.hw, | ||
433 | [AUD_CLKID_MST_A_SCLK_POST_EN] = &axg_mst_a_sclk_post_en.hw, | ||
434 | [AUD_CLKID_MST_B_SCLK_POST_EN] = &axg_mst_b_sclk_post_en.hw, | ||
435 | [AUD_CLKID_MST_C_SCLK_POST_EN] = &axg_mst_c_sclk_post_en.hw, | ||
436 | [AUD_CLKID_MST_D_SCLK_POST_EN] = &axg_mst_d_sclk_post_en.hw, | ||
437 | [AUD_CLKID_MST_E_SCLK_POST_EN] = &axg_mst_e_sclk_post_en.hw, | ||
438 | [AUD_CLKID_MST_F_SCLK_POST_EN] = &axg_mst_f_sclk_post_en.hw, | ||
439 | [AUD_CLKID_MST_A_SCLK] = &axg_mst_a_sclk.hw, | ||
440 | [AUD_CLKID_MST_B_SCLK] = &axg_mst_b_sclk.hw, | ||
441 | [AUD_CLKID_MST_C_SCLK] = &axg_mst_c_sclk.hw, | ||
442 | [AUD_CLKID_MST_D_SCLK] = &axg_mst_d_sclk.hw, | ||
443 | [AUD_CLKID_MST_E_SCLK] = &axg_mst_e_sclk.hw, | ||
444 | [AUD_CLKID_MST_F_SCLK] = &axg_mst_f_sclk.hw, | ||
445 | [AUD_CLKID_MST_A_LRCLK_DIV] = &axg_mst_a_lrclk_div.hw, | ||
446 | [AUD_CLKID_MST_B_LRCLK_DIV] = &axg_mst_b_lrclk_div.hw, | ||
447 | [AUD_CLKID_MST_C_LRCLK_DIV] = &axg_mst_c_lrclk_div.hw, | ||
448 | [AUD_CLKID_MST_D_LRCLK_DIV] = &axg_mst_d_lrclk_div.hw, | ||
449 | [AUD_CLKID_MST_E_LRCLK_DIV] = &axg_mst_e_lrclk_div.hw, | ||
450 | [AUD_CLKID_MST_F_LRCLK_DIV] = &axg_mst_f_lrclk_div.hw, | ||
451 | [AUD_CLKID_MST_A_LRCLK] = &axg_mst_a_lrclk.hw, | ||
452 | [AUD_CLKID_MST_B_LRCLK] = &axg_mst_b_lrclk.hw, | ||
453 | [AUD_CLKID_MST_C_LRCLK] = &axg_mst_c_lrclk.hw, | ||
454 | [AUD_CLKID_MST_D_LRCLK] = &axg_mst_d_lrclk.hw, | ||
455 | [AUD_CLKID_MST_E_LRCLK] = &axg_mst_e_lrclk.hw, | ||
456 | [AUD_CLKID_MST_F_LRCLK] = &axg_mst_f_lrclk.hw, | ||
457 | [AUD_CLKID_TDMIN_A_SCLK_SEL] = &axg_tdmin_a_sclk_sel.hw, | ||
458 | [AUD_CLKID_TDMIN_B_SCLK_SEL] = &axg_tdmin_b_sclk_sel.hw, | ||
459 | [AUD_CLKID_TDMIN_C_SCLK_SEL] = &axg_tdmin_c_sclk_sel.hw, | ||
460 | [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &axg_tdmin_lb_sclk_sel.hw, | ||
461 | [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &axg_tdmout_a_sclk_sel.hw, | ||
462 | [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &axg_tdmout_b_sclk_sel.hw, | ||
463 | [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &axg_tdmout_c_sclk_sel.hw, | ||
464 | [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &axg_tdmin_a_sclk_pre_en.hw, | ||
465 | [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &axg_tdmin_b_sclk_pre_en.hw, | ||
466 | [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &axg_tdmin_c_sclk_pre_en.hw, | ||
467 | [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw, | ||
468 | [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw, | ||
469 | [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw, | ||
470 | [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw, | ||
471 | [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw, | ||
472 | [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw, | ||
473 | [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw, | ||
474 | [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw, | ||
475 | [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw, | ||
476 | [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw, | ||
477 | [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw, | ||
478 | [AUD_CLKID_TDMIN_A_SCLK] = &axg_tdmin_a_sclk.hw, | ||
479 | [AUD_CLKID_TDMIN_B_SCLK] = &axg_tdmin_b_sclk.hw, | ||
480 | [AUD_CLKID_TDMIN_C_SCLK] = &axg_tdmin_c_sclk.hw, | ||
481 | [AUD_CLKID_TDMIN_LB_SCLK] = &axg_tdmin_lb_sclk.hw, | ||
482 | [AUD_CLKID_TDMOUT_A_SCLK] = &axg_tdmout_a_sclk.hw, | ||
483 | [AUD_CLKID_TDMOUT_B_SCLK] = &axg_tdmout_b_sclk.hw, | ||
484 | [AUD_CLKID_TDMOUT_C_SCLK] = &axg_tdmout_c_sclk.hw, | ||
485 | [AUD_CLKID_TDMIN_A_LRCLK] = &axg_tdmin_a_lrclk.hw, | ||
486 | [AUD_CLKID_TDMIN_B_LRCLK] = &axg_tdmin_b_lrclk.hw, | ||
487 | [AUD_CLKID_TDMIN_C_LRCLK] = &axg_tdmin_c_lrclk.hw, | ||
488 | [AUD_CLKID_TDMIN_LB_LRCLK] = &axg_tdmin_lb_lrclk.hw, | ||
489 | [AUD_CLKID_TDMOUT_A_LRCLK] = &axg_tdmout_a_lrclk.hw, | ||
490 | [AUD_CLKID_TDMOUT_B_LRCLK] = &axg_tdmout_b_lrclk.hw, | ||
491 | [AUD_CLKID_TDMOUT_C_LRCLK] = &axg_tdmout_c_lrclk.hw, | ||
492 | [NR_CLKS] = NULL, | ||
493 | }, | ||
494 | .num = NR_CLKS, | ||
495 | }; | ||
496 | |||
497 | /* Convenience table to populate regmap in .probe() */ | ||
498 | static struct clk_regmap *const axg_audio_clk_regmaps[] = { | ||
499 | &axg_ddr_arb, | ||
500 | &axg_pdm, | ||
501 | &axg_tdmin_a, | ||
502 | &axg_tdmin_b, | ||
503 | &axg_tdmin_c, | ||
504 | &axg_tdmin_lb, | ||
505 | &axg_tdmout_a, | ||
506 | &axg_tdmout_b, | ||
507 | &axg_tdmout_c, | ||
508 | &axg_frddr_a, | ||
509 | &axg_frddr_b, | ||
510 | &axg_frddr_c, | ||
511 | &axg_toddr_a, | ||
512 | &axg_toddr_b, | ||
513 | &axg_toddr_c, | ||
514 | &axg_loopback, | ||
515 | &axg_spdifin, | ||
516 | &axg_spdifout, | ||
517 | &axg_resample, | ||
518 | &axg_power_detect, | ||
519 | &axg_mst_a_mclk_sel, | ||
520 | &axg_mst_b_mclk_sel, | ||
521 | &axg_mst_c_mclk_sel, | ||
522 | &axg_mst_d_mclk_sel, | ||
523 | &axg_mst_e_mclk_sel, | ||
524 | &axg_mst_f_mclk_sel, | ||
525 | &axg_mst_a_mclk_div, | ||
526 | &axg_mst_b_mclk_div, | ||
527 | &axg_mst_c_mclk_div, | ||
528 | &axg_mst_d_mclk_div, | ||
529 | &axg_mst_e_mclk_div, | ||
530 | &axg_mst_f_mclk_div, | ||
531 | &axg_mst_a_mclk, | ||
532 | &axg_mst_b_mclk, | ||
533 | &axg_mst_c_mclk, | ||
534 | &axg_mst_d_mclk, | ||
535 | &axg_mst_e_mclk, | ||
536 | &axg_mst_f_mclk, | ||
537 | &axg_spdifout_clk_sel, | ||
538 | &axg_spdifout_clk_div, | ||
539 | &axg_spdifout_clk, | ||
540 | &axg_spdifin_clk_sel, | ||
541 | &axg_spdifin_clk_div, | ||
542 | &axg_spdifin_clk, | ||
543 | &axg_pdm_dclk_sel, | ||
544 | &axg_pdm_dclk_div, | ||
545 | &axg_pdm_dclk, | ||
546 | &axg_pdm_sysclk_sel, | ||
547 | &axg_pdm_sysclk_div, | ||
548 | &axg_pdm_sysclk, | ||
549 | &axg_mst_a_sclk_pre_en, | ||
550 | &axg_mst_b_sclk_pre_en, | ||
551 | &axg_mst_c_sclk_pre_en, | ||
552 | &axg_mst_d_sclk_pre_en, | ||
553 | &axg_mst_e_sclk_pre_en, | ||
554 | &axg_mst_f_sclk_pre_en, | ||
555 | &axg_mst_a_sclk_div, | ||
556 | &axg_mst_b_sclk_div, | ||
557 | &axg_mst_c_sclk_div, | ||
558 | &axg_mst_d_sclk_div, | ||
559 | &axg_mst_e_sclk_div, | ||
560 | &axg_mst_f_sclk_div, | ||
561 | &axg_mst_a_sclk_post_en, | ||
562 | &axg_mst_b_sclk_post_en, | ||
563 | &axg_mst_c_sclk_post_en, | ||
564 | &axg_mst_d_sclk_post_en, | ||
565 | &axg_mst_e_sclk_post_en, | ||
566 | &axg_mst_f_sclk_post_en, | ||
567 | &axg_mst_a_sclk, | ||
568 | &axg_mst_b_sclk, | ||
569 | &axg_mst_c_sclk, | ||
570 | &axg_mst_d_sclk, | ||
571 | &axg_mst_e_sclk, | ||
572 | &axg_mst_f_sclk, | ||
573 | &axg_mst_a_lrclk_div, | ||
574 | &axg_mst_b_lrclk_div, | ||
575 | &axg_mst_c_lrclk_div, | ||
576 | &axg_mst_d_lrclk_div, | ||
577 | &axg_mst_e_lrclk_div, | ||
578 | &axg_mst_f_lrclk_div, | ||
579 | &axg_mst_a_lrclk, | ||
580 | &axg_mst_b_lrclk, | ||
581 | &axg_mst_c_lrclk, | ||
582 | &axg_mst_d_lrclk, | ||
583 | &axg_mst_e_lrclk, | ||
584 | &axg_mst_f_lrclk, | ||
585 | &axg_tdmin_a_sclk_sel, | ||
586 | &axg_tdmin_b_sclk_sel, | ||
587 | &axg_tdmin_c_sclk_sel, | ||
588 | &axg_tdmin_lb_sclk_sel, | ||
589 | &axg_tdmout_a_sclk_sel, | ||
590 | &axg_tdmout_b_sclk_sel, | ||
591 | &axg_tdmout_c_sclk_sel, | ||
592 | &axg_tdmin_a_sclk_pre_en, | ||
593 | &axg_tdmin_b_sclk_pre_en, | ||
594 | &axg_tdmin_c_sclk_pre_en, | ||
595 | &axg_tdmin_lb_sclk_pre_en, | ||
596 | &axg_tdmout_a_sclk_pre_en, | ||
597 | &axg_tdmout_b_sclk_pre_en, | ||
598 | &axg_tdmout_c_sclk_pre_en, | ||
599 | &axg_tdmin_a_sclk_post_en, | ||
600 | &axg_tdmin_b_sclk_post_en, | ||
601 | &axg_tdmin_c_sclk_post_en, | ||
602 | &axg_tdmin_lb_sclk_post_en, | ||
603 | &axg_tdmout_a_sclk_post_en, | ||
604 | &axg_tdmout_b_sclk_post_en, | ||
605 | &axg_tdmout_c_sclk_post_en, | ||
606 | &axg_tdmin_a_sclk, | ||
607 | &axg_tdmin_b_sclk, | ||
608 | &axg_tdmin_c_sclk, | ||
609 | &axg_tdmin_lb_sclk, | ||
610 | &axg_tdmout_a_sclk, | ||
611 | &axg_tdmout_b_sclk, | ||
612 | &axg_tdmout_c_sclk, | ||
613 | &axg_tdmin_a_lrclk, | ||
614 | &axg_tdmin_b_lrclk, | ||
615 | &axg_tdmin_c_lrclk, | ||
616 | &axg_tdmin_lb_lrclk, | ||
617 | &axg_tdmout_a_lrclk, | ||
618 | &axg_tdmout_b_lrclk, | ||
619 | &axg_tdmout_c_lrclk, | ||
620 | }; | ||
621 | |||
622 | static struct clk *devm_clk_get_enable(struct device *dev, char *id) | ||
623 | { | ||
624 | struct clk *clk; | ||
625 | int ret; | ||
626 | |||
627 | clk = devm_clk_get(dev, id); | ||
628 | if (IS_ERR(clk)) { | ||
629 | if (PTR_ERR(clk) != -EPROBE_DEFER) | ||
630 | dev_err(dev, "failed to get %s", id); | ||
631 | return clk; | ||
632 | } | ||
633 | |||
634 | ret = clk_prepare_enable(clk); | ||
635 | if (ret) { | ||
636 | dev_err(dev, "failed to enable %s", id); | ||
637 | return ERR_PTR(ret); | ||
638 | } | ||
639 | |||
640 | ret = devm_add_action_or_reset(dev, | ||
641 | (void(*)(void *))clk_disable_unprepare, | ||
642 | clk); | ||
643 | if (ret) { | ||
644 | dev_err(dev, "failed to add reset action on %s", id); | ||
645 | return ERR_PTR(ret); | ||
646 | } | ||
647 | |||
648 | return clk; | ||
649 | } | ||
650 | |||
651 | static const struct clk_ops axg_clk_no_ops = {}; | ||
652 | |||
653 | static struct clk_hw *axg_clk_hw_register_bypass(struct device *dev, | ||
654 | const char *name, | ||
655 | const char *parent_name) | ||
656 | { | ||
657 | struct clk_hw *hw; | ||
658 | struct clk_init_data init; | ||
659 | char *clk_name; | ||
660 | int ret; | ||
661 | |||
662 | hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); | ||
663 | if (!hw) | ||
664 | return ERR_PTR(-ENOMEM); | ||
665 | |||
666 | clk_name = kasprintf(GFP_KERNEL, "axg_%s", name); | ||
667 | if (!clk_name) | ||
668 | return ERR_PTR(-ENOMEM); | ||
669 | |||
670 | init.name = clk_name; | ||
671 | init.ops = &axg_clk_no_ops; | ||
672 | init.flags = 0; | ||
673 | init.parent_names = parent_name ? &parent_name : NULL; | ||
674 | init.num_parents = parent_name ? 1 : 0; | ||
675 | hw->init = &init; | ||
676 | |||
677 | ret = devm_clk_hw_register(dev, hw); | ||
678 | kfree(clk_name); | ||
679 | |||
680 | return ret ? ERR_PTR(ret) : hw; | ||
681 | } | ||
682 | |||
683 | static int axg_register_clk_hw_input(struct device *dev, | ||
684 | const char *name, | ||
685 | unsigned int clkid) | ||
686 | { | ||
687 | struct clk *parent_clk = devm_clk_get(dev, name); | ||
688 | struct clk_hw *hw = NULL; | ||
689 | |||
690 | if (IS_ERR(parent_clk)) { | ||
691 | int err = PTR_ERR(parent_clk); | ||
692 | |||
693 | /* It is ok if an input clock is missing */ | ||
694 | if (err == -ENOENT) { | ||
695 | dev_dbg(dev, "%s not provided", name); | ||
696 | } else { | ||
697 | if (err != -EPROBE_DEFER) | ||
698 | dev_err(dev, "failed to get %s clock", name); | ||
699 | return err; | ||
700 | } | ||
701 | } else { | ||
702 | hw = axg_clk_hw_register_bypass(dev, name, | ||
703 | __clk_get_name(parent_clk)); | ||
704 | } | ||
705 | |||
706 | if (IS_ERR(hw)) { | ||
707 | dev_err(dev, "failed to register %s clock", name); | ||
708 | return PTR_ERR(hw); | ||
709 | } | ||
710 | |||
711 | axg_audio_hw_onecell_data.hws[clkid] = hw; | ||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static int axg_register_clk_hw_inputs(struct device *dev, | ||
716 | const char *basename, | ||
717 | unsigned int count, | ||
718 | unsigned int clkid) | ||
719 | { | ||
720 | char *name; | ||
721 | int i, ret; | ||
722 | |||
723 | for (i = 0; i < count; i++) { | ||
724 | name = kasprintf(GFP_KERNEL, "%s%d", basename, i); | ||
725 | if (!name) | ||
726 | return -ENOMEM; | ||
727 | |||
728 | ret = axg_register_clk_hw_input(dev, name, clkid + i); | ||
729 | kfree(name); | ||
730 | if (ret) | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static const struct regmap_config axg_audio_regmap_cfg = { | ||
738 | .reg_bits = 32, | ||
739 | .val_bits = 32, | ||
740 | .reg_stride = 4, | ||
741 | .max_register = AUDIO_CLK_PDMIN_CTRL1, | ||
742 | }; | ||
743 | |||
744 | static int axg_audio_clkc_probe(struct platform_device *pdev) | ||
745 | { | ||
746 | struct device *dev = &pdev->dev; | ||
747 | struct regmap *map; | ||
748 | struct resource *res; | ||
749 | void __iomem *regs; | ||
750 | struct clk *clk; | ||
751 | struct clk_hw *hw; | ||
752 | int ret, i; | ||
753 | |||
754 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
755 | regs = devm_ioremap_resource(dev, res); | ||
756 | if (IS_ERR(regs)) | ||
757 | return PTR_ERR(regs); | ||
758 | |||
759 | map = devm_regmap_init_mmio(dev, regs, &axg_audio_regmap_cfg); | ||
760 | if (IS_ERR(map)) { | ||
761 | dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(map)); | ||
762 | return PTR_ERR(map); | ||
763 | } | ||
764 | |||
765 | /* Get the mandatory peripheral clock */ | ||
766 | clk = devm_clk_get_enable(dev, "pclk"); | ||
767 | if (IS_ERR(clk)) | ||
768 | return PTR_ERR(clk); | ||
769 | |||
770 | ret = device_reset(dev); | ||
771 | if (ret) { | ||
772 | dev_err(dev, "failed to reset device\n"); | ||
773 | return ret; | ||
774 | } | ||
775 | |||
776 | /* Register the peripheral input clock */ | ||
777 | hw = axg_clk_hw_register_bypass(dev, "audio_pclk", | ||
778 | __clk_get_name(clk)); | ||
779 | if (IS_ERR(hw)) | ||
780 | return PTR_ERR(hw); | ||
781 | |||
782 | axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw; | ||
783 | |||
784 | /* Register optional input master clocks */ | ||
785 | ret = axg_register_clk_hw_inputs(dev, "mst_in", | ||
786 | AXG_MST_IN_COUNT, | ||
787 | AUD_CLKID_MST0); | ||
788 | if (ret) | ||
789 | return ret; | ||
790 | |||
791 | /* Register optional input slave sclks */ | ||
792 | ret = axg_register_clk_hw_inputs(dev, "slv_sclk", | ||
793 | AXG_SLV_SCLK_COUNT, | ||
794 | AUD_CLKID_SLV_SCLK0); | ||
795 | if (ret) | ||
796 | return ret; | ||
797 | |||
798 | /* Register optional input slave lrclks */ | ||
799 | ret = axg_register_clk_hw_inputs(dev, "slv_lrclk", | ||
800 | AXG_SLV_LRCLK_COUNT, | ||
801 | AUD_CLKID_SLV_LRCLK0); | ||
802 | if (ret) | ||
803 | return ret; | ||
804 | |||
805 | /* Populate regmap for the regmap backed clocks */ | ||
806 | for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++) | ||
807 | axg_audio_clk_regmaps[i]->map = map; | ||
808 | |||
809 | /* Take care to skip the registered input clocks */ | ||
810 | for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) { | ||
811 | hw = axg_audio_hw_onecell_data.hws[i]; | ||
812 | /* array might be sparse */ | ||
813 | if (!hw) | ||
814 | continue; | ||
815 | |||
816 | ret = devm_clk_hw_register(dev, hw); | ||
817 | if (ret) { | ||
818 | dev_err(dev, "failed to register clock %s\n", | ||
819 | hw->init->name); | ||
820 | return ret; | ||
821 | } | ||
822 | } | ||
823 | |||
824 | return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, | ||
825 | &axg_audio_hw_onecell_data); | ||
826 | } | ||
827 | |||
828 | static const struct of_device_id clkc_match_table[] = { | ||
829 | { .compatible = "amlogic,axg-audio-clkc" }, | ||
830 | {} | ||
831 | }; | ||
832 | MODULE_DEVICE_TABLE(of, clkc_match_table); | ||
833 | |||
834 | static struct platform_driver axg_audio_driver = { | ||
835 | .probe = axg_audio_clkc_probe, | ||
836 | .driver = { | ||
837 | .name = "axg-audio-clkc", | ||
838 | .of_match_table = clkc_match_table, | ||
839 | }, | ||
840 | }; | ||
841 | module_platform_driver(axg_audio_driver); | ||
842 | |||
843 | MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver"); | ||
844 | MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); | ||
845 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h new file mode 100644 index 000000000000..7191b39c9d65 --- /dev/null +++ b/drivers/clk/meson/axg-audio.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ | ||
2 | /* | ||
3 | * Copyright (c) 2018 BayLibre, SAS. | ||
4 | * Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | */ | ||
6 | |||
7 | #ifndef __AXG_AUDIO_CLKC_H | ||
8 | #define __AXG_AUDIO_CLKC_H | ||
9 | |||
10 | /* | ||
11 | * Audio Clock register offsets | ||
12 | * | ||
13 | * Register offsets from the datasheet must be multiplied by 4 before | ||
14 | * to get the right offset | ||
15 | */ | ||
16 | #define AUDIO_CLK_GATE_EN 0x000 | ||
17 | #define AUDIO_MCLK_A_CTRL 0x004 | ||
18 | #define AUDIO_MCLK_B_CTRL 0x008 | ||
19 | #define AUDIO_MCLK_C_CTRL 0x00C | ||
20 | #define AUDIO_MCLK_D_CTRL 0x010 | ||
21 | #define AUDIO_MCLK_E_CTRL 0x014 | ||
22 | #define AUDIO_MCLK_F_CTRL 0x018 | ||
23 | #define AUDIO_MST_A_SCLK_CTRL0 0x040 | ||
24 | #define AUDIO_MST_A_SCLK_CTRL1 0x044 | ||
25 | #define AUDIO_MST_B_SCLK_CTRL0 0x048 | ||
26 | #define AUDIO_MST_B_SCLK_CTRL1 0x04C | ||
27 | #define AUDIO_MST_C_SCLK_CTRL0 0x050 | ||
28 | #define AUDIO_MST_C_SCLK_CTRL1 0x054 | ||
29 | #define AUDIO_MST_D_SCLK_CTRL0 0x058 | ||
30 | #define AUDIO_MST_D_SCLK_CTRL1 0x05C | ||
31 | #define AUDIO_MST_E_SCLK_CTRL0 0x060 | ||
32 | #define AUDIO_MST_E_SCLK_CTRL1 0x064 | ||
33 | #define AUDIO_MST_F_SCLK_CTRL0 0x068 | ||
34 | #define AUDIO_MST_F_SCLK_CTRL1 0x06C | ||
35 | #define AUDIO_CLK_TDMIN_A_CTRL 0x080 | ||
36 | #define AUDIO_CLK_TDMIN_B_CTRL 0x084 | ||
37 | #define AUDIO_CLK_TDMIN_C_CTRL 0x088 | ||
38 | #define AUDIO_CLK_TDMIN_LB_CTRL 0x08C | ||
39 | #define AUDIO_CLK_TDMOUT_A_CTRL 0x090 | ||
40 | #define AUDIO_CLK_TDMOUT_B_CTRL 0x094 | ||
41 | #define AUDIO_CLK_TDMOUT_C_CTRL 0x098 | ||
42 | #define AUDIO_CLK_SPDIFIN_CTRL 0x09C | ||
43 | #define AUDIO_CLK_SPDIFOUT_CTRL 0x0A0 | ||
44 | #define AUDIO_CLK_RESAMPLE_CTRL 0x0A4 | ||
45 | #define AUDIO_CLK_LOCKER_CTRL 0x0A8 | ||
46 | #define AUDIO_CLK_PDMIN_CTRL0 0x0AC | ||
47 | #define AUDIO_CLK_PDMIN_CTRL1 0x0B0 | ||
48 | |||
49 | /* | ||
50 | * CLKID index values | ||
51 | * These indices are entirely contrived and do not map onto the hardware. | ||
52 | */ | ||
53 | |||
54 | #define AUD_CLKID_PCLK 0 | ||
55 | #define AUD_CLKID_MST0 1 | ||
56 | #define AUD_CLKID_MST1 2 | ||
57 | #define AUD_CLKID_MST2 3 | ||
58 | #define AUD_CLKID_MST3 4 | ||
59 | #define AUD_CLKID_MST4 5 | ||
60 | #define AUD_CLKID_MST5 6 | ||
61 | #define AUD_CLKID_MST6 7 | ||
62 | #define AUD_CLKID_MST7 8 | ||
63 | #define AUD_CLKID_MST_A_MCLK_SEL 59 | ||
64 | #define AUD_CLKID_MST_B_MCLK_SEL 60 | ||
65 | #define AUD_CLKID_MST_C_MCLK_SEL 61 | ||
66 | #define AUD_CLKID_MST_D_MCLK_SEL 62 | ||
67 | #define AUD_CLKID_MST_E_MCLK_SEL 63 | ||
68 | #define AUD_CLKID_MST_F_MCLK_SEL 64 | ||
69 | #define AUD_CLKID_MST_A_MCLK_DIV 65 | ||
70 | #define AUD_CLKID_MST_B_MCLK_DIV 66 | ||
71 | #define AUD_CLKID_MST_C_MCLK_DIV 67 | ||
72 | #define AUD_CLKID_MST_D_MCLK_DIV 68 | ||
73 | #define AUD_CLKID_MST_E_MCLK_DIV 69 | ||
74 | #define AUD_CLKID_MST_F_MCLK_DIV 70 | ||
75 | #define AUD_CLKID_SPDIFOUT_CLK_SEL 71 | ||
76 | #define AUD_CLKID_SPDIFOUT_CLK_DIV 72 | ||
77 | #define AUD_CLKID_SPDIFIN_CLK_SEL 73 | ||
78 | #define AUD_CLKID_SPDIFIN_CLK_DIV 74 | ||
79 | #define AUD_CLKID_PDM_DCLK_SEL 75 | ||
80 | #define AUD_CLKID_PDM_DCLK_DIV 76 | ||
81 | #define AUD_CLKID_PDM_SYSCLK_SEL 77 | ||
82 | #define AUD_CLKID_PDM_SYSCLK_DIV 78 | ||
83 | #define AUD_CLKID_MST_A_SCLK_PRE_EN 92 | ||
84 | #define AUD_CLKID_MST_B_SCLK_PRE_EN 93 | ||
85 | #define AUD_CLKID_MST_C_SCLK_PRE_EN 94 | ||
86 | #define AUD_CLKID_MST_D_SCLK_PRE_EN 95 | ||
87 | #define AUD_CLKID_MST_E_SCLK_PRE_EN 96 | ||
88 | #define AUD_CLKID_MST_F_SCLK_PRE_EN 97 | ||
89 | #define AUD_CLKID_MST_A_SCLK_DIV 98 | ||
90 | #define AUD_CLKID_MST_B_SCLK_DIV 99 | ||
91 | #define AUD_CLKID_MST_C_SCLK_DIV 100 | ||
92 | #define AUD_CLKID_MST_D_SCLK_DIV 101 | ||
93 | #define AUD_CLKID_MST_E_SCLK_DIV 102 | ||
94 | #define AUD_CLKID_MST_F_SCLK_DIV 103 | ||
95 | #define AUD_CLKID_MST_A_SCLK_POST_EN 104 | ||
96 | #define AUD_CLKID_MST_B_SCLK_POST_EN 105 | ||
97 | #define AUD_CLKID_MST_C_SCLK_POST_EN 106 | ||
98 | #define AUD_CLKID_MST_D_SCLK_POST_EN 107 | ||
99 | #define AUD_CLKID_MST_E_SCLK_POST_EN 108 | ||
100 | #define AUD_CLKID_MST_F_SCLK_POST_EN 109 | ||
101 | #define AUD_CLKID_MST_A_LRCLK_DIV 110 | ||
102 | #define AUD_CLKID_MST_B_LRCLK_DIV 111 | ||
103 | #define AUD_CLKID_MST_C_LRCLK_DIV 112 | ||
104 | #define AUD_CLKID_MST_D_LRCLK_DIV 113 | ||
105 | #define AUD_CLKID_MST_E_LRCLK_DIV 114 | ||
106 | #define AUD_CLKID_MST_F_LRCLK_DIV 115 | ||
107 | #define AUD_CLKID_TDMIN_A_SCLK_PRE_EN 137 | ||
108 | #define AUD_CLKID_TDMIN_B_SCLK_PRE_EN 138 | ||
109 | #define AUD_CLKID_TDMIN_C_SCLK_PRE_EN 139 | ||
110 | #define AUD_CLKID_TDMIN_LB_SCLK_PRE_EN 140 | ||
111 | #define AUD_CLKID_TDMOUT_A_SCLK_PRE_EN 141 | ||
112 | #define AUD_CLKID_TDMOUT_B_SCLK_PRE_EN 142 | ||
113 | #define AUD_CLKID_TDMOUT_C_SCLK_PRE_EN 143 | ||
114 | #define AUD_CLKID_TDMIN_A_SCLK_POST_EN 144 | ||
115 | #define AUD_CLKID_TDMIN_B_SCLK_POST_EN 145 | ||
116 | #define AUD_CLKID_TDMIN_C_SCLK_POST_EN 146 | ||
117 | #define AUD_CLKID_TDMIN_LB_SCLK_POST_EN 147 | ||
118 | #define AUD_CLKID_TDMOUT_A_SCLK_POST_EN 148 | ||
119 | #define AUD_CLKID_TDMOUT_B_SCLK_POST_EN 149 | ||
120 | #define AUD_CLKID_TDMOUT_C_SCLK_POST_EN 150 | ||
121 | |||
122 | /* include the CLKIDs which are part of the DT bindings */ | ||
123 | #include <dt-bindings/clock/axg-audio-clkc.h> | ||
124 | |||
125 | #define NR_CLKS 151 | ||
126 | |||
127 | #endif /*__AXG_AUDIO_CLKC_H */ | ||
diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index bd4dbc696b88..00ce62ad6416 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/clk.h> | 12 | #include <linux/clk.h> |
13 | #include <linux/clk-provider.h> | 13 | #include <linux/clk-provider.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/of_address.h> | ||
16 | #include <linux/of_device.h> | 15 | #include <linux/of_device.h> |
17 | #include <linux/mfd/syscon.h> | 16 | #include <linux/mfd/syscon.h> |
18 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
@@ -626,6 +625,137 @@ static struct clk_regmap axg_mpll3 = { | |||
626 | }, | 625 | }, |
627 | }; | 626 | }; |
628 | 627 | ||
628 | static const struct pll_rate_table axg_pcie_pll_rate_table[] = { | ||
629 | { | ||
630 | .rate = 100000000, | ||
631 | .m = 200, | ||
632 | .n = 3, | ||
633 | .od = 1, | ||
634 | .od2 = 3, | ||
635 | }, | ||
636 | { /* sentinel */ }, | ||
637 | }; | ||
638 | |||
639 | static const struct reg_sequence axg_pcie_init_regs[] = { | ||
640 | { .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 }, | ||
641 | { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa }, | ||
642 | { .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be }, | ||
643 | { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e }, | ||
644 | { .reg = HHI_PCIE_PLL_CNTL4, .def = 0xc000004d }, | ||
645 | { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x00078000 }, | ||
646 | { .reg = HHI_PCIE_PLL_CNTL6, .def = 0x002323c6 }, | ||
647 | }; | ||
648 | |||
649 | static struct clk_regmap axg_pcie_pll = { | ||
650 | .data = &(struct meson_clk_pll_data){ | ||
651 | .m = { | ||
652 | .reg_off = HHI_PCIE_PLL_CNTL, | ||
653 | .shift = 0, | ||
654 | .width = 9, | ||
655 | }, | ||
656 | .n = { | ||
657 | .reg_off = HHI_PCIE_PLL_CNTL, | ||
658 | .shift = 9, | ||
659 | .width = 5, | ||
660 | }, | ||
661 | .od = { | ||
662 | .reg_off = HHI_PCIE_PLL_CNTL, | ||
663 | .shift = 16, | ||
664 | .width = 2, | ||
665 | }, | ||
666 | .od2 = { | ||
667 | .reg_off = HHI_PCIE_PLL_CNTL6, | ||
668 | .shift = 6, | ||
669 | .width = 2, | ||
670 | }, | ||
671 | .frac = { | ||
672 | .reg_off = HHI_PCIE_PLL_CNTL1, | ||
673 | .shift = 0, | ||
674 | .width = 12, | ||
675 | }, | ||
676 | .l = { | ||
677 | .reg_off = HHI_PCIE_PLL_CNTL, | ||
678 | .shift = 31, | ||
679 | .width = 1, | ||
680 | }, | ||
681 | .rst = { | ||
682 | .reg_off = HHI_PCIE_PLL_CNTL, | ||
683 | .shift = 29, | ||
684 | .width = 1, | ||
685 | }, | ||
686 | .table = axg_pcie_pll_rate_table, | ||
687 | .init_regs = axg_pcie_init_regs, | ||
688 | .init_count = ARRAY_SIZE(axg_pcie_init_regs), | ||
689 | }, | ||
690 | .hw.init = &(struct clk_init_data){ | ||
691 | .name = "pcie_pll", | ||
692 | .ops = &meson_clk_pll_ops, | ||
693 | .parent_names = (const char *[]){ "xtal" }, | ||
694 | .num_parents = 1, | ||
695 | }, | ||
696 | }; | ||
697 | |||
698 | static struct clk_regmap axg_pcie_mux = { | ||
699 | .data = &(struct clk_regmap_mux_data){ | ||
700 | .offset = HHI_PCIE_PLL_CNTL6, | ||
701 | .mask = 0x1, | ||
702 | .shift = 2, | ||
703 | }, | ||
704 | .hw.init = &(struct clk_init_data){ | ||
705 | .name = "pcie_mux", | ||
706 | .ops = &clk_regmap_mux_ops, | ||
707 | .parent_names = (const char *[]){ "mpll3", "pcie_pll" }, | ||
708 | .num_parents = 2, | ||
709 | .flags = CLK_SET_RATE_PARENT, | ||
710 | }, | ||
711 | }; | ||
712 | |||
713 | static struct clk_regmap axg_pcie_ref = { | ||
714 | .data = &(struct clk_regmap_mux_data){ | ||
715 | .offset = HHI_PCIE_PLL_CNTL6, | ||
716 | .mask = 0x1, | ||
717 | .shift = 1, | ||
718 | /* skip the parent 0, reserved for debug */ | ||
719 | .table = (u32[]){ 1 }, | ||
720 | }, | ||
721 | .hw.init = &(struct clk_init_data){ | ||
722 | .name = "pcie_ref", | ||
723 | .ops = &clk_regmap_mux_ops, | ||
724 | .parent_names = (const char *[]){ "pcie_mux" }, | ||
725 | .num_parents = 1, | ||
726 | .flags = CLK_SET_RATE_PARENT, | ||
727 | }, | ||
728 | }; | ||
729 | |||
730 | static struct clk_regmap axg_pcie_cml_en0 = { | ||
731 | .data = &(struct clk_regmap_gate_data){ | ||
732 | .offset = HHI_PCIE_PLL_CNTL6, | ||
733 | .bit_idx = 4, | ||
734 | }, | ||
735 | .hw.init = &(struct clk_init_data) { | ||
736 | .name = "pcie_cml_en0", | ||
737 | .ops = &clk_regmap_gate_ops, | ||
738 | .parent_names = (const char *[]){ "pcie_ref" }, | ||
739 | .num_parents = 1, | ||
740 | .flags = CLK_SET_RATE_PARENT, | ||
741 | |||
742 | }, | ||
743 | }; | ||
744 | |||
745 | static struct clk_regmap axg_pcie_cml_en1 = { | ||
746 | .data = &(struct clk_regmap_gate_data){ | ||
747 | .offset = HHI_PCIE_PLL_CNTL6, | ||
748 | .bit_idx = 3, | ||
749 | }, | ||
750 | .hw.init = &(struct clk_init_data) { | ||
751 | .name = "pcie_cml_en1", | ||
752 | .ops = &clk_regmap_gate_ops, | ||
753 | .parent_names = (const char *[]){ "pcie_ref" }, | ||
754 | .num_parents = 1, | ||
755 | .flags = CLK_SET_RATE_PARENT, | ||
756 | }, | ||
757 | }; | ||
758 | |||
629 | static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; | 759 | static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; |
630 | static const char * const clk81_parent_names[] = { | 760 | static const char * const clk81_parent_names[] = { |
631 | "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", | 761 | "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", |
@@ -779,6 +909,63 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = { | |||
779 | }, | 909 | }, |
780 | }; | 910 | }; |
781 | 911 | ||
912 | static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, | ||
913 | 9, 10, 11, 13, 14, }; | ||
914 | static const char * const gen_clk_parent_names[] = { | ||
915 | "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3", | ||
916 | "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", | ||
917 | }; | ||
918 | |||
919 | static struct clk_regmap axg_gen_clk_sel = { | ||
920 | .data = &(struct clk_regmap_mux_data){ | ||
921 | .offset = HHI_GEN_CLK_CNTL, | ||
922 | .mask = 0xf, | ||
923 | .shift = 12, | ||
924 | .table = mux_table_gen_clk, | ||
925 | }, | ||
926 | .hw.init = &(struct clk_init_data){ | ||
927 | .name = "gen_clk_sel", | ||
928 | .ops = &clk_regmap_mux_ops, | ||
929 | /* | ||
930 | * bits 15:12 selects from 14 possible parents: | ||
931 | * xtal, [rtc_oscin_i], [sys_cpu_div16], [ddr_dpll_pt], | ||
932 | * hifi_pll, mpll0, mpll1, mpll2, mpll3, fdiv4, | ||
933 | * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll | ||
934 | */ | ||
935 | .parent_names = gen_clk_parent_names, | ||
936 | .num_parents = ARRAY_SIZE(gen_clk_parent_names), | ||
937 | }, | ||
938 | }; | ||
939 | |||
940 | static struct clk_regmap axg_gen_clk_div = { | ||
941 | .data = &(struct clk_regmap_div_data){ | ||
942 | .offset = HHI_GEN_CLK_CNTL, | ||
943 | .shift = 0, | ||
944 | .width = 11, | ||
945 | }, | ||
946 | .hw.init = &(struct clk_init_data){ | ||
947 | .name = "gen_clk_div", | ||
948 | .ops = &clk_regmap_divider_ops, | ||
949 | .parent_names = (const char *[]){ "gen_clk_sel" }, | ||
950 | .num_parents = 1, | ||
951 | .flags = CLK_SET_RATE_PARENT, | ||
952 | }, | ||
953 | }; | ||
954 | |||
955 | static struct clk_regmap axg_gen_clk = { | ||
956 | .data = &(struct clk_regmap_gate_data){ | ||
957 | .offset = HHI_GEN_CLK_CNTL, | ||
958 | .bit_idx = 7, | ||
959 | }, | ||
960 | .hw.init = &(struct clk_init_data){ | ||
961 | .name = "gen_clk", | ||
962 | .ops = &clk_regmap_gate_ops, | ||
963 | .parent_names = (const char *[]){ "gen_clk_div" }, | ||
964 | .num_parents = 1, | ||
965 | .flags = CLK_SET_RATE_PARENT, | ||
966 | }, | ||
967 | }; | ||
968 | |||
782 | /* Everything Else (EE) domain gates */ | 969 | /* Everything Else (EE) domain gates */ |
783 | static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0); | 970 | static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0); |
784 | static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2); | 971 | static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2); |
@@ -821,6 +1008,7 @@ static MESON_GATE(axg_mmc_pclk, HHI_GCLK_MPEG2, 11); | |||
821 | static MESON_GATE(axg_vpu_intr, HHI_GCLK_MPEG2, 25); | 1008 | static MESON_GATE(axg_vpu_intr, HHI_GCLK_MPEG2, 25); |
822 | static MESON_GATE(axg_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); | 1009 | static MESON_GATE(axg_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); |
823 | static MESON_GATE(axg_gic, HHI_GCLK_MPEG2, 30); | 1010 | static MESON_GATE(axg_gic, HHI_GCLK_MPEG2, 30); |
1011 | static MESON_GATE(axg_mipi_enable, HHI_MIPI_CNTL0, 29); | ||
824 | 1012 | ||
825 | /* Always On (AO) domain gates */ | 1013 | /* Always On (AO) domain gates */ |
826 | 1014 | ||
@@ -910,6 +1098,15 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { | |||
910 | [CLKID_FCLK_DIV4_DIV] = &axg_fclk_div4_div.hw, | 1098 | [CLKID_FCLK_DIV4_DIV] = &axg_fclk_div4_div.hw, |
911 | [CLKID_FCLK_DIV5_DIV] = &axg_fclk_div5_div.hw, | 1099 | [CLKID_FCLK_DIV5_DIV] = &axg_fclk_div5_div.hw, |
912 | [CLKID_FCLK_DIV7_DIV] = &axg_fclk_div7_div.hw, | 1100 | [CLKID_FCLK_DIV7_DIV] = &axg_fclk_div7_div.hw, |
1101 | [CLKID_PCIE_PLL] = &axg_pcie_pll.hw, | ||
1102 | [CLKID_PCIE_MUX] = &axg_pcie_mux.hw, | ||
1103 | [CLKID_PCIE_REF] = &axg_pcie_ref.hw, | ||
1104 | [CLKID_PCIE_CML_EN0] = &axg_pcie_cml_en0.hw, | ||
1105 | [CLKID_PCIE_CML_EN1] = &axg_pcie_cml_en1.hw, | ||
1106 | [CLKID_MIPI_ENABLE] = &axg_mipi_enable.hw, | ||
1107 | [CLKID_GEN_CLK_SEL] = &axg_gen_clk_sel.hw, | ||
1108 | [CLKID_GEN_CLK_DIV] = &axg_gen_clk_div.hw, | ||
1109 | [CLKID_GEN_CLK] = &axg_gen_clk.hw, | ||
913 | [NR_CLKS] = NULL, | 1110 | [NR_CLKS] = NULL, |
914 | }, | 1111 | }, |
915 | .num = NR_CLKS, | 1112 | .num = NR_CLKS, |
@@ -988,6 +1185,15 @@ static struct clk_regmap *const axg_clk_regmaps[] = { | |||
988 | &axg_fclk_div4, | 1185 | &axg_fclk_div4, |
989 | &axg_fclk_div5, | 1186 | &axg_fclk_div5, |
990 | &axg_fclk_div7, | 1187 | &axg_fclk_div7, |
1188 | &axg_pcie_pll, | ||
1189 | &axg_pcie_mux, | ||
1190 | &axg_pcie_ref, | ||
1191 | &axg_pcie_cml_en0, | ||
1192 | &axg_pcie_cml_en1, | ||
1193 | &axg_mipi_enable, | ||
1194 | &axg_gen_clk_sel, | ||
1195 | &axg_gen_clk_div, | ||
1196 | &axg_gen_clk, | ||
991 | }; | 1197 | }; |
992 | 1198 | ||
993 | static const struct of_device_id clkc_match_table[] = { | 1199 | static const struct of_device_id clkc_match_table[] = { |
@@ -995,49 +1201,17 @@ static const struct of_device_id clkc_match_table[] = { | |||
995 | {} | 1201 | {} |
996 | }; | 1202 | }; |
997 | 1203 | ||
998 | static const struct regmap_config clkc_regmap_config = { | ||
999 | .reg_bits = 32, | ||
1000 | .val_bits = 32, | ||
1001 | .reg_stride = 4, | ||
1002 | }; | ||
1003 | |||
1004 | static int axg_clkc_probe(struct platform_device *pdev) | 1204 | static int axg_clkc_probe(struct platform_device *pdev) |
1005 | { | 1205 | { |
1006 | struct device *dev = &pdev->dev; | 1206 | struct device *dev = &pdev->dev; |
1007 | struct resource *res; | ||
1008 | void __iomem *clk_base = NULL; | ||
1009 | struct regmap *map; | 1207 | struct regmap *map; |
1010 | int ret, i; | 1208 | int ret, i; |
1011 | 1209 | ||
1012 | /* Get the hhi system controller node if available */ | 1210 | /* Get the hhi system controller node if available */ |
1013 | map = syscon_node_to_regmap(of_get_parent(dev->of_node)); | 1211 | map = syscon_node_to_regmap(of_get_parent(dev->of_node)); |
1014 | if (IS_ERR(map)) { | 1212 | if (IS_ERR(map)) { |
1015 | dev_err(dev, | 1213 | dev_err(dev, "failed to get HHI regmap\n"); |
1016 | "failed to get HHI regmap - Trying obsolete regs\n"); | 1214 | return PTR_ERR(map); |
1017 | |||
1018 | /* | ||
1019 | * FIXME: HHI registers should be accessed through | ||
1020 | * the appropriate system controller. This is required because | ||
1021 | * there is more than just clocks in this register space | ||
1022 | * | ||
1023 | * This fallback method is only provided temporarily until | ||
1024 | * all the platform DTs are properly using the syscon node | ||
1025 | */ | ||
1026 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1027 | if (!res) | ||
1028 | return -EINVAL; | ||
1029 | |||
1030 | |||
1031 | clk_base = devm_ioremap(dev, res->start, resource_size(res)); | ||
1032 | if (!clk_base) { | ||
1033 | dev_err(dev, "Unable to map clk base\n"); | ||
1034 | return -ENXIO; | ||
1035 | } | ||
1036 | |||
1037 | map = devm_regmap_init_mmio(dev, clk_base, | ||
1038 | &clkc_regmap_config); | ||
1039 | if (IS_ERR(map)) | ||
1040 | return PTR_ERR(map); | ||
1041 | } | 1215 | } |
1042 | 1216 | ||
1043 | /* Populate regmap for the regmap backed clocks */ | 1217 | /* Populate regmap for the regmap backed clocks */ |
diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index b421df6a7ea0..1d04144a1b2c 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h | |||
@@ -16,6 +16,7 @@ | |||
16 | * Register offsets from the data sheet must be multiplied by 4 before | 16 | * Register offsets from the data sheet must be multiplied by 4 before |
17 | * adding them to the base address to get the right value. | 17 | * adding them to the base address to get the right value. |
18 | */ | 18 | */ |
19 | #define HHI_MIPI_CNTL0 0x00 | ||
19 | #define HHI_GP0_PLL_CNTL 0x40 | 20 | #define HHI_GP0_PLL_CNTL 0x40 |
20 | #define HHI_GP0_PLL_CNTL2 0x44 | 21 | #define HHI_GP0_PLL_CNTL2 0x44 |
21 | #define HHI_GP0_PLL_CNTL3 0x48 | 22 | #define HHI_GP0_PLL_CNTL3 0x48 |
@@ -127,8 +128,13 @@ | |||
127 | #define CLKID_FCLK_DIV4_DIV 73 | 128 | #define CLKID_FCLK_DIV4_DIV 73 |
128 | #define CLKID_FCLK_DIV5_DIV 74 | 129 | #define CLKID_FCLK_DIV5_DIV 74 |
129 | #define CLKID_FCLK_DIV7_DIV 75 | 130 | #define CLKID_FCLK_DIV7_DIV 75 |
131 | #define CLKID_PCIE_PLL 76 | ||
132 | #define CLKID_PCIE_MUX 77 | ||
133 | #define CLKID_PCIE_REF 78 | ||
134 | #define CLKID_GEN_CLK_SEL 82 | ||
135 | #define CLKID_GEN_CLK_DIV 83 | ||
130 | 136 | ||
131 | #define NR_CLKS 76 | 137 | #define NR_CLKS 85 |
132 | 138 | ||
133 | /* include the CLKIDs that have been made part of the DT binding */ | 139 | /* include the CLKIDs that have been made part of the DT binding */ |
134 | #include <dt-bindings/clock/axg-clkc.h> | 140 | #include <dt-bindings/clock/axg-clkc.h> |
diff --git a/drivers/clk/meson/clk-audio-divider.c b/drivers/clk/meson/clk-audio-divider.c deleted file mode 100644 index 58f546e04807..000000000000 --- a/drivers/clk/meson/clk-audio-divider.c +++ /dev/null | |||
@@ -1,110 +0,0 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (c) 2017 AmLogic, Inc. | ||
4 | * Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * i2s master clock divider: The algorithm of the generic clk-divider used with | ||
9 | * a very precise clock parent such as the mpll tends to select a low divider | ||
10 | * factor. This gives poor results with this particular divider, especially with | ||
11 | * high frequencies (> 100 MHz) | ||
12 | * | ||
13 | * This driver try to select the maximum possible divider with the rate the | ||
14 | * upstream clock can provide. | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk-provider.h> | ||
18 | #include "clkc.h" | ||
19 | |||
20 | static inline struct meson_clk_audio_div_data * | ||
21 | meson_clk_audio_div_data(struct clk_regmap *clk) | ||
22 | { | ||
23 | return (struct meson_clk_audio_div_data *)clk->data; | ||
24 | } | ||
25 | |||
26 | static int _div_round(unsigned long parent_rate, unsigned long rate, | ||
27 | unsigned long flags) | ||
28 | { | ||
29 | if (flags & CLK_DIVIDER_ROUND_CLOSEST) | ||
30 | return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, rate); | ||
31 | |||
32 | return DIV_ROUND_UP_ULL((u64)parent_rate, rate); | ||
33 | } | ||
34 | |||
35 | static int _get_val(unsigned long parent_rate, unsigned long rate) | ||
36 | { | ||
37 | return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1; | ||
38 | } | ||
39 | |||
40 | static int _valid_divider(unsigned int width, int divider) | ||
41 | { | ||
42 | int max_divider = 1 << width; | ||
43 | |||
44 | return clamp(divider, 1, max_divider); | ||
45 | } | ||
46 | |||
47 | static unsigned long audio_divider_recalc_rate(struct clk_hw *hw, | ||
48 | unsigned long parent_rate) | ||
49 | { | ||
50 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
51 | struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); | ||
52 | unsigned long divider; | ||
53 | |||
54 | divider = meson_parm_read(clk->map, &adiv->div); | ||
55 | |||
56 | return DIV_ROUND_UP_ULL((u64)parent_rate, divider); | ||
57 | } | ||
58 | |||
59 | static long audio_divider_round_rate(struct clk_hw *hw, | ||
60 | unsigned long rate, | ||
61 | unsigned long *parent_rate) | ||
62 | { | ||
63 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
64 | struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); | ||
65 | unsigned long max_prate; | ||
66 | int divider; | ||
67 | |||
68 | if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { | ||
69 | divider = _div_round(*parent_rate, rate, adiv->flags); | ||
70 | divider = _valid_divider(adiv->div.width, divider); | ||
71 | return DIV_ROUND_UP_ULL((u64)*parent_rate, divider); | ||
72 | } | ||
73 | |||
74 | /* Get the maximum parent rate */ | ||
75 | max_prate = clk_hw_round_rate(clk_hw_get_parent(hw), ULONG_MAX); | ||
76 | |||
77 | /* Get the corresponding rounded down divider */ | ||
78 | divider = max_prate / rate; | ||
79 | divider = _valid_divider(adiv->div.width, divider); | ||
80 | |||
81 | /* Get actual rate of the parent */ | ||
82 | *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), | ||
83 | divider * rate); | ||
84 | |||
85 | return DIV_ROUND_UP_ULL((u64)*parent_rate, divider); | ||
86 | } | ||
87 | |||
88 | static int audio_divider_set_rate(struct clk_hw *hw, | ||
89 | unsigned long rate, | ||
90 | unsigned long parent_rate) | ||
91 | { | ||
92 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
93 | struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); | ||
94 | int val = _get_val(parent_rate, rate); | ||
95 | |||
96 | meson_parm_write(clk->map, &adiv->div, val); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | const struct clk_ops meson_clk_audio_divider_ro_ops = { | ||
102 | .recalc_rate = audio_divider_recalc_rate, | ||
103 | .round_rate = audio_divider_round_rate, | ||
104 | }; | ||
105 | |||
106 | const struct clk_ops meson_clk_audio_divider_ops = { | ||
107 | .recalc_rate = audio_divider_recalc_rate, | ||
108 | .round_rate = audio_divider_round_rate, | ||
109 | .set_rate = audio_divider_set_rate, | ||
110 | }; | ||
diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c new file mode 100644 index 000000000000..cba43748ce3d --- /dev/null +++ b/drivers/clk/meson/clk-phase.c | |||
@@ -0,0 +1,63 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) | ||
2 | /* | ||
3 | * Copyright (c) 2018 BayLibre, SAS. | ||
4 | * Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | */ | ||
6 | |||
7 | #include <linux/clk-provider.h> | ||
8 | #include "clkc.h" | ||
9 | |||
10 | #define phase_step(_width) (360 / (1 << (_width))) | ||
11 | |||
12 | static inline struct meson_clk_phase_data * | ||
13 | meson_clk_phase_data(struct clk_regmap *clk) | ||
14 | { | ||
15 | return (struct meson_clk_phase_data *)clk->data; | ||
16 | } | ||
17 | |||
18 | int meson_clk_degrees_from_val(unsigned int val, unsigned int width) | ||
19 | { | ||
20 | return phase_step(width) * val; | ||
21 | } | ||
22 | EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val); | ||
23 | |||
24 | unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width) | ||
25 | { | ||
26 | unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width)); | ||
27 | |||
28 | /* | ||
29 | * This last calculation is here for cases when degrees is rounded | ||
30 | * to 360, in which case val == (1 << width). | ||
31 | */ | ||
32 | return val % (1 << width); | ||
33 | } | ||
34 | EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val); | ||
35 | |||
36 | static int meson_clk_phase_get_phase(struct clk_hw *hw) | ||
37 | { | ||
38 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
39 | struct meson_clk_phase_data *phase = meson_clk_phase_data(clk); | ||
40 | unsigned int val; | ||
41 | |||
42 | val = meson_parm_read(clk->map, &phase->ph); | ||
43 | |||
44 | return meson_clk_degrees_from_val(val, phase->ph.width); | ||
45 | } | ||
46 | |||
47 | static int meson_clk_phase_set_phase(struct clk_hw *hw, int degrees) | ||
48 | { | ||
49 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
50 | struct meson_clk_phase_data *phase = meson_clk_phase_data(clk); | ||
51 | unsigned int val; | ||
52 | |||
53 | val = meson_clk_degrees_to_val(degrees, phase->ph.width); | ||
54 | meson_parm_write(clk->map, &phase->ph, val); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | const struct clk_ops meson_clk_phase_ops = { | ||
60 | .get_phase = meson_clk_phase_get_phase, | ||
61 | .set_phase = meson_clk_phase_set_phase, | ||
62 | }; | ||
63 | EXPORT_SYMBOL_GPL(meson_clk_phase_ops); | ||
diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c new file mode 100644 index 000000000000..4a59936251e5 --- /dev/null +++ b/drivers/clk/meson/clk-triphase.c | |||
@@ -0,0 +1,68 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) | ||
2 | /* | ||
3 | * Copyright (c) 2018 BayLibre, SAS. | ||
4 | * Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | */ | ||
6 | |||
7 | #include <linux/clk-provider.h> | ||
8 | #include "clkc-audio.h" | ||
9 | |||
10 | /* | ||
11 | * This is a special clock for the audio controller. | ||
12 | * The phase of mst_sclk clock output can be controlled independently | ||
13 | * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2). | ||
14 | * Controlling these 3 phases as just one makes things simpler and | ||
15 | * give the same clock view to all the element on the i2s bus. | ||
16 | * If necessary, we can still control the phase in the tdm block | ||
17 | * which makes these independent control redundant. | ||
18 | */ | ||
19 | static inline struct meson_clk_triphase_data * | ||
20 | meson_clk_triphase_data(struct clk_regmap *clk) | ||
21 | { | ||
22 | return (struct meson_clk_triphase_data *)clk->data; | ||
23 | } | ||
24 | |||
25 | static void meson_clk_triphase_sync(struct clk_hw *hw) | ||
26 | { | ||
27 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
28 | struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); | ||
29 | unsigned int val; | ||
30 | |||
31 | /* Get phase 0 and sync it to phase 1 and 2 */ | ||
32 | val = meson_parm_read(clk->map, &tph->ph0); | ||
33 | meson_parm_write(clk->map, &tph->ph1, val); | ||
34 | meson_parm_write(clk->map, &tph->ph2, val); | ||
35 | } | ||
36 | |||
37 | static int meson_clk_triphase_get_phase(struct clk_hw *hw) | ||
38 | { | ||
39 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
40 | struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); | ||
41 | unsigned int val; | ||
42 | |||
43 | /* Phase are in sync, reading phase 0 is enough */ | ||
44 | val = meson_parm_read(clk->map, &tph->ph0); | ||
45 | |||
46 | return meson_clk_degrees_from_val(val, tph->ph0.width); | ||
47 | } | ||
48 | |||
49 | static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees) | ||
50 | { | ||
51 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
52 | struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk); | ||
53 | unsigned int val; | ||
54 | |||
55 | val = meson_clk_degrees_to_val(degrees, tph->ph0.width); | ||
56 | meson_parm_write(clk->map, &tph->ph0, val); | ||
57 | meson_parm_write(clk->map, &tph->ph1, val); | ||
58 | meson_parm_write(clk->map, &tph->ph2, val); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | const struct clk_ops meson_clk_triphase_ops = { | ||
64 | .init = meson_clk_triphase_sync, | ||
65 | .get_phase = meson_clk_triphase_get_phase, | ||
66 | .set_phase = meson_clk_triphase_set_phase, | ||
67 | }; | ||
68 | EXPORT_SYMBOL_GPL(meson_clk_triphase_ops); | ||
diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h new file mode 100644 index 000000000000..0a7c157ebf81 --- /dev/null +++ b/drivers/clk/meson/clkc-audio.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * Copyright (c) 2018 BayLibre, SAS. | ||
4 | * Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | */ | ||
6 | |||
7 | #ifndef __MESON_CLKC_AUDIO_H | ||
8 | #define __MESON_CLKC_AUDIO_H | ||
9 | |||
10 | #include "clkc.h" | ||
11 | |||
12 | struct meson_clk_triphase_data { | ||
13 | struct parm ph0; | ||
14 | struct parm ph1; | ||
15 | struct parm ph2; | ||
16 | }; | ||
17 | |||
18 | struct meson_sclk_div_data { | ||
19 | struct parm div; | ||
20 | struct parm hi; | ||
21 | unsigned int cached_div; | ||
22 | struct clk_duty cached_duty; | ||
23 | }; | ||
24 | |||
25 | extern const struct clk_ops meson_clk_triphase_ops; | ||
26 | extern const struct clk_ops meson_sclk_div_ops; | ||
27 | |||
28 | #endif /* __MESON_CLKC_AUDIO_H */ | ||
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 2fb084330ee9..24cec16b6038 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h | |||
@@ -91,11 +91,13 @@ struct meson_clk_mpll_data { | |||
91 | 91 | ||
92 | #define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0) | 92 | #define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0) |
93 | 93 | ||
94 | struct meson_clk_audio_div_data { | 94 | struct meson_clk_phase_data { |
95 | struct parm div; | 95 | struct parm ph; |
96 | u8 flags; | ||
97 | }; | 96 | }; |
98 | 97 | ||
98 | int meson_clk_degrees_from_val(unsigned int val, unsigned int width); | ||
99 | unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width); | ||
100 | |||
99 | #define MESON_GATE(_name, _reg, _bit) \ | 101 | #define MESON_GATE(_name, _reg, _bit) \ |
100 | struct clk_regmap _name = { \ | 102 | struct clk_regmap _name = { \ |
101 | .data = &(struct clk_regmap_gate_data){ \ | 103 | .data = &(struct clk_regmap_gate_data){ \ |
@@ -117,7 +119,6 @@ extern const struct clk_ops meson_clk_pll_ops; | |||
117 | extern const struct clk_ops meson_clk_cpu_ops; | 119 | extern const struct clk_ops meson_clk_cpu_ops; |
118 | extern const struct clk_ops meson_clk_mpll_ro_ops; | 120 | extern const struct clk_ops meson_clk_mpll_ro_ops; |
119 | extern const struct clk_ops meson_clk_mpll_ops; | 121 | extern const struct clk_ops meson_clk_mpll_ops; |
120 | extern const struct clk_ops meson_clk_audio_divider_ro_ops; | 122 | extern const struct clk_ops meson_clk_phase_ops; |
121 | extern const struct clk_ops meson_clk_audio_divider_ops; | ||
122 | 123 | ||
123 | #endif /* __CLKC_H */ | 124 | #endif /* __CLKC_H */ |
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 240658404367..86d3ae58e84c 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/clk.h> | 7 | #include <linux/clk.h> |
8 | #include <linux/clk-provider.h> | 8 | #include <linux/clk-provider.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/of_address.h> | ||
11 | #include <linux/of_device.h> | 10 | #include <linux/of_device.h> |
12 | #include <linux/mfd/syscon.h> | 11 | #include <linux/mfd/syscon.h> |
13 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
@@ -498,6 +497,7 @@ static struct clk_regmap gxbb_fclk_div2 = { | |||
498 | .ops = &clk_regmap_gate_ops, | 497 | .ops = &clk_regmap_gate_ops, |
499 | .parent_names = (const char *[]){ "fclk_div2_div" }, | 498 | .parent_names = (const char *[]){ "fclk_div2_div" }, |
500 | .num_parents = 1, | 499 | .num_parents = 1, |
500 | .flags = CLK_IS_CRITICAL, | ||
501 | }, | 501 | }, |
502 | }; | 502 | }; |
503 | 503 | ||
@@ -970,28 +970,26 @@ static struct clk_regmap gxbb_cts_amclk_sel = { | |||
970 | .mask = 0x3, | 970 | .mask = 0x3, |
971 | .shift = 9, | 971 | .shift = 9, |
972 | .table = (u32[]){ 1, 2, 3 }, | 972 | .table = (u32[]){ 1, 2, 3 }, |
973 | .flags = CLK_MUX_ROUND_CLOSEST, | ||
973 | }, | 974 | }, |
974 | .hw.init = &(struct clk_init_data){ | 975 | .hw.init = &(struct clk_init_data){ |
975 | .name = "cts_amclk_sel", | 976 | .name = "cts_amclk_sel", |
976 | .ops = &clk_regmap_mux_ops, | 977 | .ops = &clk_regmap_mux_ops, |
977 | .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, | 978 | .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, |
978 | .num_parents = 3, | 979 | .num_parents = 3, |
979 | .flags = CLK_SET_RATE_PARENT, | ||
980 | }, | 980 | }, |
981 | }; | 981 | }; |
982 | 982 | ||
983 | static struct clk_regmap gxbb_cts_amclk_div = { | 983 | static struct clk_regmap gxbb_cts_amclk_div = { |
984 | .data = &(struct meson_clk_audio_div_data){ | 984 | .data = &(struct clk_regmap_div_data) { |
985 | .div = { | 985 | .offset = HHI_AUD_CLK_CNTL, |
986 | .reg_off = HHI_AUD_CLK_CNTL, | 986 | .shift = 0, |
987 | .shift = 0, | 987 | .width = 8, |
988 | .width = 8, | ||
989 | }, | ||
990 | .flags = CLK_DIVIDER_ROUND_CLOSEST, | 988 | .flags = CLK_DIVIDER_ROUND_CLOSEST, |
991 | }, | 989 | }, |
992 | .hw.init = &(struct clk_init_data){ | 990 | .hw.init = &(struct clk_init_data){ |
993 | .name = "cts_amclk_div", | 991 | .name = "cts_amclk_div", |
994 | .ops = &meson_clk_audio_divider_ops, | 992 | .ops = &clk_regmap_divider_ops, |
995 | .parent_names = (const char *[]){ "cts_amclk_sel" }, | 993 | .parent_names = (const char *[]){ "cts_amclk_sel" }, |
996 | .num_parents = 1, | 994 | .num_parents = 1, |
997 | .flags = CLK_SET_RATE_PARENT, | 995 | .flags = CLK_SET_RATE_PARENT, |
@@ -1018,13 +1016,13 @@ static struct clk_regmap gxbb_cts_mclk_i958_sel = { | |||
1018 | .mask = 0x3, | 1016 | .mask = 0x3, |
1019 | .shift = 25, | 1017 | .shift = 25, |
1020 | .table = (u32[]){ 1, 2, 3 }, | 1018 | .table = (u32[]){ 1, 2, 3 }, |
1019 | .flags = CLK_MUX_ROUND_CLOSEST, | ||
1021 | }, | 1020 | }, |
1022 | .hw.init = &(struct clk_init_data) { | 1021 | .hw.init = &(struct clk_init_data) { |
1023 | .name = "cts_mclk_i958_sel", | 1022 | .name = "cts_mclk_i958_sel", |
1024 | .ops = &clk_regmap_mux_ops, | 1023 | .ops = &clk_regmap_mux_ops, |
1025 | .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, | 1024 | .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, |
1026 | .num_parents = 3, | 1025 | .num_parents = 3, |
1027 | .flags = CLK_SET_RATE_PARENT, | ||
1028 | }, | 1026 | }, |
1029 | }; | 1027 | }; |
1030 | 1028 | ||
@@ -1626,6 +1624,63 @@ static struct clk_regmap gxbb_vdec_hevc = { | |||
1626 | }, | 1624 | }, |
1627 | }; | 1625 | }; |
1628 | 1626 | ||
1627 | static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8, | ||
1628 | 9, 10, 11, 13, 14, }; | ||
1629 | static const char * const gen_clk_parent_names[] = { | ||
1630 | "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2", | ||
1631 | "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll", | ||
1632 | }; | ||
1633 | |||
1634 | static struct clk_regmap gxbb_gen_clk_sel = { | ||
1635 | .data = &(struct clk_regmap_mux_data){ | ||
1636 | .offset = HHI_GEN_CLK_CNTL, | ||
1637 | .mask = 0xf, | ||
1638 | .shift = 12, | ||
1639 | .table = mux_table_gen_clk, | ||
1640 | }, | ||
1641 | .hw.init = &(struct clk_init_data){ | ||
1642 | .name = "gen_clk_sel", | ||
1643 | .ops = &clk_regmap_mux_ops, | ||
1644 | /* | ||
1645 | * bits 15:12 selects from 14 possible parents: | ||
1646 | * xtal, [rtc_oscin_i], [sys_cpu_div16], [ddr_dpll_pt], | ||
1647 | * vid_pll, vid2_pll (hevc), mpll0, mpll1, mpll2, fdiv4, | ||
1648 | * fdiv3, fdiv5, [cts_msr_clk], fdiv7, gp0_pll | ||
1649 | */ | ||
1650 | .parent_names = gen_clk_parent_names, | ||
1651 | .num_parents = ARRAY_SIZE(gen_clk_parent_names), | ||
1652 | }, | ||
1653 | }; | ||
1654 | |||
1655 | static struct clk_regmap gxbb_gen_clk_div = { | ||
1656 | .data = &(struct clk_regmap_div_data){ | ||
1657 | .offset = HHI_GEN_CLK_CNTL, | ||
1658 | .shift = 0, | ||
1659 | .width = 11, | ||
1660 | }, | ||
1661 | .hw.init = &(struct clk_init_data){ | ||
1662 | .name = "gen_clk_div", | ||
1663 | .ops = &clk_regmap_divider_ops, | ||
1664 | .parent_names = (const char *[]){ "gen_clk_sel" }, | ||
1665 | .num_parents = 1, | ||
1666 | .flags = CLK_SET_RATE_PARENT, | ||
1667 | }, | ||
1668 | }; | ||
1669 | |||
1670 | static struct clk_regmap gxbb_gen_clk = { | ||
1671 | .data = &(struct clk_regmap_gate_data){ | ||
1672 | .offset = HHI_GEN_CLK_CNTL, | ||
1673 | .bit_idx = 7, | ||
1674 | }, | ||
1675 | .hw.init = &(struct clk_init_data){ | ||
1676 | .name = "gen_clk", | ||
1677 | .ops = &clk_regmap_gate_ops, | ||
1678 | .parent_names = (const char *[]){ "gen_clk_div" }, | ||
1679 | .num_parents = 1, | ||
1680 | .flags = CLK_SET_RATE_PARENT, | ||
1681 | }, | ||
1682 | }; | ||
1683 | |||
1629 | /* Everything Else (EE) domain gates */ | 1684 | /* Everything Else (EE) domain gates */ |
1630 | static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); | 1685 | static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); |
1631 | static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); | 1686 | static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); |
@@ -1875,6 +1930,9 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { | |||
1875 | [CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw, | 1930 | [CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw, |
1876 | [CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw, | 1931 | [CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw, |
1877 | [CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw, | 1932 | [CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw, |
1933 | [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, | ||
1934 | [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, | ||
1935 | [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, | ||
1878 | [NR_CLKS] = NULL, | 1936 | [NR_CLKS] = NULL, |
1879 | }, | 1937 | }, |
1880 | .num = NR_CLKS, | 1938 | .num = NR_CLKS, |
@@ -2037,6 +2095,9 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { | |||
2037 | [CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw, | 2095 | [CLKID_VDEC_HEVC_SEL] = &gxbb_vdec_hevc_sel.hw, |
2038 | [CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw, | 2096 | [CLKID_VDEC_HEVC_DIV] = &gxbb_vdec_hevc_div.hw, |
2039 | [CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw, | 2097 | [CLKID_VDEC_HEVC] = &gxbb_vdec_hevc.hw, |
2098 | [CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw, | ||
2099 | [CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw, | ||
2100 | [CLKID_GEN_CLK] = &gxbb_gen_clk.hw, | ||
2040 | [NR_CLKS] = NULL, | 2101 | [NR_CLKS] = NULL, |
2041 | }, | 2102 | }, |
2042 | .num = NR_CLKS, | 2103 | .num = NR_CLKS, |
@@ -2201,6 +2262,9 @@ static struct clk_regmap *const gx_clk_regmaps[] = { | |||
2201 | &gxbb_vdec_hevc_sel, | 2262 | &gxbb_vdec_hevc_sel, |
2202 | &gxbb_vdec_hevc_div, | 2263 | &gxbb_vdec_hevc_div, |
2203 | &gxbb_vdec_hevc, | 2264 | &gxbb_vdec_hevc, |
2265 | &gxbb_gen_clk_sel, | ||
2266 | &gxbb_gen_clk_div, | ||
2267 | &gxbb_gen_clk, | ||
2204 | }; | 2268 | }; |
2205 | 2269 | ||
2206 | struct clkc_data { | 2270 | struct clkc_data { |
@@ -2227,17 +2291,9 @@ static const struct of_device_id clkc_match_table[] = { | |||
2227 | {}, | 2291 | {}, |
2228 | }; | 2292 | }; |
2229 | 2293 | ||
2230 | static const struct regmap_config clkc_regmap_config = { | ||
2231 | .reg_bits = 32, | ||
2232 | .val_bits = 32, | ||
2233 | .reg_stride = 4, | ||
2234 | }; | ||
2235 | |||
2236 | static int gxbb_clkc_probe(struct platform_device *pdev) | 2294 | static int gxbb_clkc_probe(struct platform_device *pdev) |
2237 | { | 2295 | { |
2238 | const struct clkc_data *clkc_data; | 2296 | const struct clkc_data *clkc_data; |
2239 | struct resource *res; | ||
2240 | void __iomem *clk_base; | ||
2241 | struct regmap *map; | 2297 | struct regmap *map; |
2242 | int ret, i; | 2298 | int ret, i; |
2243 | struct device *dev = &pdev->dev; | 2299 | struct device *dev = &pdev->dev; |
@@ -2249,31 +2305,8 @@ static int gxbb_clkc_probe(struct platform_device *pdev) | |||
2249 | /* Get the hhi system controller node if available */ | 2305 | /* Get the hhi system controller node if available */ |
2250 | map = syscon_node_to_regmap(of_get_parent(dev->of_node)); | 2306 | map = syscon_node_to_regmap(of_get_parent(dev->of_node)); |
2251 | if (IS_ERR(map)) { | 2307 | if (IS_ERR(map)) { |
2252 | dev_err(dev, | 2308 | dev_err(dev, "failed to get HHI regmap\n"); |
2253 | "failed to get HHI regmap - Trying obsolete regs\n"); | 2309 | return PTR_ERR(map); |
2254 | |||
2255 | /* | ||
2256 | * FIXME: HHI registers should be accessed through | ||
2257 | * the appropriate system controller. This is required because | ||
2258 | * there is more than just clocks in this register space | ||
2259 | * | ||
2260 | * This fallback method is only provided temporarily until | ||
2261 | * all the platform DTs are properly using the syscon node | ||
2262 | */ | ||
2263 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
2264 | if (!res) | ||
2265 | return -EINVAL; | ||
2266 | |||
2267 | clk_base = devm_ioremap(dev, res->start, resource_size(res)); | ||
2268 | if (!clk_base) { | ||
2269 | dev_err(dev, "Unable to map clk base\n"); | ||
2270 | return -ENXIO; | ||
2271 | } | ||
2272 | |||
2273 | map = devm_regmap_init_mmio(dev, clk_base, | ||
2274 | &clkc_regmap_config); | ||
2275 | if (IS_ERR(map)) | ||
2276 | return PTR_ERR(map); | ||
2277 | } | 2310 | } |
2278 | 2311 | ||
2279 | /* Populate regmap for the common regmap backed clocks */ | 2312 | /* Populate regmap for the common regmap backed clocks */ |
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index ec1a812bf1fd..20dfb1daf5b8 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h | |||
@@ -66,7 +66,6 @@ | |||
66 | #define HHI_USB_CLK_CNTL 0x220 /* 0x88 offset in data sheet */ | 66 | #define HHI_USB_CLK_CNTL 0x220 /* 0x88 offset in data sheet */ |
67 | #define HHI_32K_CLK_CNTL 0x224 /* 0x89 offset in data sheet */ | 67 | #define HHI_32K_CLK_CNTL 0x224 /* 0x89 offset in data sheet */ |
68 | #define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */ | 68 | #define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */ |
69 | #define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */ | ||
70 | 69 | ||
71 | #define HHI_PCM_CLK_CNTL 0x258 /* 0x96 offset in data sheet */ | 70 | #define HHI_PCM_CLK_CNTL 0x258 /* 0x96 offset in data sheet */ |
72 | #define HHI_NAND_CLK_CNTL 0x25C /* 0x97 offset in data sheet */ | 71 | #define HHI_NAND_CLK_CNTL 0x25C /* 0x97 offset in data sheet */ |
@@ -158,8 +157,10 @@ | |||
158 | #define CLKID_VDEC_1_DIV 152 | 157 | #define CLKID_VDEC_1_DIV 152 |
159 | #define CLKID_VDEC_HEVC_SEL 154 | 158 | #define CLKID_VDEC_HEVC_SEL 154 |
160 | #define CLKID_VDEC_HEVC_DIV 155 | 159 | #define CLKID_VDEC_HEVC_DIV 155 |
160 | #define CLKID_GEN_CLK_SEL 157 | ||
161 | #define CLKID_GEN_CLK_DIV 158 | ||
161 | 162 | ||
162 | #define NR_CLKS 157 | 163 | #define NR_CLKS 160 |
163 | 164 | ||
164 | /* include the CLKIDs that have been made part of the DT binding */ | 165 | /* include the CLKIDs that have been made part of the DT binding */ |
165 | #include <dt-bindings/clock/gxbb-clkc.h> | 166 | #include <dt-bindings/clock/gxbb-clkc.h> |
diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c new file mode 100644 index 000000000000..bc64019b8eeb --- /dev/null +++ b/drivers/clk/meson/sclk-div.c | |||
@@ -0,0 +1,243 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) | ||
2 | /* | ||
3 | * Copyright (c) 2018 BayLibre, SAS. | ||
4 | * Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | * | ||
6 | * Sample clock generator divider: | ||
7 | * This HW divider gates with value 0 but is otherwise a zero based divider: | ||
8 | * | ||
9 | * val >= 1 | ||
10 | * divider = val + 1 | ||
11 | * | ||
12 | * The duty cycle may also be set for the LR clock variant. The duty cycle | ||
13 | * ratio is: | ||
14 | * | ||
15 | * hi = [0 - val] | ||
16 | * duty_cycle = (1 + hi) / (1 + val) | ||
17 | */ | ||
18 | |||
19 | #include "clkc-audio.h" | ||
20 | |||
21 | static inline struct meson_sclk_div_data * | ||
22 | meson_sclk_div_data(struct clk_regmap *clk) | ||
23 | { | ||
24 | return (struct meson_sclk_div_data *)clk->data; | ||
25 | } | ||
26 | |||
27 | static int sclk_div_maxval(struct meson_sclk_div_data *sclk) | ||
28 | { | ||
29 | return (1 << sclk->div.width) - 1; | ||
30 | } | ||
31 | |||
32 | static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk) | ||
33 | { | ||
34 | return sclk_div_maxval(sclk) + 1; | ||
35 | } | ||
36 | |||
37 | static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate, | ||
38 | unsigned long prate, int maxdiv) | ||
39 | { | ||
40 | int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate); | ||
41 | |||
42 | return clamp(div, 2, maxdiv); | ||
43 | } | ||
44 | |||
45 | static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate, | ||
46 | unsigned long *prate, | ||
47 | struct meson_sclk_div_data *sclk) | ||
48 | { | ||
49 | struct clk_hw *parent = clk_hw_get_parent(hw); | ||
50 | int bestdiv = 0, i; | ||
51 | unsigned long maxdiv, now, parent_now; | ||
52 | unsigned long best = 0, best_parent = 0; | ||
53 | |||
54 | if (!rate) | ||
55 | rate = 1; | ||
56 | |||
57 | maxdiv = sclk_div_maxdiv(sclk); | ||
58 | |||
59 | if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) | ||
60 | return sclk_div_getdiv(hw, rate, *prate, maxdiv); | ||
61 | |||
62 | /* | ||
63 | * The maximum divider we can use without overflowing | ||
64 | * unsigned long in rate * i below | ||
65 | */ | ||
66 | maxdiv = min(ULONG_MAX / rate, maxdiv); | ||
67 | |||
68 | for (i = 2; i <= maxdiv; i++) { | ||
69 | /* | ||
70 | * It's the most ideal case if the requested rate can be | ||
71 | * divided from parent clock without needing to change | ||
72 | * parent rate, so return the divider immediately. | ||
73 | */ | ||
74 | if (rate * i == *prate) | ||
75 | return i; | ||
76 | |||
77 | parent_now = clk_hw_round_rate(parent, rate * i); | ||
78 | now = DIV_ROUND_UP_ULL((u64)parent_now, i); | ||
79 | |||
80 | if (abs(rate - now) < abs(rate - best)) { | ||
81 | bestdiv = i; | ||
82 | best = now; | ||
83 | best_parent = parent_now; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | if (!bestdiv) | ||
88 | bestdiv = sclk_div_maxdiv(sclk); | ||
89 | else | ||
90 | *prate = best_parent; | ||
91 | |||
92 | return bestdiv; | ||
93 | } | ||
94 | |||
95 | static long sclk_div_round_rate(struct clk_hw *hw, unsigned long rate, | ||
96 | unsigned long *prate) | ||
97 | { | ||
98 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
99 | struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); | ||
100 | int div; | ||
101 | |||
102 | div = sclk_div_bestdiv(hw, rate, prate, sclk); | ||
103 | |||
104 | return DIV_ROUND_UP_ULL((u64)*prate, div); | ||
105 | } | ||
106 | |||
107 | static void sclk_apply_ratio(struct clk_regmap *clk, | ||
108 | struct meson_sclk_div_data *sclk) | ||
109 | { | ||
110 | unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div * | ||
111 | sclk->cached_duty.num, | ||
112 | sclk->cached_duty.den); | ||
113 | |||
114 | if (hi) | ||
115 | hi -= 1; | ||
116 | |||
117 | meson_parm_write(clk->map, &sclk->hi, hi); | ||
118 | } | ||
119 | |||
120 | static int sclk_div_set_duty_cycle(struct clk_hw *hw, | ||
121 | struct clk_duty *duty) | ||
122 | { | ||
123 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
124 | struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); | ||
125 | |||
126 | if (MESON_PARM_APPLICABLE(&sclk->hi)) { | ||
127 | memcpy(&sclk->cached_duty, duty, sizeof(*duty)); | ||
128 | sclk_apply_ratio(clk, sclk); | ||
129 | } | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int sclk_div_get_duty_cycle(struct clk_hw *hw, | ||
135 | struct clk_duty *duty) | ||
136 | { | ||
137 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
138 | struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); | ||
139 | int hi; | ||
140 | |||
141 | if (!MESON_PARM_APPLICABLE(&sclk->hi)) { | ||
142 | duty->num = 1; | ||
143 | duty->den = 2; | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | hi = meson_parm_read(clk->map, &sclk->hi); | ||
148 | duty->num = hi + 1; | ||
149 | duty->den = sclk->cached_div; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static void sclk_apply_divider(struct clk_regmap *clk, | ||
154 | struct meson_sclk_div_data *sclk) | ||
155 | { | ||
156 | if (MESON_PARM_APPLICABLE(&sclk->hi)) | ||
157 | sclk_apply_ratio(clk, sclk); | ||
158 | |||
159 | meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1); | ||
160 | } | ||
161 | |||
162 | static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate, | ||
163 | unsigned long prate) | ||
164 | { | ||
165 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
166 | struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); | ||
167 | unsigned long maxdiv = sclk_div_maxdiv(sclk); | ||
168 | |||
169 | sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv); | ||
170 | |||
171 | if (clk_hw_is_enabled(hw)) | ||
172 | sclk_apply_divider(clk, sclk); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static unsigned long sclk_div_recalc_rate(struct clk_hw *hw, | ||
178 | unsigned long prate) | ||
179 | { | ||
180 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
181 | struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); | ||
182 | |||
183 | return DIV_ROUND_UP_ULL((u64)prate, sclk->cached_div); | ||
184 | } | ||
185 | |||
186 | static int sclk_div_enable(struct clk_hw *hw) | ||
187 | { | ||
188 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
189 | struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); | ||
190 | |||
191 | sclk_apply_divider(clk, sclk); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static void sclk_div_disable(struct clk_hw *hw) | ||
197 | { | ||
198 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
199 | struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); | ||
200 | |||
201 | meson_parm_write(clk->map, &sclk->div, 0); | ||
202 | } | ||
203 | |||
204 | static int sclk_div_is_enabled(struct clk_hw *hw) | ||
205 | { | ||
206 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
207 | struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); | ||
208 | |||
209 | if (meson_parm_read(clk->map, &sclk->div)) | ||
210 | return 1; | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static void sclk_div_init(struct clk_hw *hw) | ||
216 | { | ||
217 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
218 | struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk); | ||
219 | unsigned int val; | ||
220 | |||
221 | val = meson_parm_read(clk->map, &sclk->div); | ||
222 | |||
223 | /* if the divider is initially disabled, assume max */ | ||
224 | if (!val) | ||
225 | sclk->cached_div = sclk_div_maxdiv(sclk); | ||
226 | else | ||
227 | sclk->cached_div = val + 1; | ||
228 | |||
229 | sclk_div_get_duty_cycle(hw, &sclk->cached_duty); | ||
230 | } | ||
231 | |||
232 | const struct clk_ops meson_sclk_div_ops = { | ||
233 | .recalc_rate = sclk_div_recalc_rate, | ||
234 | .round_rate = sclk_div_round_rate, | ||
235 | .set_rate = sclk_div_set_rate, | ||
236 | .enable = sclk_div_enable, | ||
237 | .disable = sclk_div_disable, | ||
238 | .is_enabled = sclk_div_is_enabled, | ||
239 | .get_duty_cycle = sclk_div_get_duty_cycle, | ||
240 | .set_duty_cycle = sclk_div_set_duty_cycle, | ||
241 | .init = sclk_div_init, | ||
242 | }; | ||
243 | EXPORT_SYMBOL_GPL(meson_sclk_div_ops); | ||
diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h new file mode 100644 index 000000000000..fd9c362099d9 --- /dev/null +++ b/include/dt-bindings/clock/axg-audio-clkc.h | |||
@@ -0,0 +1,94 @@ | |||
1 | /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ | ||
2 | /* | ||
3 | * Copyright (c) 2018 Baylibre SAS. | ||
4 | * Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | */ | ||
6 | |||
7 | #ifndef __AXG_AUDIO_CLKC_BINDINGS_H | ||
8 | #define __AXG_AUDIO_CLKC_BINDINGS_H | ||
9 | |||
10 | #define AUD_CLKID_SLV_SCLK0 9 | ||
11 | #define AUD_CLKID_SLV_SCLK1 10 | ||
12 | #define AUD_CLKID_SLV_SCLK2 11 | ||
13 | #define AUD_CLKID_SLV_SCLK3 12 | ||
14 | #define AUD_CLKID_SLV_SCLK4 13 | ||
15 | #define AUD_CLKID_SLV_SCLK5 14 | ||
16 | #define AUD_CLKID_SLV_SCLK6 15 | ||
17 | #define AUD_CLKID_SLV_SCLK7 16 | ||
18 | #define AUD_CLKID_SLV_SCLK8 17 | ||
19 | #define AUD_CLKID_SLV_SCLK9 18 | ||
20 | #define AUD_CLKID_SLV_LRCLK0 19 | ||
21 | #define AUD_CLKID_SLV_LRCLK1 20 | ||
22 | #define AUD_CLKID_SLV_LRCLK2 21 | ||
23 | #define AUD_CLKID_SLV_LRCLK3 22 | ||
24 | #define AUD_CLKID_SLV_LRCLK4 23 | ||
25 | #define AUD_CLKID_SLV_LRCLK5 24 | ||
26 | #define AUD_CLKID_SLV_LRCLK6 25 | ||
27 | #define AUD_CLKID_SLV_LRCLK7 26 | ||
28 | #define AUD_CLKID_SLV_LRCLK8 27 | ||
29 | #define AUD_CLKID_SLV_LRCLK9 28 | ||
30 | #define AUD_CLKID_DDR_ARB 29 | ||
31 | #define AUD_CLKID_PDM 30 | ||
32 | #define AUD_CLKID_TDMIN_A 31 | ||
33 | #define AUD_CLKID_TDMIN_B 32 | ||
34 | #define AUD_CLKID_TDMIN_C 33 | ||
35 | #define AUD_CLKID_TDMIN_LB 34 | ||
36 | #define AUD_CLKID_TDMOUT_A 35 | ||
37 | #define AUD_CLKID_TDMOUT_B 36 | ||
38 | #define AUD_CLKID_TDMOUT_C 37 | ||
39 | #define AUD_CLKID_FRDDR_A 38 | ||
40 | #define AUD_CLKID_FRDDR_B 39 | ||
41 | #define AUD_CLKID_FRDDR_C 40 | ||
42 | #define AUD_CLKID_TODDR_A 41 | ||
43 | #define AUD_CLKID_TODDR_B 42 | ||
44 | #define AUD_CLKID_TODDR_C 43 | ||
45 | #define AUD_CLKID_LOOPBACK 44 | ||
46 | #define AUD_CLKID_SPDIFIN 45 | ||
47 | #define AUD_CLKID_SPDIFOUT 46 | ||
48 | #define AUD_CLKID_RESAMPLE 47 | ||
49 | #define AUD_CLKID_POWER_DETECT 48 | ||
50 | #define AUD_CLKID_MST_A_MCLK 49 | ||
51 | #define AUD_CLKID_MST_B_MCLK 50 | ||
52 | #define AUD_CLKID_MST_C_MCLK 51 | ||
53 | #define AUD_CLKID_MST_D_MCLK 52 | ||
54 | #define AUD_CLKID_MST_E_MCLK 53 | ||
55 | #define AUD_CLKID_MST_F_MCLK 54 | ||
56 | #define AUD_CLKID_SPDIFOUT_CLK 55 | ||
57 | #define AUD_CLKID_SPDIFIN_CLK 56 | ||
58 | #define AUD_CLKID_PDM_DCLK 57 | ||
59 | #define AUD_CLKID_PDM_SYSCLK 58 | ||
60 | #define AUD_CLKID_MST_A_SCLK 79 | ||
61 | #define AUD_CLKID_MST_B_SCLK 80 | ||
62 | #define AUD_CLKID_MST_C_SCLK 81 | ||
63 | #define AUD_CLKID_MST_D_SCLK 82 | ||
64 | #define AUD_CLKID_MST_E_SCLK 83 | ||
65 | #define AUD_CLKID_MST_F_SCLK 84 | ||
66 | #define AUD_CLKID_MST_A_LRCLK 86 | ||
67 | #define AUD_CLKID_MST_B_LRCLK 87 | ||
68 | #define AUD_CLKID_MST_C_LRCLK 88 | ||
69 | #define AUD_CLKID_MST_D_LRCLK 89 | ||
70 | #define AUD_CLKID_MST_E_LRCLK 90 | ||
71 | #define AUD_CLKID_MST_F_LRCLK 91 | ||
72 | #define AUD_CLKID_TDMIN_A_SCLK_SEL 116 | ||
73 | #define AUD_CLKID_TDMIN_B_SCLK_SEL 117 | ||
74 | #define AUD_CLKID_TDMIN_C_SCLK_SEL 118 | ||
75 | #define AUD_CLKID_TDMIN_LB_SCLK_SEL 119 | ||
76 | #define AUD_CLKID_TDMOUT_A_SCLK_SEL 120 | ||
77 | #define AUD_CLKID_TDMOUT_B_SCLK_SEL 121 | ||
78 | #define AUD_CLKID_TDMOUT_C_SCLK_SEL 122 | ||
79 | #define AUD_CLKID_TDMIN_A_SCLK 123 | ||
80 | #define AUD_CLKID_TDMIN_B_SCLK 124 | ||
81 | #define AUD_CLKID_TDMIN_C_SCLK 125 | ||
82 | #define AUD_CLKID_TDMIN_LB_SCLK 126 | ||
83 | #define AUD_CLKID_TDMOUT_A_SCLK 127 | ||
84 | #define AUD_CLKID_TDMOUT_B_SCLK 128 | ||
85 | #define AUD_CLKID_TDMOUT_C_SCLK 129 | ||
86 | #define AUD_CLKID_TDMIN_A_LRCLK 130 | ||
87 | #define AUD_CLKID_TDMIN_B_LRCLK 131 | ||
88 | #define AUD_CLKID_TDMIN_C_LRCLK 132 | ||
89 | #define AUD_CLKID_TDMIN_LB_LRCLK 133 | ||
90 | #define AUD_CLKID_TDMOUT_A_LRCLK 134 | ||
91 | #define AUD_CLKID_TDMOUT_B_LRCLK 135 | ||
92 | #define AUD_CLKID_TDMOUT_C_LRCLK 136 | ||
93 | |||
94 | #endif /* __AXG_AUDIO_CLKC_BINDINGS_H */ | ||
diff --git a/include/dt-bindings/clock/axg-clkc.h b/include/dt-bindings/clock/axg-clkc.h index 555937a25504..fd1f938c38d1 100644 --- a/include/dt-bindings/clock/axg-clkc.h +++ b/include/dt-bindings/clock/axg-clkc.h | |||
@@ -68,5 +68,9 @@ | |||
68 | #define CLKID_SD_EMMC_B_CLK0 59 | 68 | #define CLKID_SD_EMMC_B_CLK0 59 |
69 | #define CLKID_SD_EMMC_C_CLK0 60 | 69 | #define CLKID_SD_EMMC_C_CLK0 60 |
70 | #define CLKID_HIFI_PLL 69 | 70 | #define CLKID_HIFI_PLL 69 |
71 | #define CLKID_PCIE_CML_EN0 79 | ||
72 | #define CLKID_PCIE_CML_EN1 80 | ||
73 | #define CLKID_MIPI_ENABLE 81 | ||
74 | #define CLKID_GEN_CLK 84 | ||
71 | 75 | ||
72 | #endif /* __AXG_CLKC_H */ | 76 | #endif /* __AXG_CLKC_H */ |
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h index 7a892be90549..3979d48c025f 100644 --- a/include/dt-bindings/clock/gxbb-clkc.h +++ b/include/dt-bindings/clock/gxbb-clkc.h | |||
@@ -127,5 +127,6 @@ | |||
127 | #define CLKID_VAPB 140 | 127 | #define CLKID_VAPB 140 |
128 | #define CLKID_VDEC_1 153 | 128 | #define CLKID_VDEC_1 153 |
129 | #define CLKID_VDEC_HEVC 156 | 129 | #define CLKID_VDEC_HEVC 156 |
130 | #define CLKID_GEN_CLK 159 | ||
130 | 131 | ||
131 | #endif /* __GXBB_CLKC_H */ | 132 | #endif /* __GXBB_CLKC_H */ |
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index b7cfa037e593..08b1aa70a38d 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h | |||
@@ -38,6 +38,8 @@ | |||
38 | #define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ | 38 | #define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ |
39 | /* parents need enable during gate/ungate, set rate and re-parent */ | 39 | /* parents need enable during gate/ungate, set rate and re-parent */ |
40 | #define CLK_OPS_PARENT_ENABLE BIT(12) | 40 | #define CLK_OPS_PARENT_ENABLE BIT(12) |
41 | /* duty cycle call may be forwarded to the parent clock */ | ||
42 | #define CLK_DUTY_CYCLE_PARENT BIT(13) | ||
41 | 43 | ||
42 | struct clk; | 44 | struct clk; |
43 | struct clk_hw; | 45 | struct clk_hw; |
@@ -67,6 +69,17 @@ struct clk_rate_request { | |||
67 | }; | 69 | }; |
68 | 70 | ||
69 | /** | 71 | /** |
72 | * struct clk_duty - Struture encoding the duty cycle ratio of a clock | ||
73 | * | ||
74 | * @num: Numerator of the duty cycle ratio | ||
75 | * @den: Denominator of the duty cycle ratio | ||
76 | */ | ||
77 | struct clk_duty { | ||
78 | unsigned int num; | ||
79 | unsigned int den; | ||
80 | }; | ||
81 | |||
82 | /** | ||
70 | * struct clk_ops - Callback operations for hardware clocks; these are to | 83 | * struct clk_ops - Callback operations for hardware clocks; these are to |
71 | * be provided by the clock implementation, and will be called by drivers | 84 | * be provided by the clock implementation, and will be called by drivers |
72 | * through the clk_* api. | 85 | * through the clk_* api. |
@@ -169,6 +182,15 @@ struct clk_rate_request { | |||
169 | * by the second argument. Valid values for degrees are | 182 | * by the second argument. Valid values for degrees are |
170 | * 0-359. Return 0 on success, otherwise -EERROR. | 183 | * 0-359. Return 0 on success, otherwise -EERROR. |
171 | * | 184 | * |
185 | * @get_duty_cycle: Queries the hardware to get the current duty cycle ratio | ||
186 | * of a clock. Returned values denominator cannot be 0 and must be | ||
187 | * superior or equal to the numerator. | ||
188 | * | ||
189 | * @set_duty_cycle: Apply the duty cycle ratio to this clock signal specified by | ||
190 | * the numerator (2nd argurment) and denominator (3rd argument). | ||
191 | * Argument must be a valid ratio (denominator > 0 | ||
192 | * and >= numerator) Return 0 on success, otherwise -EERROR. | ||
193 | * | ||
172 | * @init: Perform platform-specific initialization magic. | 194 | * @init: Perform platform-specific initialization magic. |
173 | * This is not not used by any of the basic clock types. | 195 | * This is not not used by any of the basic clock types. |
174 | * Please consider other ways of solving initialization problems | 196 | * Please consider other ways of solving initialization problems |
@@ -218,6 +240,10 @@ struct clk_ops { | |||
218 | unsigned long parent_accuracy); | 240 | unsigned long parent_accuracy); |
219 | int (*get_phase)(struct clk_hw *hw); | 241 | int (*get_phase)(struct clk_hw *hw); |
220 | int (*set_phase)(struct clk_hw *hw, int degrees); | 242 | int (*set_phase)(struct clk_hw *hw, int degrees); |
243 | int (*get_duty_cycle)(struct clk_hw *hw, | ||
244 | struct clk_duty *duty); | ||
245 | int (*set_duty_cycle)(struct clk_hw *hw, | ||
246 | struct clk_duty *duty); | ||
221 | void (*init)(struct clk_hw *hw); | 247 | void (*init)(struct clk_hw *hw); |
222 | void (*debug_init)(struct clk_hw *hw, struct dentry *dentry); | 248 | void (*debug_init)(struct clk_hw *hw, struct dentry *dentry); |
223 | }; | 249 | }; |
diff --git a/include/linux/clk.h b/include/linux/clk.h index 0dbd0885b2c2..4f750c481b82 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h | |||
@@ -142,6 +142,27 @@ int clk_set_phase(struct clk *clk, int degrees); | |||
142 | int clk_get_phase(struct clk *clk); | 142 | int clk_get_phase(struct clk *clk); |
143 | 143 | ||
144 | /** | 144 | /** |
145 | * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal | ||
146 | * @clk: clock signal source | ||
147 | * @num: numerator of the duty cycle ratio to be applied | ||
148 | * @den: denominator of the duty cycle ratio to be applied | ||
149 | * | ||
150 | * Adjust the duty cycle of a clock signal by the specified ratio. Returns 0 on | ||
151 | * success, -EERROR otherwise. | ||
152 | */ | ||
153 | int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den); | ||
154 | |||
155 | /** | ||
156 | * clk_get_duty_cycle - return the duty cycle ratio of a clock signal | ||
157 | * @clk: clock signal source | ||
158 | * @scale: scaling factor to be applied to represent the ratio as an integer | ||
159 | * | ||
160 | * Returns the duty cycle ratio multiplied by the scale provided, otherwise | ||
161 | * returns -EERROR. | ||
162 | */ | ||
163 | int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale); | ||
164 | |||
165 | /** | ||
145 | * clk_is_match - check if two clk's point to the same hardware clock | 166 | * clk_is_match - check if two clk's point to the same hardware clock |
146 | * @p: clk compared against q | 167 | * @p: clk compared against q |
147 | * @q: clk compared against p | 168 | * @q: clk compared against p |
@@ -183,6 +204,18 @@ static inline long clk_get_phase(struct clk *clk) | |||
183 | return -ENOTSUPP; | 204 | return -ENOTSUPP; |
184 | } | 205 | } |
185 | 206 | ||
207 | static inline int clk_set_duty_cycle(struct clk *clk, unsigned int num, | ||
208 | unsigned int den) | ||
209 | { | ||
210 | return -ENOTSUPP; | ||
211 | } | ||
212 | |||
213 | static inline unsigned int clk_get_scaled_duty_cycle(struct clk *clk, | ||
214 | unsigned int scale) | ||
215 | { | ||
216 | return 0; | ||
217 | } | ||
218 | |||
186 | static inline bool clk_is_match(const struct clk *p, const struct clk *q) | 219 | static inline bool clk_is_match(const struct clk *p, const struct clk *q) |
187 | { | 220 | { |
188 | return p == q; | 221 | return p == q; |
diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h index 2cd449328aee..9004ffff7f32 100644 --- a/include/trace/events/clk.h +++ b/include/trace/events/clk.h | |||
@@ -192,6 +192,42 @@ DEFINE_EVENT(clk_phase, clk_set_phase_complete, | |||
192 | TP_ARGS(core, phase) | 192 | TP_ARGS(core, phase) |
193 | ); | 193 | ); |
194 | 194 | ||
195 | DECLARE_EVENT_CLASS(clk_duty_cycle, | ||
196 | |||
197 | TP_PROTO(struct clk_core *core, struct clk_duty *duty), | ||
198 | |||
199 | TP_ARGS(core, duty), | ||
200 | |||
201 | TP_STRUCT__entry( | ||
202 | __string( name, core->name ) | ||
203 | __field( unsigned int, num ) | ||
204 | __field( unsigned int, den ) | ||
205 | ), | ||
206 | |||
207 | TP_fast_assign( | ||
208 | __assign_str(name, core->name); | ||
209 | __entry->num = duty->num; | ||
210 | __entry->den = duty->den; | ||
211 | ), | ||
212 | |||
213 | TP_printk("%s %u/%u", __get_str(name), (unsigned int)__entry->num, | ||
214 | (unsigned int)__entry->den) | ||
215 | ); | ||
216 | |||
217 | DEFINE_EVENT(clk_duty_cycle, clk_set_duty_cycle, | ||
218 | |||
219 | TP_PROTO(struct clk_core *core, struct clk_duty *duty), | ||
220 | |||
221 | TP_ARGS(core, duty) | ||
222 | ); | ||
223 | |||
224 | DEFINE_EVENT(clk_duty_cycle, clk_set_duty_cycle_complete, | ||
225 | |||
226 | TP_PROTO(struct clk_core *core, struct clk_duty *duty), | ||
227 | |||
228 | TP_ARGS(core, duty) | ||
229 | ); | ||
230 | |||
195 | #endif /* _TRACE_CLK_H */ | 231 | #endif /* _TRACE_CLK_H */ |
196 | 232 | ||
197 | /* This part must be outside protection */ | 233 | /* This part must be outside protection */ |