aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@kernel.org>2018-07-09 12:47:55 -0400
committerStephen Boyd <sboyd@kernel.org>2018-07-09 12:47:55 -0400
commit166f3a8ad67738061d6deada4d71019240bdbdaf (patch)
tree6a95385f018bca6963984ef1252fc3edc7f32ade
parentce397d215ccd07b8ae3f71db689aedb85d56ab40 (diff)
parent7df533a7e3d2216e860ecf147ae8cee49bf133e9 (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.txt56
-rw-r--r--drivers/clk/clk.c199
-rw-r--r--drivers/clk/meson/Kconfig28
-rw-r--r--drivers/clk/meson/Makefile4
-rw-r--r--drivers/clk/meson/axg-audio.c845
-rw-r--r--drivers/clk/meson/axg-audio.h127
-rw-r--r--drivers/clk/meson/axg.c244
-rw-r--r--drivers/clk/meson/axg.h8
-rw-r--r--drivers/clk/meson/clk-audio-divider.c110
-rw-r--r--drivers/clk/meson/clk-phase.c63
-rw-r--r--drivers/clk/meson/clk-triphase.c68
-rw-r--r--drivers/clk/meson/clkc-audio.h28
-rw-r--r--drivers/clk/meson/clkc.h11
-rw-r--r--drivers/clk/meson/gxbb.c119
-rw-r--r--drivers/clk/meson/gxbb.h5
-rw-r--r--drivers/clk/meson/sclk-div.c243
-rw-r--r--include/dt-bindings/clock/axg-audio-clkc.h94
-rw-r--r--include/dt-bindings/clock/axg-clkc.h4
-rw-r--r--include/dt-bindings/clock/gxbb-clkc.h1
-rw-r--r--include/linux/clk-provider.h26
-rw-r--r--include/linux/clk.h33
-rw-r--r--include/trace/events/clk.h36
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
3The Amlogic AXG audio clock controller generates and supplies clock to the
4other elements of the audio subsystem, such as fifos, i2s, spdif and pdm
5devices.
6
7Required 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
25Each clock is assigned an identifier and client nodes can use this identifier
26to specify the clock which they consume. All available clocks are defined as
27preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be
28used in device tree sources.
29
30Example:
31
32clkc_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}
2403EXPORT_SYMBOL_GPL(clk_get_phase); 2404EXPORT_SYMBOL_GPL(clk_get_phase);
2404 2405
2406static 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
2413static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core);
2414
2415static 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
2435reset:
2436 clk_core_reset_duty_cycle_nolock(core);
2437 return ret;
2438}
2439
2440static 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
2455static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core,
2456 struct clk_duty *duty);
2457
2458static 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
2482static 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 */
2507int 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}
2536EXPORT_SYMBOL_GPL(clk_set_duty_cycle);
2537
2538static 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 */
2563int 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}
2570EXPORT_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
2466static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, 2634static 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
2516static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level) 2686static 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}
2611DEFINE_SHOW_ATTRIBUTE(possible_parents); 2782DEFINE_SHOW_ATTRIBUTE(possible_parents);
2612 2783
2784static 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}
2793DEFINE_SHOW_ATTRIBUTE(clk_duty_cycle);
2794
2613static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) 2795static 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 @@
1config COMMON_CLK_AMLOGIC 1config 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
6config COMMON_CLK_AMLOGIC_AUDIO
7 bool
8 depends on ARCH_MESON || COMPILE_TEST
9 select COMMON_CLK_AMLOGIC
5 10
6config COMMON_CLK_MESON_AO 11config 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
12config COMMON_CLK_REGMAP_MESON 18config COMMON_CLK_REGMAP_MESON
13 bool 19 bool
@@ -15,9 +21,8 @@ config COMMON_CLK_REGMAP_MESON
15 21
16config COMMON_CLK_MESON8B 22config 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
26config COMMON_CLK_GXBB 31config 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
37config COMMON_CLK_AXG 40config 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
49config 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
5obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o 5obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o
6obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o
6obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o 7obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
7obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o 8obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
8obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o 9obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
9obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o 10obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
11obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
10obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o 12obj-$(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) \
25struct 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) \
40struct 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) \
57struct 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 */
77static AXG_PCLK_GATE(ddr_arb, 0);
78static AXG_PCLK_GATE(pdm, 1);
79static AXG_PCLK_GATE(tdmin_a, 2);
80static AXG_PCLK_GATE(tdmin_b, 3);
81static AXG_PCLK_GATE(tdmin_c, 4);
82static AXG_PCLK_GATE(tdmin_lb, 5);
83static AXG_PCLK_GATE(tdmout_a, 6);
84static AXG_PCLK_GATE(tdmout_b, 7);
85static AXG_PCLK_GATE(tdmout_c, 8);
86static AXG_PCLK_GATE(frddr_a, 9);
87static AXG_PCLK_GATE(frddr_b, 10);
88static AXG_PCLK_GATE(frddr_c, 11);
89static AXG_PCLK_GATE(toddr_a, 12);
90static AXG_PCLK_GATE(toddr_b, 13);
91static AXG_PCLK_GATE(toddr_c, 14);
92static AXG_PCLK_GATE(loopback, 15);
93static AXG_PCLK_GATE(spdifin, 16);
94static AXG_PCLK_GATE(spdifout, 17);
95static AXG_PCLK_GATE(resample, 18);
96static AXG_PCLK_GATE(power_detect, 19);
97
98/* Audio Master Clocks */
99static 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
108static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL);
109static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL);
110static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL);
111static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL);
112static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL);
113static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL);
114static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
115static AXG_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
116static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
117static 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
123static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL);
124static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL);
125static AXG_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL);
126static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL);
127static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL);
128static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL);
129static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
130static AXG_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
131static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
132static 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
138static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL);
139static AXG_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL);
140static AXG_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL);
141static AXG_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL);
142static AXG_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL);
143static AXG_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL);
144static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
145static AXG_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
146static AXG_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
147static 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
154static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0);
155static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0);
156static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0);
157static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0);
158static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0);
159static 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) \
163struct 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
190static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
191static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
192static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
193static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
194static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
195static 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
201static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0);
202static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0);
203static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0);
204static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0);
205static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0);
206static 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) \
210struct 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
241static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1);
242static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1);
243static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1);
244static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1);
245static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1);
246static 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
252static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0);
253static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0);
254static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0);
255static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0);
256static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0);
257static 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
263static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1);
264static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1);
265static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1);
266static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1);
267static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1);
268static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1);
269
270static 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
284static AXG_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL);
285static AXG_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL);
286static AXG_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL);
287static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
288static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
289static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
290static 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
296static AXG_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL);
297static AXG_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL);
298static AXG_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL);
299static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
300static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
301static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
302static 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
308static AXG_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL);
309static AXG_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL);
310static AXG_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL);
311static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
312static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
313static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
314static 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
335static AXG_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL);
336static AXG_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL);
337static AXG_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL);
338static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
339static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
340static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
341static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL);
342
343static 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
357static AXG_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL);
358static AXG_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL);
359static AXG_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL);
360static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL);
361static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL);
362static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL);
363static 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 */
369static 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() */
498static 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
622static 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
651static const struct clk_ops axg_clk_no_ops = {};
652
653static 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
683static 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
715static 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
737static 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
744static 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
828static const struct of_device_id clkc_match_table[] = {
829 { .compatible = "amlogic,axg-audio-clkc" },
830 {}
831};
832MODULE_DEVICE_TABLE(of, clkc_match_table);
833
834static 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};
841module_platform_driver(axg_audio_driver);
842
843MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver");
844MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
845MODULE_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
628static 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
639static 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
649static 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
698static 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
713static 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
730static 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
745static 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
629static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; 759static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 };
630static const char * const clk81_parent_names[] = { 760static 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
912static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8,
913 9, 10, 11, 13, 14, };
914static 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
919static 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
940static 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
955static 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 */
783static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0); 970static MESON_GATE(axg_ddr, HHI_GCLK_MPEG0, 0);
784static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2); 971static MESON_GATE(axg_audio_locker, HHI_GCLK_MPEG0, 2);
@@ -821,6 +1008,7 @@ static MESON_GATE(axg_mmc_pclk, HHI_GCLK_MPEG2, 11);
821static MESON_GATE(axg_vpu_intr, HHI_GCLK_MPEG2, 25); 1008static MESON_GATE(axg_vpu_intr, HHI_GCLK_MPEG2, 25);
822static MESON_GATE(axg_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); 1009static MESON_GATE(axg_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26);
823static MESON_GATE(axg_gic, HHI_GCLK_MPEG2, 30); 1010static MESON_GATE(axg_gic, HHI_GCLK_MPEG2, 30);
1011static 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
993static const struct of_device_id clkc_match_table[] = { 1199static 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
998static const struct regmap_config clkc_regmap_config = {
999 .reg_bits = 32,
1000 .val_bits = 32,
1001 .reg_stride = 4,
1002};
1003
1004static int axg_clkc_probe(struct platform_device *pdev) 1204static 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
20static inline struct meson_clk_audio_div_data *
21meson_clk_audio_div_data(struct clk_regmap *clk)
22{
23 return (struct meson_clk_audio_div_data *)clk->data;
24}
25
26static 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
35static int _get_val(unsigned long parent_rate, unsigned long rate)
36{
37 return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1;
38}
39
40static 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
47static 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
59static 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
88static 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
101const 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
106const 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
12static inline struct meson_clk_phase_data *
13meson_clk_phase_data(struct clk_regmap *clk)
14{
15 return (struct meson_clk_phase_data *)clk->data;
16}
17
18int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
19{
20 return phase_step(width) * val;
21}
22EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val);
23
24unsigned 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}
34EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val);
35
36static 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
47static 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
59const struct clk_ops meson_clk_phase_ops = {
60 .get_phase = meson_clk_phase_get_phase,
61 .set_phase = meson_clk_phase_set_phase,
62};
63EXPORT_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 */
19static inline struct meson_clk_triphase_data *
20meson_clk_triphase_data(struct clk_regmap *clk)
21{
22 return (struct meson_clk_triphase_data *)clk->data;
23}
24
25static 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
37static 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
49static 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
63const 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};
68EXPORT_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
12struct meson_clk_triphase_data {
13 struct parm ph0;
14 struct parm ph1;
15 struct parm ph2;
16};
17
18struct 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
25extern const struct clk_ops meson_clk_triphase_ops;
26extern 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
94struct meson_clk_audio_div_data { 94struct meson_clk_phase_data {
95 struct parm div; 95 struct parm ph;
96 u8 flags;
97}; 96};
98 97
98int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
99unsigned 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) \
100struct clk_regmap _name = { \ 102struct 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;
117extern const struct clk_ops meson_clk_cpu_ops; 119extern const struct clk_ops meson_clk_cpu_ops;
118extern const struct clk_ops meson_clk_mpll_ro_ops; 120extern const struct clk_ops meson_clk_mpll_ro_ops;
119extern const struct clk_ops meson_clk_mpll_ops; 121extern const struct clk_ops meson_clk_mpll_ops;
120extern const struct clk_ops meson_clk_audio_divider_ro_ops; 122extern const struct clk_ops meson_clk_phase_ops;
121extern 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
983static struct clk_regmap gxbb_cts_amclk_div = { 983static 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
1627static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8,
1628 9, 10, 11, 13, 14, };
1629static 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
1634static 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
1655static 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
1670static 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 */
1630static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); 1685static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0);
1631static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); 1686static 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
2206struct clkc_data { 2270struct clkc_data {
@@ -2227,17 +2291,9 @@ static const struct of_device_id clkc_match_table[] = {
2227 {}, 2291 {},
2228}; 2292};
2229 2293
2230static const struct regmap_config clkc_regmap_config = {
2231 .reg_bits = 32,
2232 .val_bits = 32,
2233 .reg_stride = 4,
2234};
2235
2236static int gxbb_clkc_probe(struct platform_device *pdev) 2294static 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
21static inline struct meson_sclk_div_data *
22meson_sclk_div_data(struct clk_regmap *clk)
23{
24 return (struct meson_sclk_div_data *)clk->data;
25}
26
27static int sclk_div_maxval(struct meson_sclk_div_data *sclk)
28{
29 return (1 << sclk->div.width) - 1;
30}
31
32static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk)
33{
34 return sclk_div_maxval(sclk) + 1;
35}
36
37static 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
45static 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
95static 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
107static 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
120static 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
134static 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
153static 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
162static 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
177static 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
186static 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
196static 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
204static 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
215static 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
232const 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};
243EXPORT_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
42struct clk; 44struct clk;
43struct clk_hw; 45struct 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 */
77struct 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);
142int clk_get_phase(struct clk *clk); 142int 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 */
153int 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 */
163int 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
207static inline int clk_set_duty_cycle(struct clk *clk, unsigned int num,
208 unsigned int den)
209{
210 return -ENOTSUPP;
211}
212
213static inline unsigned int clk_get_scaled_duty_cycle(struct clk *clk,
214 unsigned int scale)
215{
216 return 0;
217}
218
186static inline bool clk_is_match(const struct clk *p, const struct clk *q) 219static 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
195DECLARE_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
217DEFINE_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
224DEFINE_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 */