From 59a43fa2487bf8ac67a758c4e653ce3db16f86a9 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 21 Dec 2021 14:24:23 +0900 Subject: [PATCH 01/26] clk: renesas: r8a779f0: Add SYS-DMAC clocks Add SYS-DMAC clocks on r8a779f0. Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20211221052423.597283-1-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a779f0-cpg-mssr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c index e6ec02c2c2a8..8cc7457564db 100644 --- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c @@ -119,6 +119,8 @@ static const struct mssr_mod_clk r8a779f0_mod_clks[] __initconst = { DEF_MOD("scif1", 703, R8A779F0_CLK_S0D12_PER), DEF_MOD("scif3", 704, R8A779F0_CLK_S0D12_PER), DEF_MOD("scif4", 705, R8A779F0_CLK_S0D12_PER), + DEF_MOD("sys-dmac0", 709, R8A779F0_CLK_S0D3_PER), + DEF_MOD("sys-dmac1", 710, R8A779F0_CLK_S0D3_PER), }; /* From d843e61e0ea50ecf2fc9276c828ea3867867fd89 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Sat, 25 Dec 2021 22:39:57 +0300 Subject: [PATCH 02/26] clk: renesas: r8a7799[05]: Add MLP clocks Add clocks for MLP modules on Renesas R-Car E3 and D3 SoCs. Similar to other R-Car Gen3 SoC, exact information on the parents of MLP clocks on E3 and D3 is not available. However, since the parents of these clocks are not anyhow software-controllable, the only harm from this is inexact information exported via debugfs. So just keep the parent set in the same way as with other Gen3 SoCs. Signed-off-by: Nikita Yushchenko Link: https://lore.kernel.org/r/20211225193957.2195012-1-nikita.yoush@cogentembedded.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a77990-cpg-mssr.c | 1 + drivers/clk/renesas/r8a77995-cpg-mssr.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a77990-cpg-mssr.c b/drivers/clk/renesas/r8a77990-cpg-mssr.c index faf60f7adc8d..d34d97baab35 100644 --- a/drivers/clk/renesas/r8a77990-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77990-cpg-mssr.c @@ -200,6 +200,7 @@ static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = { DEF_MOD("du0", 724, R8A77990_CLK_S1D1), DEF_MOD("lvds", 727, R8A77990_CLK_S2D1), + DEF_MOD("mlp", 802, R8A77990_CLK_S2D1), DEF_MOD("vin5", 806, R8A77990_CLK_S1D2), DEF_MOD("vin4", 807, R8A77990_CLK_S1D2), DEF_MOD("etheravb", 812, R8A77990_CLK_S3D2), diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c index 7713cfd99c1d..525eef197fd9 100644 --- a/drivers/clk/renesas/r8a77995-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c @@ -160,6 +160,7 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = { DEF_MOD("du1", 723, R8A77995_CLK_S1D1), DEF_MOD("du0", 724, R8A77995_CLK_S1D1), DEF_MOD("lvds", 727, R8A77995_CLK_S2D1), + DEF_MOD("mlp", 802, R8A77995_CLK_S2D1), DEF_MOD("vin4", 807, R8A77995_CLK_S1D2), DEF_MOD("etheravb", 812, R8A77995_CLK_S3D2), DEF_MOD("imr0", 823, R8A77995_CLK_S1D2), From b289cdecc7c3e25e001cde260c882e4d9a8b0772 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 23 Dec 2021 09:32:23 +0000 Subject: [PATCH 03/26] clk: renesas: r9a07g044: Update multiplier and divider values for PLL2/3 As per the HW manual (Rev.1.00 Sep, 2021) PLL2 and PLL3 should be 1600 MHz, but with current multiplier and divider values this resulted to 1596 MHz. This patch updates the multiplier and divider values for PLL2 and PLL3 so that we get the exact (1600 MHz) values. Fixes: 17f0ff3d49ff1 ("clk: renesas: Add support for R9A07G044 SoC") Suggested-by: Biju Das Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20211223093223.4725-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a07g044-cpg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c index 79042bf46fe8..46359afef0d4 100644 --- a/drivers/clk/renesas/r9a07g044-cpg.c +++ b/drivers/clk/renesas/r9a07g044-cpg.c @@ -88,8 +88,8 @@ static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = { DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1), DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000), DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)), - DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 133, 2), - DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 133, 2), + DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3), + DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3), DEF_FIXED(".pll3_400", CLK_PLL3_400, CLK_PLL3, 1, 4), DEF_FIXED(".pll3_533", CLK_PLL3_533, CLK_PLL3, 1, 3), From 9b621b6adff533468798404acca062c46da141af Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 11 Jan 2022 17:22:27 +0100 Subject: [PATCH 04/26] clk: renesas: r8a779a0: Add CANFD module clock Adds "canfd0" to mod clocks. Signed-off-by: Ulrich Hecht Link: https://lore.kernel.org/r/20220111162231.10390-2-uli+renesas@fpond.eu Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a779a0-cpg-mssr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index 1c09d4ebe90f..fadd8a1718c6 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -136,6 +136,7 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = { DEF_MOD("avb3", 214, R8A779A0_CLK_S3D2), DEF_MOD("avb4", 215, R8A779A0_CLK_S3D2), DEF_MOD("avb5", 216, R8A779A0_CLK_S3D2), + DEF_MOD("canfd0", 328, R8A779A0_CLK_CANFD), DEF_MOD("csi40", 331, R8A779A0_CLK_CSI0), DEF_MOD("csi41", 400, R8A779A0_CLK_CSI0), DEF_MOD("csi42", 401, R8A779A0_CLK_CSI0), From 4917394e0c765e89787ed8e296a0706cac51440d Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 19 Jan 2022 12:54:34 +0100 Subject: [PATCH 05/26] clk: zynqmp: replace warn_once with pr_debug for failed clock ops The warning that a clock operation failed is only printed once. However, the function is called for various different clocks. The limit hides the warnings if different clocks are affected by the failures. The clock ops might fail if the firmware that handles the clocks is misconfigured. Therefore, replace the pr_warn_once with pr_debug to allow the user to see all errors if necessary. By default, hide the error messages and let drivers handle the errors. Signed-off-by: Michael Tretter Link: https://lore.kernel.org/r/20220119115434.2042017-1-m.tretter@pengutronix.de Acked-by: Michal Simek Signed-off-by: Stephen Boyd --- drivers/clk/zynqmp/clk-gate-zynqmp.c | 12 +++++------ drivers/clk/zynqmp/clk-mux-zynqmp.c | 8 +++---- drivers/clk/zynqmp/divider.c | 12 +++++------ drivers/clk/zynqmp/pll.c | 32 ++++++++++++++-------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/clk/zynqmp/clk-gate-zynqmp.c b/drivers/clk/zynqmp/clk-gate-zynqmp.c index 565ed67a0430..b89e55737198 100644 --- a/drivers/clk/zynqmp/clk-gate-zynqmp.c +++ b/drivers/clk/zynqmp/clk-gate-zynqmp.c @@ -41,8 +41,8 @@ static int zynqmp_clk_gate_enable(struct clk_hw *hw) ret = zynqmp_pm_clock_enable(clk_id); if (ret) - pr_warn_once("%s() clock enabled failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() clock enable failed for %s (id %d), ret = %d\n", + __func__, clk_name, clk_id, ret); return ret; } @@ -61,8 +61,8 @@ static void zynqmp_clk_gate_disable(struct clk_hw *hw) ret = zynqmp_pm_clock_disable(clk_id); if (ret) - pr_warn_once("%s() clock disable failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() clock disable failed for %s (id %d), ret = %d\n", + __func__, clk_name, clk_id, ret); } /** @@ -80,8 +80,8 @@ static int zynqmp_clk_gate_is_enabled(struct clk_hw *hw) ret = zynqmp_pm_clock_getstate(clk_id, &state); if (ret) { - pr_warn_once("%s() clock get state failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() clock get state failed for %s, ret = %d\n", + __func__, clk_name, ret); return -EIO; } diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c index 17afce594f28..60359333f26d 100644 --- a/drivers/clk/zynqmp/clk-mux-zynqmp.c +++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c @@ -51,8 +51,8 @@ static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw) ret = zynqmp_pm_clock_getparent(clk_id, &val); if (ret) { - pr_warn_once("%s() getparent failed for clock: %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() getparent failed for clock: %s, ret = %d\n", + __func__, clk_name, ret); /* * clk_core_get_parent_by_index() takes num_parents as incorrect * index which is exactly what I want to return here @@ -80,8 +80,8 @@ static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index) ret = zynqmp_pm_clock_setparent(clk_id, index); if (ret) - pr_warn_once("%s() set parent failed for clock: %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() set parent failed for clock: %s, ret = %d\n", + __func__, clk_name, ret); return ret; } diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c index cb49281f9cf9..422ea79907dd 100644 --- a/drivers/clk/zynqmp/divider.c +++ b/drivers/clk/zynqmp/divider.c @@ -89,8 +89,8 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, ret = zynqmp_pm_clock_getdivider(clk_id, &div); if (ret) - pr_warn_once("%s() get divider failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() get divider failed for %s, ret = %d\n", + __func__, clk_name, ret); if (div_type == TYPE_DIV1) value = div & 0xFFFF; @@ -177,8 +177,8 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, ret = zynqmp_pm_clock_getdivider(clk_id, &bestdiv); if (ret) - pr_warn_once("%s() get divider failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() get divider failed for %s, ret = %d\n", + __func__, clk_name, ret); if (div_type == TYPE_DIV1) bestdiv = bestdiv & 0xFFFF; else @@ -244,8 +244,8 @@ static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, ret = zynqmp_pm_clock_setdivider(clk_id, div); if (ret) - pr_warn_once("%s() set divider failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() set divider failed for %s, ret = %d\n", + __func__, clk_name, ret); return ret; } diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c index 036e4ff64a2f..91a6b4cc910e 100644 --- a/drivers/clk/zynqmp/pll.c +++ b/drivers/clk/zynqmp/pll.c @@ -56,8 +56,8 @@ static inline enum pll_mode zynqmp_pll_get_mode(struct clk_hw *hw) ret = zynqmp_pm_get_pll_frac_mode(clk_id, ret_payload); if (ret) { - pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() PLL get frac mode failed for %s, ret = %d\n", + __func__, clk_name, ret); return PLL_MODE_ERROR; } @@ -84,8 +84,8 @@ static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on) ret = zynqmp_pm_set_pll_frac_mode(clk_id, mode); if (ret) - pr_warn_once("%s() PLL set frac mode failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() PLL set frac mode failed for %s, ret = %d\n", + __func__, clk_name, ret); else clk->set_pll_mode = true; } @@ -145,8 +145,8 @@ static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw, ret = zynqmp_pm_clock_getdivider(clk_id, &fbdiv); if (ret) { - pr_warn_once("%s() get divider failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() get divider failed for %s, ret = %d\n", + __func__, clk_name, ret); return 0ul; } @@ -200,8 +200,8 @@ static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate, WARN(1, "More than allowed devices are using the %s, which is forbidden\n", clk_name); else if (ret) - pr_warn_once("%s() set divider failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() set divider failed for %s, ret = %d\n", + __func__, clk_name, ret); zynqmp_pm_set_pll_frac_data(clk_id, f); return rate + frac; @@ -211,8 +211,8 @@ static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate, fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX); ret = zynqmp_pm_clock_setdivider(clk_id, fbdiv); if (ret) - pr_warn_once("%s() set divider failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() set divider failed for %s, ret = %d\n", + __func__, clk_name, ret); return parent_rate * fbdiv; } @@ -233,8 +233,8 @@ static int zynqmp_pll_is_enabled(struct clk_hw *hw) ret = zynqmp_pm_clock_getstate(clk_id, &state); if (ret) { - pr_warn_once("%s() clock get state failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() clock get state failed for %s, ret = %d\n", + __func__, clk_name, ret); return -EIO; } @@ -265,8 +265,8 @@ static int zynqmp_pll_enable(struct clk_hw *hw) ret = zynqmp_pm_clock_enable(clk_id); if (ret) - pr_warn_once("%s() clock enable failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() clock enable failed for %s, ret = %d\n", + __func__, clk_name, ret); return ret; } @@ -287,8 +287,8 @@ static void zynqmp_pll_disable(struct clk_hw *hw) ret = zynqmp_pm_clock_disable(clk_id); if (ret) - pr_warn_once("%s() clock disable failed for %s, ret = %d\n", - __func__, clk_name, ret); + pr_debug("%s() clock disable failed for %s, ret = %d\n", + __func__, clk_name, ret); } static const struct clk_ops zynqmp_pll_ops = { From a992acbb219a74fb025f8c2d65760fe05e775c7b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 20 Jan 2022 09:59:02 -0800 Subject: [PATCH 06/26] clk: gate: Add some kunit test suites Test various parts of the clk gate implementation with the kunit testing framework. Reviewed-by: Brendan Higgins Acked-by: Daniel Latypov Cc: Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20220120175902.2165958-1-sboyd@kernel.org --- drivers/clk/.kunitconfig | 3 + drivers/clk/Kconfig | 8 + drivers/clk/Makefile | 1 + drivers/clk/clk-gate_test.c | 464 ++++++++++++++++++++++++++++++++++++ 4 files changed, 476 insertions(+) create mode 100644 drivers/clk/.kunitconfig create mode 100644 drivers/clk/clk-gate_test.c diff --git a/drivers/clk/.kunitconfig b/drivers/clk/.kunitconfig new file mode 100644 index 000000000000..3754fdb9485a --- /dev/null +++ b/drivers/clk/.kunitconfig @@ -0,0 +1,3 @@ +CONFIG_KUNIT=y +CONFIG_COMMON_CLK=y +CONFIG_CLK_GATE_KUNIT_TEST=y diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index ad4256d54361..3cdf33470a75 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -428,4 +428,12 @@ source "drivers/clk/x86/Kconfig" source "drivers/clk/xilinx/Kconfig" source "drivers/clk/zynqmp/Kconfig" +# Kunit test cases +config CLK_GATE_KUNIT_TEST + tristate "Basic gate type Kunit test" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + Kunit test for the basic clk gate type. + endif diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 16e588630472..6a98291350b6 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-divider.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o obj-$(CONFIG_COMMON_CLK) += clk-gate.o +obj-$(CONFIG_CLK_GATE_KUNIT_TEST) += clk-gate_test.o obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_COMMON_CLK) += clk-composite.o diff --git a/drivers/clk/clk-gate_test.c b/drivers/clk/clk-gate_test.c new file mode 100644 index 000000000000..e136aaad48bf --- /dev/null +++ b/drivers/clk/clk-gate_test.c @@ -0,0 +1,464 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Kunit test for clk gate basic type + */ +#include +#include +#include + +#include + +static void clk_gate_register_test_dev(struct kunit *test) +{ + struct clk_hw *ret; + struct platform_device *pdev; + + pdev = platform_device_register_simple("test_gate_device", -1, NULL, 0); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + + ret = clk_hw_register_gate(&pdev->dev, "test_gate", NULL, 0, NULL, + 0, 0, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); + KUNIT_EXPECT_STREQ(test, "test_gate", clk_hw_get_name(ret)); + KUNIT_EXPECT_EQ(test, 0UL, clk_hw_get_flags(ret)); + + clk_hw_unregister_gate(ret); + platform_device_put(pdev); +} + +static void clk_gate_register_test_parent_names(struct kunit *test) +{ + struct clk_hw *parent; + struct clk_hw *ret; + + parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0, + 1000000); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); + + ret = clk_hw_register_gate(NULL, "test_gate", "test_parent", 0, NULL, + 0, 0, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); + KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret)); + + clk_hw_unregister_gate(ret); + clk_hw_unregister_fixed_rate(parent); +} + +static void clk_gate_register_test_parent_data(struct kunit *test) +{ + struct clk_hw *parent; + struct clk_hw *ret; + struct clk_parent_data pdata = { }; + + parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0, + 1000000); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); + pdata.hw = parent; + + ret = clk_hw_register_gate_parent_data(NULL, "test_gate", &pdata, 0, + NULL, 0, 0, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); + KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret)); + + clk_hw_unregister_gate(ret); + clk_hw_unregister_fixed_rate(parent); +} + +static void clk_gate_register_test_parent_data_legacy(struct kunit *test) +{ + struct clk_hw *parent; + struct clk_hw *ret; + struct clk_parent_data pdata = { }; + + parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0, + 1000000); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); + pdata.name = "test_parent"; + + ret = clk_hw_register_gate_parent_data(NULL, "test_gate", &pdata, 0, + NULL, 0, 0, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); + KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret)); + + clk_hw_unregister_gate(ret); + clk_hw_unregister_fixed_rate(parent); +} + +static void clk_gate_register_test_parent_hw(struct kunit *test) +{ + struct clk_hw *parent; + struct clk_hw *ret; + + parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0, + 1000000); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); + + ret = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0, NULL, + 0, 0, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret); + KUNIT_EXPECT_PTR_EQ(test, parent, clk_hw_get_parent(ret)); + + clk_hw_unregister_gate(ret); + clk_hw_unregister_fixed_rate(parent); +} + +static void clk_gate_register_test_hiword_invalid(struct kunit *test) +{ + struct clk_hw *ret; + + ret = clk_hw_register_gate(NULL, "test_gate", NULL, 0, NULL, + 20, CLK_GATE_HIWORD_MASK, NULL); + + KUNIT_EXPECT_TRUE(test, IS_ERR(ret)); +} + +static struct kunit_case clk_gate_register_test_cases[] = { + KUNIT_CASE(clk_gate_register_test_dev), + KUNIT_CASE(clk_gate_register_test_parent_names), + KUNIT_CASE(clk_gate_register_test_parent_data), + KUNIT_CASE(clk_gate_register_test_parent_data_legacy), + KUNIT_CASE(clk_gate_register_test_parent_hw), + KUNIT_CASE(clk_gate_register_test_hiword_invalid), + {} +}; + +static struct kunit_suite clk_gate_register_test_suite = { + .name = "clk-gate-register-test", + .test_cases = clk_gate_register_test_cases, +}; + +struct clk_gate_test_context { + void __iomem *fake_mem; + struct clk_hw *hw; + struct clk_hw *parent; + u32 fake_reg; /* Keep at end, KASAN can detect out of bounds */ +}; + +static struct clk_gate_test_context *clk_gate_test_alloc_ctx(struct kunit *test) +{ + struct clk_gate_test_context *ctx; + + test->priv = ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + ctx->fake_mem = (void __force __iomem *)&ctx->fake_reg; + + return ctx; +} + +static void clk_gate_test_parent_rate(struct kunit *test) +{ + struct clk_gate_test_context *ctx = test->priv; + struct clk_hw *parent = ctx->parent; + struct clk_hw *hw = ctx->hw; + unsigned long prate = clk_hw_get_rate(parent); + unsigned long rate = clk_hw_get_rate(hw); + + KUNIT_EXPECT_EQ(test, prate, rate); +} + +static void clk_gate_test_enable(struct kunit *test) +{ + struct clk_gate_test_context *ctx = test->priv; + struct clk_hw *parent = ctx->parent; + struct clk_hw *hw = ctx->hw; + struct clk *clk = hw->clk; + u32 enable_val = BIT(5); + + KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); + + KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg); + KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw)); + KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw)); + KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent)); + KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent)); +} + +static void clk_gate_test_disable(struct kunit *test) +{ + struct clk_gate_test_context *ctx = test->priv; + struct clk_hw *parent = ctx->parent; + struct clk_hw *hw = ctx->hw; + struct clk *clk = hw->clk; + u32 enable_val = BIT(5); + u32 disable_val = 0; + + KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); + KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg); + + clk_disable_unprepare(clk); + KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg); + KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw)); + KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw)); + KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent)); + KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent)); +} + +static struct kunit_case clk_gate_test_cases[] = { + KUNIT_CASE(clk_gate_test_parent_rate), + KUNIT_CASE(clk_gate_test_enable), + KUNIT_CASE(clk_gate_test_disable), + {} +}; + +static int clk_gate_test_init(struct kunit *test) +{ + struct clk_hw *parent; + struct clk_hw *hw; + struct clk_gate_test_context *ctx; + + ctx = clk_gate_test_alloc_ctx(test); + parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0, + 2000000); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); + + hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0, + ctx->fake_mem, 5, 0, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + + ctx->hw = hw; + ctx->parent = parent; + + return 0; +} + +static void clk_gate_test_exit(struct kunit *test) +{ + struct clk_gate_test_context *ctx = test->priv; + + clk_hw_unregister_gate(ctx->hw); + clk_hw_unregister_fixed_rate(ctx->parent); +} + +static struct kunit_suite clk_gate_test_suite = { + .name = "clk-gate-test", + .init = clk_gate_test_init, + .exit = clk_gate_test_exit, + .test_cases = clk_gate_test_cases, +}; + +static void clk_gate_test_invert_enable(struct kunit *test) +{ + struct clk_gate_test_context *ctx = test->priv; + struct clk_hw *parent = ctx->parent; + struct clk_hw *hw = ctx->hw; + struct clk *clk = hw->clk; + u32 enable_val = 0; + + KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); + + KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg); + KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw)); + KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw)); + KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent)); + KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent)); +} + +static void clk_gate_test_invert_disable(struct kunit *test) +{ + struct clk_gate_test_context *ctx = test->priv; + struct clk_hw *parent = ctx->parent; + struct clk_hw *hw = ctx->hw; + struct clk *clk = hw->clk; + u32 enable_val = 0; + u32 disable_val = BIT(15); + + KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); + KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg); + + clk_disable_unprepare(clk); + KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg); + KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw)); + KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw)); + KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent)); + KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent)); +} + +static struct kunit_case clk_gate_test_invert_cases[] = { + KUNIT_CASE(clk_gate_test_invert_enable), + KUNIT_CASE(clk_gate_test_invert_disable), + {} +}; + +static int clk_gate_test_invert_init(struct kunit *test) +{ + struct clk_hw *parent; + struct clk_hw *hw; + struct clk_gate_test_context *ctx; + + ctx = clk_gate_test_alloc_ctx(test); + parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0, + 2000000); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); + + ctx->fake_reg = BIT(15); /* Default to off */ + hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0, + ctx->fake_mem, 15, + CLK_GATE_SET_TO_DISABLE, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + + ctx->hw = hw; + ctx->parent = parent; + + return 0; +} + +static struct kunit_suite clk_gate_test_invert_suite = { + .name = "clk-gate-invert-test", + .init = clk_gate_test_invert_init, + .exit = clk_gate_test_exit, + .test_cases = clk_gate_test_invert_cases, +}; + +static void clk_gate_test_hiword_enable(struct kunit *test) +{ + struct clk_gate_test_context *ctx = test->priv; + struct clk_hw *parent = ctx->parent; + struct clk_hw *hw = ctx->hw; + struct clk *clk = hw->clk; + u32 enable_val = BIT(9) | BIT(9 + 16); + + KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); + + KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg); + KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw)); + KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw)); + KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent)); + KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(parent)); +} + +static void clk_gate_test_hiword_disable(struct kunit *test) +{ + struct clk_gate_test_context *ctx = test->priv; + struct clk_hw *parent = ctx->parent; + struct clk_hw *hw = ctx->hw; + struct clk *clk = hw->clk; + u32 enable_val = BIT(9) | BIT(9 + 16); + u32 disable_val = BIT(9 + 16); + + KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); + KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg); + + clk_disable_unprepare(clk); + KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg); + KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw)); + KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw)); + KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent)); + KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(parent)); +} + +static struct kunit_case clk_gate_test_hiword_cases[] = { + KUNIT_CASE(clk_gate_test_hiword_enable), + KUNIT_CASE(clk_gate_test_hiword_disable), + {} +}; + +static int clk_gate_test_hiword_init(struct kunit *test) +{ + struct clk_hw *parent; + struct clk_hw *hw; + struct clk_gate_test_context *ctx; + + ctx = clk_gate_test_alloc_ctx(test); + parent = clk_hw_register_fixed_rate(NULL, "test_parent", NULL, 0, + 2000000); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); + + hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0, + ctx->fake_mem, 9, + CLK_GATE_HIWORD_MASK, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + + ctx->hw = hw; + ctx->parent = parent; + + return 0; +} + +static struct kunit_suite clk_gate_test_hiword_suite = { + .name = "clk-gate-hiword-test", + .init = clk_gate_test_hiword_init, + .exit = clk_gate_test_exit, + .test_cases = clk_gate_test_hiword_cases, +}; + +static void clk_gate_test_is_enabled(struct kunit *test) +{ + struct clk_hw *hw; + struct clk_gate_test_context *ctx; + + ctx = clk_gate_test_alloc_ctx(test); + ctx->fake_reg = BIT(7); + hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7, + 0, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw)); + + clk_hw_unregister_gate(hw); +} + +static void clk_gate_test_is_disabled(struct kunit *test) +{ + struct clk_hw *hw; + struct clk_gate_test_context *ctx; + + ctx = clk_gate_test_alloc_ctx(test); + ctx->fake_reg = BIT(4); + hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7, + 0, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw)); + + clk_hw_unregister_gate(hw); +} + +static void clk_gate_test_is_enabled_inverted(struct kunit *test) +{ + struct clk_hw *hw; + struct clk_gate_test_context *ctx; + + ctx = clk_gate_test_alloc_ctx(test); + ctx->fake_reg = BIT(31); + hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 2, + CLK_GATE_SET_TO_DISABLE, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + KUNIT_ASSERT_TRUE(test, clk_hw_is_enabled(hw)); + + clk_hw_unregister_gate(hw); +} + +static void clk_gate_test_is_disabled_inverted(struct kunit *test) +{ + struct clk_hw *hw; + struct clk_gate_test_context *ctx; + + ctx = clk_gate_test_alloc_ctx(test); + ctx->fake_reg = BIT(29); + hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 29, + CLK_GATE_SET_TO_DISABLE, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + KUNIT_ASSERT_FALSE(test, clk_hw_is_enabled(hw)); + + clk_hw_unregister_gate(hw); +} + +static struct kunit_case clk_gate_test_enabled_cases[] = { + KUNIT_CASE(clk_gate_test_is_enabled), + KUNIT_CASE(clk_gate_test_is_disabled), + KUNIT_CASE(clk_gate_test_is_enabled_inverted), + KUNIT_CASE(clk_gate_test_is_disabled_inverted), + {} +}; + +static struct kunit_suite clk_gate_test_enabled_suite = { + .name = "clk-gate-is_enabled-test", + .test_cases = clk_gate_test_enabled_cases, +}; + +kunit_test_suites( + &clk_gate_register_test_suite, + &clk_gate_test_suite, + &clk_gate_test_invert_suite, + &clk_gate_test_hiword_suite, + &clk_gate_test_enabled_suite +); +MODULE_LICENSE("GPL v2"); From 8e972afb3be633a2985081af75664a26f1929cf2 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 25 Jan 2022 10:33:28 +0100 Subject: [PATCH 07/26] dt-bindings: clock: convert cs2000-cp bindings to yaml The original author of the file was added as maintainer. Signed-off-by: Daniel Mack Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20220125093336.226787-2-daniel@zonque.org Signed-off-by: Stephen Boyd --- .../bindings/clock/cirrus,cs2000-cp.yaml | 63 +++++++++++++++++++ .../devicetree/bindings/clock/cs2000-cp.txt | 22 ------- 2 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml delete mode 100644 Documentation/devicetree/bindings/clock/cs2000-cp.txt diff --git a/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml b/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml new file mode 100644 index 000000000000..379a8bab49ca --- /dev/null +++ b/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/cirrus,cs2000-cp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Binding CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier + +maintainers: + - Kuninori Morimoto + +description: | + The CS2000-CP is an extremely versatile system clocking device that + utilizes a programmable phase lock loop. + + Link: https://www.cirrus.com/products/cs2000/ + +properties: + compatible: + enum: + - cirrus,cs2000-cp + + clocks: + description: + Common clock binding for CLK_IN, XTI/REF_CLK + minItems: 2 + maxItems: 2 + + clock-names: + items: + - const: clk_in + - const: ref_clk + + '#clock-cells': + const: 0 + + reg: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + +additionalProperties: false + +examples: + - | + i2c@0 { + reg = <0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + + clock-controller@4f { + #clock-cells = <0>; + compatible = "cirrus,cs2000-cp"; + reg = <0x4f>; + clocks = <&rcar_sound 0>, <&x12_clk>; + clock-names = "clk_in", "ref_clk"; + }; + }; diff --git a/Documentation/devicetree/bindings/clock/cs2000-cp.txt b/Documentation/devicetree/bindings/clock/cs2000-cp.txt deleted file mode 100644 index 54e6df0bee8a..000000000000 --- a/Documentation/devicetree/bindings/clock/cs2000-cp.txt +++ /dev/null @@ -1,22 +0,0 @@ -CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier - -Required properties: - -- compatible: "cirrus,cs2000-cp" -- reg: The chip select number on the I2C bus -- clocks: common clock binding for CLK_IN, XTI/REF_CLK -- clock-names: CLK_IN : clk_in, XTI/REF_CLK : ref_clk -- #clock-cells: must be <0> - -Example: - -&i2c2 { - ... - cs2000: clk_multiplier@4f { - #clock-cells = <0>; - compatible = "cirrus,cs2000-cp"; - reg = <0x4f>; - clocks = <&rcar_sound 0>, <&x12_clk>; - clock-names = "clk_in", "ref_clk"; - }; -}; From 68643c3735102177139237fd6656085eac403b69 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 25 Jan 2022 10:33:29 +0100 Subject: [PATCH 08/26] dt-bindings: clock: cs2000-cp: document aux-output-source This new optional property can be used to control the function of the auxiliary output pin. Introduce a new dt-bindings include file that contains the numerical values. Signed-off-by: Daniel Mack Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220125093336.226787-3-daniel@zonque.org Signed-off-by: Stephen Boyd --- .../bindings/clock/cirrus,cs2000-cp.yaml | 14 ++++++++++++++ include/dt-bindings/clock/cirrus,cs2000-cp.h | 14 ++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 include/dt-bindings/clock/cirrus,cs2000-cp.h diff --git a/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml b/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml index 379a8bab49ca..79b90500f6ac 100644 --- a/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml +++ b/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml @@ -37,6 +37,17 @@ properties: reg: maxItems: 1 + cirrus,aux-output-source: + description: + Specifies the function of the auxiliary clock output pin + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # CS2000CP_AUX_OUTPUT_REF_CLK: ref_clk input + - 1 # CS2000CP_AUX_OUTPUT_CLK_IN: clk_in input + - 2 # CS2000CP_AUX_OUTPUT_CLK_OUT: clk_out output + - 3 # CS2000CP_AUX_OUTPUT_PLL_LOCK: pll lock status + default: 0 + required: - compatible - reg @@ -48,6 +59,8 @@ additionalProperties: false examples: - | + #include + i2c@0 { reg = <0x0 0x100>; #address-cells = <1>; @@ -59,5 +72,6 @@ examples: reg = <0x4f>; clocks = <&rcar_sound 0>, <&x12_clk>; clock-names = "clk_in", "ref_clk"; + cirrus,aux-output-source = ; }; }; diff --git a/include/dt-bindings/clock/cirrus,cs2000-cp.h b/include/dt-bindings/clock/cirrus,cs2000-cp.h new file mode 100644 index 000000000000..fe3ac71750a8 --- /dev/null +++ b/include/dt-bindings/clock/cirrus,cs2000-cp.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) 2021 Daniel Mack + */ + +#ifndef __DT_BINDINGS_CS2000CP_CLK_H +#define __DT_BINDINGS_CS2000CP_CLK_H + +#define CS2000CP_AUX_OUTPUT_REF_CLK 0 +#define CS2000CP_AUX_OUTPUT_CLK_IN 1 +#define CS2000CP_AUX_OUTPUT_CLK_OUT 2 +#define CS2000CP_AUX_OUTPUT_PLL_LOCK 3 + +#endif /* __DT_BINDINGS_CS2000CP_CLK_H */ From 11dda11f00079cdf764b80211e948d48379c1e2e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 25 Jan 2022 10:33:30 +0100 Subject: [PATCH 09/26] dt-bindings: clock: cs2000-cp: document cirrus,clock-skip flag This mode allows the PLL to maintain lock even when CLK_IN has missing pulses for up to 20 ms. Signed-off-by: Daniel Mack Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220125093336.226787-4-daniel@zonque.org Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/cirrus,cs2000-cp.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml b/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml index 79b90500f6ac..9047d8a24a08 100644 --- a/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml +++ b/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml @@ -48,6 +48,12 @@ properties: - 3 # CS2000CP_AUX_OUTPUT_PLL_LOCK: pll lock status default: 0 + cirrus,clock-skip: + description: + This mode allows the PLL to maintain lock even when CLK_IN + has missing pulses for up to 20 ms. + $ref: /schemas/types.yaml#/definitions/flag + required: - compatible - reg From 519ba32e34985fa3b79ab8163995e7a85568caa3 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 25 Jan 2022 10:33:31 +0100 Subject: [PATCH 10/26] dt-bindings: clock: cs2000-cp: document cirrus,dynamic-mode This new flag exists to enable the dynamic mode of the hardware. When not given, the static mode is used. Signed-off-by: Daniel Mack Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220125093336.226787-5-daniel@zonque.org Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/cirrus,cs2000-cp.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml b/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml index 9047d8a24a08..0abd6ba82dfd 100644 --- a/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml +++ b/Documentation/devicetree/bindings/clock/cirrus,cs2000-cp.yaml @@ -54,6 +54,14 @@ properties: has missing pulses for up to 20 ms. $ref: /schemas/types.yaml#/definitions/flag + cirrus,dynamic-mode: + description: + In dynamic mode, the CLK_IN input is used to drive the + digital PLL of the silicon. + If not given, the static mode shall be used to derive the + output signal directly from the REF_CLK input. + $ref: /schemas/types.yaml#/definitions/flag + required: - compatible - reg From a6e11bb24ebd40a05a33ac1985d8643eb7217a40 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 25 Jan 2022 10:33:32 +0100 Subject: [PATCH 11/26] clk: cs2000-cp: Make aux output function controllable The aux output pin can be configured to output either of the two clock inputs, the generated clock or the pll lock status. Allow access to this feature through a new optional device-tree property. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20220125093336.226787-6-daniel@zonque.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-cs2000-cp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index 92bc4aca0f95..db7290621cef 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -39,6 +39,8 @@ /* DEVICE_CFG1 */ #define RSEL(x) (((x) & 0x3) << 3) #define RSEL_MASK RSEL(0x3) +#define AUXOUTSRC(x) (((x) & 0x3) << 1) +#define AUXOUTSRC_MASK AUXOUTSRC(0x3) #define ENDEV1 (0x1) /* DEVICE_CFG2 */ @@ -421,12 +423,19 @@ static int cs2000_clk_register(struct cs2000_priv *priv) struct clk_init_data init; const char *name = np->name; static const char *parent_names[CLK_MAX]; + u32 aux_out = 0; int ch = 0; /* it uses ch0 only at this point */ int rate; int ret; of_property_read_string(np, "clock-output-names", &name); + of_property_read_u32(np, "cirrus,aux-output-source", &aux_out); + ret = cs2000_bset(priv, DEVICE_CFG1, + AUXOUTSRC_MASK, AUXOUTSRC(aux_out)); + if (ret < 0) + return ret; + /* * set default rate as 1/1. * otherwise .set_rate which setup ratio From da1eb4e8b4df2942614478289c89a2031d0488b1 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 25 Jan 2022 10:33:33 +0100 Subject: [PATCH 12/26] clk: cs2000-cp: add support for dynamic mode The CS2000 chip features two input clocks, REF_CLK and CLK_IN. In static mode, the output clock (CLK_OUT) is directly derived from REF_CLK, and CLK_IN is ignored. In dynamic mode, CLK_IN is used by the digital PLL. In dynamic mode, a low-frequency ratio configuration that uses a higher multiplier factor. Until now, only the static mode and high-frequency divider rations of the hardware was supported by the driver. This patch adds support for dynamic mode and both ratios: * Parse a new OF property 'cirrus,dynamic-mode' to determine the mode * In dynamic mode, present CLK_IN as parent clock, else use REF_CLK * The low-frequency ratio mode is automatically selected, depending on the mode of operation and the given input and output rates Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20220125093336.226787-7-daniel@zonque.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-cs2000-cp.c | 111 ++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index db7290621cef..bd030e156d65 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -49,7 +49,7 @@ #define LOCKCLK_MASK LOCKCLK(0x3) #define FRACNSRC_MASK (1 << 0) #define FRACNSRC_STATIC (0 << 0) -#define FRACNSRC_DYNAMIC (1 << 1) +#define FRACNSRC_DYNAMIC (1 << 0) /* GLOBAL_CFG */ #define ENDEV2 (0x1) @@ -79,6 +79,9 @@ struct cs2000_priv { struct clk *clk_in; struct clk *ref_clk; + bool dynamic_mode; + bool lf_ratio; + /* suspend/resume */ unsigned long saved_rate; unsigned long saved_parent_rate; @@ -134,17 +137,11 @@ static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable) if (ret < 0) return ret; - /* FIXME: for Static ratio mode */ - ret = cs2000_bset(priv, FUNC_CFG2, LFRATIO_MASK, - LFRATIO_12_20); - if (ret < 0) - return ret; - return 0; } -static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv, - u32 rate_in) +static int cs2000_ref_clk_bound_rate(struct cs2000_priv *priv, + u32 rate_in) { u32 val; @@ -191,35 +188,37 @@ static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable) (AUXOUTDIS | CLKOUTDIS)); } -static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out) +static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out, bool lf_ratio) { u64 ratio; + u32 multiplier = lf_ratio ? 12 : 20; /* - * ratio = rate_out / rate_in * 2^20 + * ratio = rate_out / rate_in * 2^multiplier * * To avoid over flow, rate_out is u64. * The result should be u32. */ - ratio = (u64)rate_out << 20; + ratio = (u64)rate_out << multiplier; do_div(ratio, rate_in); return ratio; } -static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in) +static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in, bool lf_ratio) { u64 rate_out; + u32 multiplier = lf_ratio ? 12 : 20; /* - * ratio = rate_out / rate_in * 2^20 + * ratio = rate_out / rate_in * 2^multiplier * * To avoid over flow, rate_out is u64. * The result should be u32 or unsigned long. */ rate_out = (u64)ratio * rate_in; - return rate_out >> 20; + return rate_out >> multiplier; } static int cs2000_ratio_set(struct cs2000_priv *priv, @@ -232,7 +231,7 @@ static int cs2000_ratio_set(struct cs2000_priv *priv, if (CH_SIZE_ERR(ch)) return -EINVAL; - val = cs2000_rate_to_ratio(rate_in, rate_out); + val = cs2000_rate_to_ratio(rate_in, rate_out, priv->lf_ratio); for (i = 0; i < RATIO_REG_SIZE; i++) { ret = cs2000_write(priv, Ratio_Add(ch, i), @@ -265,22 +264,20 @@ static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch) static int cs2000_ratio_select(struct cs2000_priv *priv, int ch) { int ret; + u8 fracnsrc; if (CH_SIZE_ERR(ch)) return -EINVAL; - /* - * FIXME - * - * this driver supports static ratio mode only at this point. - */ ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch)); if (ret < 0) return ret; + fracnsrc = priv->dynamic_mode ? FRACNSRC_DYNAMIC : FRACNSRC_STATIC; + ret = cs2000_bset(priv, DEVICE_CFG2, - (AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK), - (LOCKCLK(ch) | FRACNSRC_STATIC)); + AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK, + LOCKCLK(ch) | fracnsrc); if (ret < 0) return ret; @@ -296,17 +293,39 @@ static unsigned long cs2000_recalc_rate(struct clk_hw *hw, ratio = cs2000_ratio_get(priv, ch); - return cs2000_ratio_to_rate(ratio, parent_rate); + return cs2000_ratio_to_rate(ratio, parent_rate, priv->lf_ratio); } static long cs2000_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { + struct cs2000_priv *priv = hw_to_priv(hw); u32 ratio; - ratio = cs2000_rate_to_ratio(*parent_rate, rate); + ratio = cs2000_rate_to_ratio(*parent_rate, rate, priv->lf_ratio); - return cs2000_ratio_to_rate(ratio, *parent_rate); + return cs2000_ratio_to_rate(ratio, *parent_rate, priv->lf_ratio); +} + +static int cs2000_select_ratio_mode(struct cs2000_priv *priv, + unsigned long rate, + unsigned long parent_rate) +{ + /* + * From the datasheet: + * + * | It is recommended that the 12.20 High-Resolution format be + * | utilized whenever the desired ratio is less than 4096 since + * | the output frequency accuracy of the PLL is directly proportional + * | to the accuracy of the timing reference clock and the resolution + * | of the R_UD. + * + * This mode is only available in dynamic mode. + */ + priv->lf_ratio = priv->dynamic_mode && ((rate / parent_rate) > 4096); + + return cs2000_bset(priv, FUNC_CFG2, LFRATIO_MASK, + priv->lf_ratio ? LFRATIO_20_12 : LFRATIO_12_20); } static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, @@ -315,7 +334,7 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, { int ret; - ret = cs2000_clk_in_bound_rate(priv, parent_rate); + ret = cs2000_select_ratio_mode(priv, rate, parent_rate); if (ret < 0) return ret; @@ -382,8 +401,13 @@ static void cs2000_disable(struct clk_hw *hw) static u8 cs2000_get_parent(struct clk_hw *hw) { - /* always return REF_CLK */ - return REF_CLK; + struct cs2000_priv *priv = hw_to_priv(hw); + + /* + * In dynamic mode, output rates are derived from CLK_IN. + * In static mode, CLK_IN is ignored, so we return REF_CLK instead. + */ + return priv->dynamic_mode ? CLK_IN : REF_CLK; } static const struct clk_ops cs2000_ops = { @@ -424,28 +448,41 @@ static int cs2000_clk_register(struct cs2000_priv *priv) const char *name = np->name; static const char *parent_names[CLK_MAX]; u32 aux_out = 0; + int ref_clk_rate; int ch = 0; /* it uses ch0 only at this point */ - int rate; int ret; of_property_read_string(np, "clock-output-names", &name); + priv->dynamic_mode = of_property_read_bool(np, "cirrus,dynamic-mode"); + dev_info(dev, "operating in %s mode\n", + priv->dynamic_mode ? "dynamic" : "static"); + of_property_read_u32(np, "cirrus,aux-output-source", &aux_out); ret = cs2000_bset(priv, DEVICE_CFG1, AUXOUTSRC_MASK, AUXOUTSRC(aux_out)); if (ret < 0) return ret; - /* - * set default rate as 1/1. - * otherwise .set_rate which setup ratio - * is never called if user requests 1/1 rate - */ - rate = clk_get_rate(priv->ref_clk); - ret = __cs2000_set_rate(priv, ch, rate, rate); + ref_clk_rate = clk_get_rate(priv->ref_clk); + ret = cs2000_ref_clk_bound_rate(priv, ref_clk_rate); if (ret < 0) return ret; + if (priv->dynamic_mode) { + /* Default to low-frequency mode to allow for large ratios */ + priv->lf_ratio = true; + } else { + /* + * set default rate as 1/1. + * otherwise .set_rate which setup ratio + * is never called if user requests 1/1 rate + */ + ret = __cs2000_set_rate(priv, ch, ref_clk_rate, ref_clk_rate); + if (ret < 0) + return ret; + } + parent_names[CLK_IN] = __clk_get_name(priv->clk_in); parent_names[REF_CLK] = __clk_get_name(priv->ref_clk); From b83688258605900413dd6c85ac9278eea3bda614 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 25 Jan 2022 10:33:34 +0100 Subject: [PATCH 13/26] clk: cs2000-cp: make clock skip setting configurable The clock skip function of this chip is not necessarily desirable in all hardware appliances. This patch makes the feature configurable through a device-tree property. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20220125093336.226787-8-daniel@zonque.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-cs2000-cp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index bd030e156d65..9f99e39b41f2 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -81,6 +81,7 @@ struct cs2000_priv { bool dynamic_mode; bool lf_ratio; + bool clk_skip; /* suspend/resume */ unsigned long saved_rate; @@ -133,7 +134,7 @@ static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable) return ret; ret = cs2000_bset(priv, FUNC_CFG1, CLKSKIPEN, - enable ? CLKSKIPEN : 0); + (enable && priv->clk_skip) ? CLKSKIPEN : 0); if (ret < 0) return ret; @@ -464,6 +465,8 @@ static int cs2000_clk_register(struct cs2000_priv *priv) if (ret < 0) return ret; + priv->clk_skip = of_property_read_bool(np, "cirrus,clock-skip"); + ref_clk_rate = clk_get_rate(priv->ref_clk); ret = cs2000_ref_clk_bound_rate(priv, ref_clk_rate); if (ret < 0) From 2f3d32fe9df80a65485c548a145916145fc99d68 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 25 Jan 2022 10:33:35 +0100 Subject: [PATCH 14/26] clk: cs2000-cp: freeze config during register fiddling Make sure to freeze the configuration of the chip during the programming of 32-bit registers. This avoids the processing of invalid intermediate states. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20220125093336.226787-9-daniel@zonque.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-cs2000-cp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index 9f99e39b41f2..1baf0595ba59 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -52,6 +52,7 @@ #define FRACNSRC_DYNAMIC (1 << 0) /* GLOBAL_CFG */ +#define FREEZE (1 << 7) #define ENDEV2 (0x1) /* FUNC_CFG1 */ @@ -335,6 +336,10 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, { int ret; + ret = cs2000_bset(priv, GLOBAL_CFG, FREEZE, FREEZE); + if (ret < 0) + return ret; + ret = cs2000_select_ratio_mode(priv, rate, parent_rate); if (ret < 0) return ret; @@ -347,6 +352,10 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, if (ret < 0) return ret; + ret = cs2000_bset(priv, GLOBAL_CFG, FREEZE, 0); + if (ret < 0) + return ret; + priv->saved_rate = rate; priv->saved_parent_rate = parent_rate; From 5edffb980519c3d59f93fdaff7249af83c3a3495 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 25 Jan 2022 10:33:36 +0100 Subject: [PATCH 15/26] clk: cs2000-cp: convert driver to regmap Regmap gives us caching, debugging infrastructure and other things for free and does away with open-coded bit-fiddling implementations. Signed-off-by: Daniel Mack Link: https://lore.kernel.org/r/20220125093336.226787-10-daniel@zonque.org Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 1 + drivers/clk/clk-cs2000-cp.c | 124 ++++++++++++++++++++---------------- 2 files changed, 69 insertions(+), 56 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index ad4256d54361..87ff6e2263f9 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -197,6 +197,7 @@ config COMMON_CLK_CDCE925 config COMMON_CLK_CS2000_CP tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier" depends on I2C + select REGMAP_I2C help If you say yes here you get support for the CS2000 clock multiplier. diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index 1baf0595ba59..dc5040a84dcc 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -11,6 +11,7 @@ #include #include #include +#include #define CH_MAX 4 #define RATIO_REG_SIZE 4 @@ -74,11 +75,36 @@ #define REF_CLK 1 #define CLK_MAX 2 +static bool cs2000_readable_reg(struct device *dev, unsigned int reg) +{ + return reg > 0; +} + +static bool cs2000_writeable_reg(struct device *dev, unsigned int reg) +{ + return reg != DEVICE_ID; +} + +static bool cs2000_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == DEVICE_CTRL; +} + +static const struct regmap_config cs2000_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = FUNC_CFG2, + .readable_reg = cs2000_readable_reg, + .writeable_reg = cs2000_writeable_reg, + .volatile_reg = cs2000_volatile_reg, +}; + struct cs2000_priv { struct clk_hw hw; struct i2c_client *client; struct clk *clk_in; struct clk *ref_clk; + struct regmap *regmap; bool dynamic_mode; bool lf_ratio; @@ -101,41 +127,22 @@ static const struct i2c_device_id cs2000_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs2000_id); -#define cs2000_read(priv, addr) \ - i2c_smbus_read_byte_data(priv_to_client(priv), addr) -#define cs2000_write(priv, addr, val) \ - i2c_smbus_write_byte_data(priv_to_client(priv), addr, val) - -static int cs2000_bset(struct cs2000_priv *priv, u8 addr, u8 mask, u8 val) -{ - s32 data; - - data = cs2000_read(priv, addr); - if (data < 0) - return data; - - data &= ~mask; - data |= (val & mask); - - return cs2000_write(priv, addr, data); -} - static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable) { int ret; - ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1, - enable ? ENDEV1 : 0); + ret = regmap_update_bits(priv->regmap, DEVICE_CFG1, ENDEV1, + enable ? ENDEV1 : 0); if (ret < 0) return ret; - ret = cs2000_bset(priv, GLOBAL_CFG, ENDEV2, - enable ? ENDEV2 : 0); + ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, ENDEV2, + enable ? ENDEV2 : 0); if (ret < 0) return ret; - ret = cs2000_bset(priv, FUNC_CFG1, CLKSKIPEN, - (enable && priv->clk_skip) ? CLKSKIPEN : 0); + ret = regmap_update_bits(priv->regmap, FUNC_CFG1, CLKSKIPEN, + (enable && priv->clk_skip) ? CLKSKIPEN : 0); if (ret < 0) return ret; @@ -156,21 +163,21 @@ static int cs2000_ref_clk_bound_rate(struct cs2000_priv *priv, else return -EINVAL; - return cs2000_bset(priv, FUNC_CFG1, - REFCLKDIV_MASK, - REFCLKDIV(val)); + return regmap_update_bits(priv->regmap, FUNC_CFG1, + REFCLKDIV_MASK, + REFCLKDIV(val)); } static int cs2000_wait_pll_lock(struct cs2000_priv *priv) { struct device *dev = priv_to_dev(priv); - s32 val; - unsigned int i; + unsigned int i, val; + int ret; for (i = 0; i < 256; i++) { - val = cs2000_read(priv, DEVICE_CTRL); - if (val < 0) - return val; + ret = regmap_read(priv->regmap, DEVICE_CTRL, &val); + if (ret < 0) + return ret; if (!(val & PLL_UNLOCK)) return 0; udelay(1); @@ -184,10 +191,10 @@ static int cs2000_wait_pll_lock(struct cs2000_priv *priv) static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable) { /* enable both AUX_OUT, CLK_OUT */ - return cs2000_bset(priv, DEVICE_CTRL, - (AUXOUTDIS | CLKOUTDIS), - enable ? 0 : - (AUXOUTDIS | CLKOUTDIS)); + return regmap_update_bits(priv->regmap, DEVICE_CTRL, + (AUXOUTDIS | CLKOUTDIS), + enable ? 0 : + (AUXOUTDIS | CLKOUTDIS)); } static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out, bool lf_ratio) @@ -235,7 +242,7 @@ static int cs2000_ratio_set(struct cs2000_priv *priv, val = cs2000_rate_to_ratio(rate_in, rate_out, priv->lf_ratio); for (i = 0; i < RATIO_REG_SIZE; i++) { - ret = cs2000_write(priv, + ret = regmap_write(priv->regmap, Ratio_Add(ch, i), Ratio_Val(val, i)); if (ret < 0) @@ -247,14 +254,14 @@ static int cs2000_ratio_set(struct cs2000_priv *priv, static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch) { - s32 tmp; + unsigned int tmp, i; u32 val; - unsigned int i; + int ret; val = 0; for (i = 0; i < RATIO_REG_SIZE; i++) { - tmp = cs2000_read(priv, Ratio_Add(ch, i)); - if (tmp < 0) + ret = regmap_read(priv->regmap, Ratio_Add(ch, i), &tmp); + if (ret < 0) return 0; val |= Val_Ratio(tmp, i); @@ -271,15 +278,15 @@ static int cs2000_ratio_select(struct cs2000_priv *priv, int ch) if (CH_SIZE_ERR(ch)) return -EINVAL; - ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch)); + ret = regmap_update_bits(priv->regmap, DEVICE_CFG1, RSEL_MASK, RSEL(ch)); if (ret < 0) return ret; fracnsrc = priv->dynamic_mode ? FRACNSRC_DYNAMIC : FRACNSRC_STATIC; - ret = cs2000_bset(priv, DEVICE_CFG2, - AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK, - LOCKCLK(ch) | fracnsrc); + ret = regmap_update_bits(priv->regmap, DEVICE_CFG2, + AUTORMOD | LOCKCLK_MASK | FRACNSRC_MASK, + LOCKCLK(ch) | fracnsrc); if (ret < 0) return ret; @@ -326,8 +333,8 @@ static int cs2000_select_ratio_mode(struct cs2000_priv *priv, */ priv->lf_ratio = priv->dynamic_mode && ((rate / parent_rate) > 4096); - return cs2000_bset(priv, FUNC_CFG2, LFRATIO_MASK, - priv->lf_ratio ? LFRATIO_20_12 : LFRATIO_12_20); + return regmap_update_bits(priv->regmap, FUNC_CFG2, LFRATIO_MASK, + priv->lf_ratio ? LFRATIO_20_12 : LFRATIO_12_20); } static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, @@ -336,7 +343,7 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, { int ret; - ret = cs2000_bset(priv, GLOBAL_CFG, FREEZE, FREEZE); + ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, FREEZE, FREEZE); if (ret < 0) return ret; @@ -352,7 +359,7 @@ static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, if (ret < 0) return ret; - ret = cs2000_bset(priv, GLOBAL_CFG, FREEZE, 0); + ret = regmap_update_bits(priv->regmap, GLOBAL_CFG, FREEZE, 0); if (ret < 0) return ret; @@ -469,8 +476,8 @@ static int cs2000_clk_register(struct cs2000_priv *priv) priv->dynamic_mode ? "dynamic" : "static"); of_property_read_u32(np, "cirrus,aux-output-source", &aux_out); - ret = cs2000_bset(priv, DEVICE_CFG1, - AUXOUTSRC_MASK, AUXOUTSRC(aux_out)); + ret = regmap_update_bits(priv->regmap, DEVICE_CFG1, + AUXOUTSRC_MASK, AUXOUTSRC(aux_out)); if (ret < 0) return ret; @@ -522,12 +529,13 @@ static int cs2000_clk_register(struct cs2000_priv *priv) static int cs2000_version_print(struct cs2000_priv *priv) { struct device *dev = priv_to_dev(priv); - s32 val; const char *revision; + unsigned int val; + int ret; - val = cs2000_read(priv, DEVICE_ID); - if (val < 0) - return val; + ret = regmap_read(priv->regmap, DEVICE_ID, &val); + if (ret < 0) + return ret; /* CS2000 should be 0x0 */ if (val >> 3) @@ -576,6 +584,10 @@ static int cs2000_probe(struct i2c_client *client, priv->client = client; i2c_set_clientdata(client, priv); + priv->regmap = devm_regmap_init_i2c(client, &cs2000_regmap_config); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + ret = cs2000_clk_get(priv); if (ret < 0) return ret; From 4decd2e54b61686787f36b727d2772e067a46ea5 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 26 Jan 2022 21:10:03 +0000 Subject: [PATCH 16/26] dt-bindings: clock: Add R9A07G054 CPG Clock and Reset Definitions Define RZ/V2L (R9A07G054) Clock Pulse Generator Core Clock and module clock outputs, as listed in Table 7.1.4.2 ("Clock List r1.0") and also add Reset definitions referring to registers CPG_RST_* in Section 7.2.3 ("Register configuration") of the RZ/V2L Hardware User's Manual (Rev. 1.00, Nov. 2021). Signed-off-by: Biju Das Signed-off-by: Lad Prabhakar Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220126211003.6675-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- include/dt-bindings/clock/r9a07g054-cpg.h | 229 ++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 include/dt-bindings/clock/r9a07g054-cpg.h diff --git a/include/dt-bindings/clock/r9a07g054-cpg.h b/include/dt-bindings/clock/r9a07g054-cpg.h new file mode 100644 index 000000000000..43f4dbda872c --- /dev/null +++ b/include/dt-bindings/clock/r9a07g054-cpg.h @@ -0,0 +1,229 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + * + * Copyright (C) 2022 Renesas Electronics Corp. + */ +#ifndef __DT_BINDINGS_CLOCK_R9A07G054_CPG_H__ +#define __DT_BINDINGS_CLOCK_R9A07G054_CPG_H__ + +#include + +/* R9A07G054 CPG Core Clocks */ +#define R9A07G054_CLK_I 0 +#define R9A07G054_CLK_I2 1 +#define R9A07G054_CLK_G 2 +#define R9A07G054_CLK_S0 3 +#define R9A07G054_CLK_S1 4 +#define R9A07G054_CLK_SPI0 5 +#define R9A07G054_CLK_SPI1 6 +#define R9A07G054_CLK_SD0 7 +#define R9A07G054_CLK_SD1 8 +#define R9A07G054_CLK_M0 9 +#define R9A07G054_CLK_M1 10 +#define R9A07G054_CLK_M2 11 +#define R9A07G054_CLK_M3 12 +#define R9A07G054_CLK_M4 13 +#define R9A07G054_CLK_HP 14 +#define R9A07G054_CLK_TSU 15 +#define R9A07G054_CLK_ZT 16 +#define R9A07G054_CLK_P0 17 +#define R9A07G054_CLK_P1 18 +#define R9A07G054_CLK_P2 19 +#define R9A07G054_CLK_AT 20 +#define R9A07G054_OSCCLK 21 +#define R9A07G054_CLK_P0_DIV2 22 +#define R9A07G054_CLK_DRP_M 23 +#define R9A07G054_CLK_DRP_D 24 +#define R9A07G054_CLK_DRP_A 25 + +/* R9A07G054 Module Clocks */ +#define R9A07G054_CA55_SCLK 0 +#define R9A07G054_CA55_PCLK 1 +#define R9A07G054_CA55_ATCLK 2 +#define R9A07G054_CA55_GICCLK 3 +#define R9A07G054_CA55_PERICLK 4 +#define R9A07G054_CA55_ACLK 5 +#define R9A07G054_CA55_TSCLK 6 +#define R9A07G054_GIC600_GICCLK 7 +#define R9A07G054_IA55_CLK 8 +#define R9A07G054_IA55_PCLK 9 +#define R9A07G054_MHU_PCLK 10 +#define R9A07G054_SYC_CNT_CLK 11 +#define R9A07G054_DMAC_ACLK 12 +#define R9A07G054_DMAC_PCLK 13 +#define R9A07G054_OSTM0_PCLK 14 +#define R9A07G054_OSTM1_PCLK 15 +#define R9A07G054_OSTM2_PCLK 16 +#define R9A07G054_MTU_X_MCK_MTU3 17 +#define R9A07G054_POE3_CLKM_POE 18 +#define R9A07G054_GPT_PCLK 19 +#define R9A07G054_POEG_A_CLKP 20 +#define R9A07G054_POEG_B_CLKP 21 +#define R9A07G054_POEG_C_CLKP 22 +#define R9A07G054_POEG_D_CLKP 23 +#define R9A07G054_WDT0_PCLK 24 +#define R9A07G054_WDT0_CLK 25 +#define R9A07G054_WDT1_PCLK 26 +#define R9A07G054_WDT1_CLK 27 +#define R9A07G054_WDT2_PCLK 28 +#define R9A07G054_WDT2_CLK 29 +#define R9A07G054_SPI_CLK2 30 +#define R9A07G054_SPI_CLK 31 +#define R9A07G054_SDHI0_IMCLK 32 +#define R9A07G054_SDHI0_IMCLK2 33 +#define R9A07G054_SDHI0_CLK_HS 34 +#define R9A07G054_SDHI0_ACLK 35 +#define R9A07G054_SDHI1_IMCLK 36 +#define R9A07G054_SDHI1_IMCLK2 37 +#define R9A07G054_SDHI1_CLK_HS 38 +#define R9A07G054_SDHI1_ACLK 39 +#define R9A07G054_GPU_CLK 40 +#define R9A07G054_GPU_AXI_CLK 41 +#define R9A07G054_GPU_ACE_CLK 42 +#define R9A07G054_ISU_ACLK 43 +#define R9A07G054_ISU_PCLK 44 +#define R9A07G054_H264_CLK_A 45 +#define R9A07G054_H264_CLK_P 46 +#define R9A07G054_CRU_SYSCLK 47 +#define R9A07G054_CRU_VCLK 48 +#define R9A07G054_CRU_PCLK 49 +#define R9A07G054_CRU_ACLK 50 +#define R9A07G054_MIPI_DSI_PLLCLK 51 +#define R9A07G054_MIPI_DSI_SYSCLK 52 +#define R9A07G054_MIPI_DSI_ACLK 53 +#define R9A07G054_MIPI_DSI_PCLK 54 +#define R9A07G054_MIPI_DSI_VCLK 55 +#define R9A07G054_MIPI_DSI_LPCLK 56 +#define R9A07G054_LCDC_CLK_A 57 +#define R9A07G054_LCDC_CLK_P 58 +#define R9A07G054_LCDC_CLK_D 59 +#define R9A07G054_SSI0_PCLK2 60 +#define R9A07G054_SSI0_PCLK_SFR 61 +#define R9A07G054_SSI1_PCLK2 62 +#define R9A07G054_SSI1_PCLK_SFR 63 +#define R9A07G054_SSI2_PCLK2 64 +#define R9A07G054_SSI2_PCLK_SFR 65 +#define R9A07G054_SSI3_PCLK2 66 +#define R9A07G054_SSI3_PCLK_SFR 67 +#define R9A07G054_SRC_CLKP 68 +#define R9A07G054_USB_U2H0_HCLK 69 +#define R9A07G054_USB_U2H1_HCLK 70 +#define R9A07G054_USB_U2P_EXR_CPUCLK 71 +#define R9A07G054_USB_PCLK 72 +#define R9A07G054_ETH0_CLK_AXI 73 +#define R9A07G054_ETH0_CLK_CHI 74 +#define R9A07G054_ETH1_CLK_AXI 75 +#define R9A07G054_ETH1_CLK_CHI 76 +#define R9A07G054_I2C0_PCLK 77 +#define R9A07G054_I2C1_PCLK 78 +#define R9A07G054_I2C2_PCLK 79 +#define R9A07G054_I2C3_PCLK 80 +#define R9A07G054_SCIF0_CLK_PCK 81 +#define R9A07G054_SCIF1_CLK_PCK 82 +#define R9A07G054_SCIF2_CLK_PCK 83 +#define R9A07G054_SCIF3_CLK_PCK 84 +#define R9A07G054_SCIF4_CLK_PCK 85 +#define R9A07G054_SCI0_CLKP 86 +#define R9A07G054_SCI1_CLKP 87 +#define R9A07G054_IRDA_CLKP 88 +#define R9A07G054_RSPI0_CLKB 89 +#define R9A07G054_RSPI1_CLKB 90 +#define R9A07G054_RSPI2_CLKB 91 +#define R9A07G054_CANFD_PCLK 92 +#define R9A07G054_GPIO_HCLK 93 +#define R9A07G054_ADC_ADCLK 94 +#define R9A07G054_ADC_PCLK 95 +#define R9A07G054_TSU_PCLK 96 +#define R9A07G054_STPAI_INITCLK 97 +#define R9A07G054_STPAI_ACLK 98 +#define R9A07G054_STPAI_MCLK 99 +#define R9A07G054_STPAI_DCLKIN 100 +#define R9A07G054_STPAI_ACLK_DRP 101 + +/* R9A07G054 Resets */ +#define R9A07G054_CA55_RST_1_0 0 +#define R9A07G054_CA55_RST_1_1 1 +#define R9A07G054_CA55_RST_3_0 2 +#define R9A07G054_CA55_RST_3_1 3 +#define R9A07G054_CA55_RST_4 4 +#define R9A07G054_CA55_RST_5 5 +#define R9A07G054_CA55_RST_6 6 +#define R9A07G054_CA55_RST_7 7 +#define R9A07G054_CA55_RST_8 8 +#define R9A07G054_CA55_RST_9 9 +#define R9A07G054_CA55_RST_10 10 +#define R9A07G054_CA55_RST_11 11 +#define R9A07G054_CA55_RST_12 12 +#define R9A07G054_GIC600_GICRESET_N 13 +#define R9A07G054_GIC600_DBG_GICRESET_N 14 +#define R9A07G054_IA55_RESETN 15 +#define R9A07G054_MHU_RESETN 16 +#define R9A07G054_DMAC_ARESETN 17 +#define R9A07G054_DMAC_RST_ASYNC 18 +#define R9A07G054_SYC_RESETN 19 +#define R9A07G054_OSTM0_PRESETZ 20 +#define R9A07G054_OSTM1_PRESETZ 21 +#define R9A07G054_OSTM2_PRESETZ 22 +#define R9A07G054_MTU_X_PRESET_MTU3 23 +#define R9A07G054_POE3_RST_M_REG 24 +#define R9A07G054_GPT_RST_C 25 +#define R9A07G054_POEG_A_RST 26 +#define R9A07G054_POEG_B_RST 27 +#define R9A07G054_POEG_C_RST 28 +#define R9A07G054_POEG_D_RST 29 +#define R9A07G054_WDT0_PRESETN 30 +#define R9A07G054_WDT1_PRESETN 31 +#define R9A07G054_WDT2_PRESETN 32 +#define R9A07G054_SPI_RST 33 +#define R9A07G054_SDHI0_IXRST 34 +#define R9A07G054_SDHI1_IXRST 35 +#define R9A07G054_GPU_RESETN 36 +#define R9A07G054_GPU_AXI_RESETN 37 +#define R9A07G054_GPU_ACE_RESETN 38 +#define R9A07G054_ISU_ARESETN 39 +#define R9A07G054_ISU_PRESETN 40 +#define R9A07G054_H264_X_RESET_VCP 41 +#define R9A07G054_H264_CP_PRESET_P 42 +#define R9A07G054_CRU_CMN_RSTB 43 +#define R9A07G054_CRU_PRESETN 44 +#define R9A07G054_CRU_ARESETN 45 +#define R9A07G054_MIPI_DSI_CMN_RSTB 46 +#define R9A07G054_MIPI_DSI_ARESET_N 47 +#define R9A07G054_MIPI_DSI_PRESET_N 48 +#define R9A07G054_LCDC_RESET_N 49 +#define R9A07G054_SSI0_RST_M2_REG 50 +#define R9A07G054_SSI1_RST_M2_REG 51 +#define R9A07G054_SSI2_RST_M2_REG 52 +#define R9A07G054_SSI3_RST_M2_REG 53 +#define R9A07G054_SRC_RST 54 +#define R9A07G054_USB_U2H0_HRESETN 55 +#define R9A07G054_USB_U2H1_HRESETN 56 +#define R9A07G054_USB_U2P_EXL_SYSRST 57 +#define R9A07G054_USB_PRESETN 58 +#define R9A07G054_ETH0_RST_HW_N 59 +#define R9A07G054_ETH1_RST_HW_N 60 +#define R9A07G054_I2C0_MRST 61 +#define R9A07G054_I2C1_MRST 62 +#define R9A07G054_I2C2_MRST 63 +#define R9A07G054_I2C3_MRST 64 +#define R9A07G054_SCIF0_RST_SYSTEM_N 65 +#define R9A07G054_SCIF1_RST_SYSTEM_N 66 +#define R9A07G054_SCIF2_RST_SYSTEM_N 67 +#define R9A07G054_SCIF3_RST_SYSTEM_N 68 +#define R9A07G054_SCIF4_RST_SYSTEM_N 69 +#define R9A07G054_SCI0_RST 70 +#define R9A07G054_SCI1_RST 71 +#define R9A07G054_IRDA_RST 72 +#define R9A07G054_RSPI0_RST 73 +#define R9A07G054_RSPI1_RST 74 +#define R9A07G054_RSPI2_RST 75 +#define R9A07G054_CANFD_RSTP_N 76 +#define R9A07G054_CANFD_RSTC_N 77 +#define R9A07G054_GPIO_RSTN 78 +#define R9A07G054_GPIO_PORT_RESETN 79 +#define R9A07G054_GPIO_SPARE_RESETN 80 +#define R9A07G054_ADC_PRESETN 81 +#define R9A07G054_ADC_ADRST_N 82 +#define R9A07G054_TSU_PRESETN 83 +#define R9A07G054_STPAI_ARESETN 84 + +#endif /* __DT_BINDINGS_CLOCK_R9A07G054_CPG_H__ */ From 678eb67513a963e5ce00a4ed6a07a5722bd1267e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 10 Jan 2022 13:46:51 +0000 Subject: [PATCH 17/26] dt-bindings: clock: renesas: Document RZ/V2L SoC Document the device tree binding for the Renesas RZ/V2L SoC. Signed-off-by: Biju Das Signed-off-by: Lad Prabhakar Acked-by: Rob Herring Link: https://lore.kernel.org/r/20220110134659.30424-5-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- .../bindings/clock/renesas,rzg2l-cpg.yaml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/renesas,rzg2l-cpg.yaml b/Documentation/devicetree/bindings/clock/renesas,rzg2l-cpg.yaml index 30b2e3d0d25d..bd3af8fc616b 100644 --- a/Documentation/devicetree/bindings/clock/renesas,rzg2l-cpg.yaml +++ b/Documentation/devicetree/bindings/clock/renesas,rzg2l-cpg.yaml @@ -4,13 +4,13 @@ $id: "http://devicetree.org/schemas/clock/renesas,rzg2l-cpg.yaml#" $schema: "http://devicetree.org/meta-schemas/core.yaml#" -title: Renesas RZ/G2L Clock Pulse Generator / Module Standby Mode +title: Renesas RZ/{G2L,V2L} Clock Pulse Generator / Module Standby Mode maintainers: - Geert Uytterhoeven description: | - On Renesas RZ/G2L SoC, the CPG (Clock Pulse Generator) and Module + On Renesas RZ/{G2L,V2L} SoC, the CPG (Clock Pulse Generator) and Module Standby Mode share the same register block. They provide the following functionalities: @@ -22,7 +22,9 @@ description: | properties: compatible: - const: renesas,r9a07g044-cpg # RZ/G2{L,LC} + enum: + - renesas,r9a07g044-cpg # RZ/G2{L,LC} + - renesas,r9a07g054-cpg # RZ/V2L reg: maxItems: 1 @@ -40,9 +42,9 @@ properties: description: | - For CPG core clocks, the two clock specifier cells must be "CPG_CORE" and a core clock reference, as defined in - + - For module clocks, the two clock specifier cells must be "CPG_MOD" and - a module number, as defined in the . + a module number, as defined in the . const: 2 '#power-domain-cells': @@ -56,7 +58,7 @@ properties: '#reset-cells': description: The single reset specifier cell must be the module number, as defined in - the . + the . const: 1 required: From a1bcf50a99dd1e40f0c6a963bd4f12547a89d4cd Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 5 Feb 2022 08:40:06 +0000 Subject: [PATCH 18/26] clk: renesas: rzg2l-cpg: Add support for RZ/V2L SoC The clock structure for RZ/V2L is almost identical to the RZ/G2L SoC. The only difference being that RZ/V2L has additional registers to control clocks and resets for the DRP-AI block. Reuse r9a07g044-cpg.c, as the clock IDs and reset IDs are the same between RZ/G2L and RZ/V2L, and add a separate r9a07g054_cpg_info to take care of the DRP-AI clocks/resets. Signed-off-by: Biju Das Signed-off-by: Lad Prabhakar Link: https://lore.kernel.org/r/20220205084006.7142-1-biju.das.jz@bp.renesas.com Link: https://lore.kernel.org/r/20220209203411.22332-1-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/Kconfig | 7 +- drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/r9a07g044-cpg.c | 426 +++++++++++++++------------- drivers/clk/renesas/rzg2l-cpg.c | 6 + drivers/clk/renesas/rzg2l-cpg.h | 1 + 5 files changed, 250 insertions(+), 191 deletions(-) diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index be6e6ae7448c..c281f3af5716 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -34,6 +34,7 @@ config CLK_RENESAS select CLK_R8A779F0 if ARCH_R8A779F0 select CLK_R9A06G032 if ARCH_R9A06G032 select CLK_R9A07G044 if ARCH_R9A07G044 + select CLK_R9A07G054 if ARCH_R9A07G054 select CLK_SH73A0 if ARCH_SH73A0 if CLK_RENESAS @@ -163,6 +164,10 @@ config CLK_R9A07G044 bool "RZ/G2L clock support" if COMPILE_TEST select CLK_RZG2L +config CLK_R9A07G054 + bool "RZ/V2L clock support" if COMPILE_TEST + select CLK_RZG2L + config CLK_SH73A0 bool "SH-Mobile AG5 clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP @@ -195,7 +200,7 @@ config CLK_RCAR_USB2_CLOCK_SEL This is a driver for R-Car USB2 clock selector config CLK_RZG2L - bool "Renesas RZ/G2L family clock support" if COMPILE_TEST + bool "Renesas RZ/{G2L,V2L} family clock support" if COMPILE_TEST select RESET_CONTROLLER # Generic diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 8b34db1a328c..d5e571699a30 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_CLK_R8A779A0) += r8a779a0-cpg-mssr.o obj-$(CONFIG_CLK_R8A779F0) += r8a779f0-cpg-mssr.o obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o obj-$(CONFIG_CLK_R9A07G044) += r9a07g044-cpg.o +obj-$(CONFIG_CLK_R9A07G054) += r9a07g044-cpg.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o # Family diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c index 46359afef0d4..bdfabb992a20 100644 --- a/drivers/clk/renesas/r9a07g044-cpg.c +++ b/drivers/clk/renesas/r9a07g044-cpg.c @@ -11,12 +11,13 @@ #include #include +#include #include "rzg2l-cpg.h" enum clk_ids { /* Core Clock Outputs exported to DT */ - LAST_DT_CORE_CLK = R9A07G044_CLK_P0_DIV2, + LAST_DT_CORE_CLK = R9A07G054_CLK_DRP_A, /* External Input Clocks */ CLK_EXTAL, @@ -80,200 +81,222 @@ static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" }; -static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = { - /* External Clock Inputs */ - DEF_INPUT("extal", CLK_EXTAL), +static const struct { + struct cpg_core_clk common[44]; +#ifdef CONFIG_CLK_R9A07G054 + struct cpg_core_clk drp[0]; +#endif +} core_clks __initconst = { + .common = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), - /* Internal Core Clocks */ - DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1), - DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000), - DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)), - DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3), - DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3), - DEF_FIXED(".pll3_400", CLK_PLL3_400, CLK_PLL3, 1, 4), - DEF_FIXED(".pll3_533", CLK_PLL3_533, CLK_PLL3, 1, 3), + /* Internal Core Clocks */ + DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1), + DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000), + DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)), + DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3), + DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3), + DEF_FIXED(".pll3_400", CLK_PLL3_400, CLK_PLL3, 1, 4), + DEF_FIXED(".pll3_533", CLK_PLL3_533, CLK_PLL3, 1, 3), - DEF_FIXED(".pll5", CLK_PLL5, CLK_EXTAL, 125, 1), - DEF_FIXED(".pll5_fout3", CLK_PLL5_FOUT3, CLK_PLL5, 1, 6), + DEF_FIXED(".pll5", CLK_PLL5, CLK_EXTAL, 125, 1), + DEF_FIXED(".pll5_fout3", CLK_PLL5_FOUT3, CLK_PLL5, 1, 6), - DEF_FIXED(".pll6", CLK_PLL6, CLK_EXTAL, 125, 6), + DEF_FIXED(".pll6", CLK_PLL6, CLK_EXTAL, 125, 6), - DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2), - DEF_FIXED(".clk_800", CLK_PLL2_800, CLK_PLL2, 1, 2), - DEF_FIXED(".clk_533", CLK_PLL2_SDHI_533, CLK_PLL2, 1, 3), - DEF_FIXED(".clk_400", CLK_PLL2_SDHI_400, CLK_PLL2_800, 1, 2), - DEF_FIXED(".clk_266", CLK_PLL2_SDHI_266, CLK_PLL2_SDHI_533, 1, 2), + DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2), + DEF_FIXED(".clk_800", CLK_PLL2_800, CLK_PLL2, 1, 2), + DEF_FIXED(".clk_533", CLK_PLL2_SDHI_533, CLK_PLL2, 1, 3), + DEF_FIXED(".clk_400", CLK_PLL2_SDHI_400, CLK_PLL2_800, 1, 2), + DEF_FIXED(".clk_266", CLK_PLL2_SDHI_266, CLK_PLL2_SDHI_533, 1, 2), - DEF_FIXED(".pll2_div2_8", CLK_PLL2_DIV2_8, CLK_PLL2_DIV2, 1, 8), - DEF_FIXED(".pll2_div2_10", CLK_PLL2_DIV2_10, CLK_PLL2_DIV2, 1, 10), + DEF_FIXED(".pll2_div2_8", CLK_PLL2_DIV2_8, CLK_PLL2_DIV2, 1, 8), + DEF_FIXED(".pll2_div2_10", CLK_PLL2_DIV2_10, CLK_PLL2_DIV2, 1, 10), - DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2), - DEF_FIXED(".pll3_div2_2", CLK_PLL3_DIV2_2, CLK_PLL3_DIV2, 1, 2), - DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4), - DEF_FIXED(".pll3_div2_4_2", CLK_PLL3_DIV2_4_2, CLK_PLL3_DIV2_4, 1, 2), - DEF_MUX(".sel_pll3_3", CLK_SEL_PLL3_3, SEL_PLL3_3, - sel_pll3_3, ARRAY_SIZE(sel_pll3_3), 0, CLK_MUX_READ_ONLY), - DEF_DIV("divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3, - DIVPL3C, dtable_1_32, CLK_DIVIDER_HIWORD_MASK), + DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2), + DEF_FIXED(".pll3_div2_2", CLK_PLL3_DIV2_2, CLK_PLL3_DIV2, 1, 2), + DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4), + DEF_FIXED(".pll3_div2_4_2", CLK_PLL3_DIV2_4_2, CLK_PLL3_DIV2_4, 1, 2), + DEF_MUX(".sel_pll3_3", CLK_SEL_PLL3_3, SEL_PLL3_3, + sel_pll3_3, ARRAY_SIZE(sel_pll3_3), 0, CLK_MUX_READ_ONLY), + DEF_DIV("divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3, + DIVPL3C, dtable_1_32, CLK_DIVIDER_HIWORD_MASK), - DEF_FIXED(".pll5_250", CLK_PLL5_250, CLK_PLL5_FOUT3, 1, 2), - DEF_FIXED(".pll6_250", CLK_PLL6_250, CLK_PLL6, 1, 2), - DEF_MUX(".sel_gpu2", CLK_SEL_GPU2, SEL_GPU2, - sel_gpu2, ARRAY_SIZE(sel_gpu2), 0, CLK_MUX_READ_ONLY), + DEF_FIXED(".pll5_250", CLK_PLL5_250, CLK_PLL5_FOUT3, 1, 2), + DEF_FIXED(".pll6_250", CLK_PLL6_250, CLK_PLL6, 1, 2), + DEF_MUX(".sel_gpu2", CLK_SEL_GPU2, SEL_GPU2, + sel_gpu2, ARRAY_SIZE(sel_gpu2), 0, CLK_MUX_READ_ONLY), - /* Core output clk */ - DEF_DIV("I", R9A07G044_CLK_I, CLK_PLL1, DIVPL1A, dtable_1_8, - CLK_DIVIDER_HIWORD_MASK), - DEF_DIV("P0", R9A07G044_CLK_P0, CLK_PLL2_DIV2_8, DIVPL2A, - dtable_1_32, CLK_DIVIDER_HIWORD_MASK), - DEF_FIXED("P0_DIV2", R9A07G044_CLK_P0_DIV2, R9A07G044_CLK_P0, 1, 2), - DEF_FIXED("TSU", R9A07G044_CLK_TSU, CLK_PLL2_DIV2_10, 1, 1), - DEF_DIV("P1", R9A07G044_CLK_P1, CLK_PLL3_DIV2_4, - DIVPL3B, dtable_1_32, CLK_DIVIDER_HIWORD_MASK), - DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A07G044_CLK_P1, 1, 2), - DEF_DIV("P2", R9A07G044_CLK_P2, CLK_PLL3_DIV2_4_2, - DIVPL3A, dtable_1_32, CLK_DIVIDER_HIWORD_MASK), - DEF_FIXED("M0", R9A07G044_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), - DEF_FIXED("ZT", R9A07G044_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1), - DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2, - sel_pll6_2, ARRAY_SIZE(sel_pll6_2), 0, CLK_MUX_HIWORD_MASK), - DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), - DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), - DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, - sel_shdi, ARRAY_SIZE(sel_shdi)), - DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, - sel_shdi, ARRAY_SIZE(sel_shdi)), - DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), - DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), - DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8, - CLK_DIVIDER_HIWORD_MASK), + /* Core output clk */ + DEF_DIV("I", R9A07G044_CLK_I, CLK_PLL1, DIVPL1A, dtable_1_8, + CLK_DIVIDER_HIWORD_MASK), + DEF_DIV("P0", R9A07G044_CLK_P0, CLK_PLL2_DIV2_8, DIVPL2A, + dtable_1_32, CLK_DIVIDER_HIWORD_MASK), + DEF_FIXED("P0_DIV2", R9A07G044_CLK_P0_DIV2, R9A07G044_CLK_P0, 1, 2), + DEF_FIXED("TSU", R9A07G044_CLK_TSU, CLK_PLL2_DIV2_10, 1, 1), + DEF_DIV("P1", R9A07G044_CLK_P1, CLK_PLL3_DIV2_4, + DIVPL3B, dtable_1_32, CLK_DIVIDER_HIWORD_MASK), + DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A07G044_CLK_P1, 1, 2), + DEF_DIV("P2", R9A07G044_CLK_P2, CLK_PLL3_DIV2_4_2, + DIVPL3A, dtable_1_32, CLK_DIVIDER_HIWORD_MASK), + DEF_FIXED("M0", R9A07G044_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), + DEF_FIXED("ZT", R9A07G044_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1), + DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2, + sel_pll6_2, ARRAY_SIZE(sel_pll6_2), 0, CLK_MUX_HIWORD_MASK), + DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), + DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), + DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, + sel_shdi, ARRAY_SIZE(sel_shdi)), + DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, + sel_shdi, ARRAY_SIZE(sel_shdi)), + DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), + DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), + DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8, + CLK_DIVIDER_HIWORD_MASK), + }, +#ifdef CONFIG_CLK_R9A07G054 + .drp = { + }, +#endif }; -static struct rzg2l_mod_clk r9a07g044_mod_clks[] = { - DEF_MOD("gic", R9A07G044_GIC600_GICCLK, R9A07G044_CLK_P1, - 0x514, 0), - DEF_MOD("ia55_pclk", R9A07G044_IA55_PCLK, R9A07G044_CLK_P2, - 0x518, 0), - DEF_MOD("ia55_clk", R9A07G044_IA55_CLK, R9A07G044_CLK_P1, - 0x518, 1), - DEF_MOD("dmac_aclk", R9A07G044_DMAC_ACLK, R9A07G044_CLK_P1, - 0x52c, 0), - DEF_MOD("dmac_pclk", R9A07G044_DMAC_PCLK, CLK_P1_DIV2, - 0x52c, 1), - DEF_MOD("ostm0_pclk", R9A07G044_OSTM0_PCLK, R9A07G044_CLK_P0, - 0x534, 0), - DEF_MOD("ostm1_clk", R9A07G044_OSTM1_PCLK, R9A07G044_CLK_P0, - 0x534, 1), - DEF_MOD("ostm2_pclk", R9A07G044_OSTM2_PCLK, R9A07G044_CLK_P0, - 0x534, 2), - DEF_MOD("wdt0_pclk", R9A07G044_WDT0_PCLK, R9A07G044_CLK_P0, - 0x548, 0), - DEF_MOD("wdt0_clk", R9A07G044_WDT0_CLK, R9A07G044_OSCCLK, - 0x548, 1), - DEF_MOD("wdt1_pclk", R9A07G044_WDT1_PCLK, R9A07G044_CLK_P0, - 0x548, 2), - DEF_MOD("wdt1_clk", R9A07G044_WDT1_CLK, R9A07G044_OSCCLK, - 0x548, 3), - DEF_MOD("wdt2_pclk", R9A07G044_WDT2_PCLK, R9A07G044_CLK_P0, - 0x548, 4), - DEF_MOD("wdt2_clk", R9A07G044_WDT2_CLK, R9A07G044_OSCCLK, - 0x548, 5), - DEF_MOD("spi_clk2", R9A07G044_SPI_CLK2, R9A07G044_CLK_SPI1, - 0x550, 0), - DEF_MOD("spi_clk", R9A07G044_SPI_CLK, R9A07G044_CLK_SPI0, - 0x550, 1), - DEF_MOD("sdhi0_imclk", R9A07G044_SDHI0_IMCLK, CLK_SD0_DIV4, - 0x554, 0), - DEF_MOD("sdhi0_imclk2", R9A07G044_SDHI0_IMCLK2, CLK_SD0_DIV4, - 0x554, 1), - DEF_MOD("sdhi0_clk_hs", R9A07G044_SDHI0_CLK_HS, R9A07G044_CLK_SD0, - 0x554, 2), - DEF_MOD("sdhi0_aclk", R9A07G044_SDHI0_ACLK, R9A07G044_CLK_P1, - 0x554, 3), - DEF_MOD("sdhi1_imclk", R9A07G044_SDHI1_IMCLK, CLK_SD1_DIV4, - 0x554, 4), - DEF_MOD("sdhi1_imclk2", R9A07G044_SDHI1_IMCLK2, CLK_SD1_DIV4, - 0x554, 5), - DEF_MOD("sdhi1_clk_hs", R9A07G044_SDHI1_CLK_HS, R9A07G044_CLK_SD1, - 0x554, 6), - DEF_MOD("sdhi1_aclk", R9A07G044_SDHI1_ACLK, R9A07G044_CLK_P1, - 0x554, 7), - DEF_MOD("gpu_clk", R9A07G044_GPU_CLK, R9A07G044_CLK_G, - 0x558, 0), - DEF_MOD("gpu_axi_clk", R9A07G044_GPU_AXI_CLK, R9A07G044_CLK_P1, - 0x558, 1), - DEF_MOD("gpu_ace_clk", R9A07G044_GPU_ACE_CLK, R9A07G044_CLK_P1, - 0x558, 2), - DEF_MOD("ssi0_pclk", R9A07G044_SSI0_PCLK2, R9A07G044_CLK_P0, - 0x570, 0), - DEF_MOD("ssi0_sfr", R9A07G044_SSI0_PCLK_SFR, R9A07G044_CLK_P0, - 0x570, 1), - DEF_MOD("ssi1_pclk", R9A07G044_SSI1_PCLK2, R9A07G044_CLK_P0, - 0x570, 2), - DEF_MOD("ssi1_sfr", R9A07G044_SSI1_PCLK_SFR, R9A07G044_CLK_P0, - 0x570, 3), - DEF_MOD("ssi2_pclk", R9A07G044_SSI2_PCLK2, R9A07G044_CLK_P0, - 0x570, 4), - DEF_MOD("ssi2_sfr", R9A07G044_SSI2_PCLK_SFR, R9A07G044_CLK_P0, - 0x570, 5), - DEF_MOD("ssi3_pclk", R9A07G044_SSI3_PCLK2, R9A07G044_CLK_P0, - 0x570, 6), - DEF_MOD("ssi3_sfr", R9A07G044_SSI3_PCLK_SFR, R9A07G044_CLK_P0, - 0x570, 7), - DEF_MOD("usb0_host", R9A07G044_USB_U2H0_HCLK, R9A07G044_CLK_P1, - 0x578, 0), - DEF_MOD("usb1_host", R9A07G044_USB_U2H1_HCLK, R9A07G044_CLK_P1, - 0x578, 1), - DEF_MOD("usb0_func", R9A07G044_USB_U2P_EXR_CPUCLK, R9A07G044_CLK_P1, - 0x578, 2), - DEF_MOD("usb_pclk", R9A07G044_USB_PCLK, R9A07G044_CLK_P1, - 0x578, 3), - DEF_COUPLED("eth0_axi", R9A07G044_ETH0_CLK_AXI, R9A07G044_CLK_M0, - 0x57c, 0), - DEF_COUPLED("eth0_chi", R9A07G044_ETH0_CLK_CHI, R9A07G044_CLK_ZT, - 0x57c, 0), - DEF_COUPLED("eth1_axi", R9A07G044_ETH1_CLK_AXI, R9A07G044_CLK_M0, - 0x57c, 1), - DEF_COUPLED("eth1_chi", R9A07G044_ETH1_CLK_CHI, R9A07G044_CLK_ZT, - 0x57c, 1), - DEF_MOD("i2c0", R9A07G044_I2C0_PCLK, R9A07G044_CLK_P0, - 0x580, 0), - DEF_MOD("i2c1", R9A07G044_I2C1_PCLK, R9A07G044_CLK_P0, - 0x580, 1), - DEF_MOD("i2c2", R9A07G044_I2C2_PCLK, R9A07G044_CLK_P0, - 0x580, 2), - DEF_MOD("i2c3", R9A07G044_I2C3_PCLK, R9A07G044_CLK_P0, - 0x580, 3), - DEF_MOD("scif0", R9A07G044_SCIF0_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 0), - DEF_MOD("scif1", R9A07G044_SCIF1_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 1), - DEF_MOD("scif2", R9A07G044_SCIF2_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 2), - DEF_MOD("scif3", R9A07G044_SCIF3_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 3), - DEF_MOD("scif4", R9A07G044_SCIF4_CLK_PCK, R9A07G044_CLK_P0, - 0x584, 4), - DEF_MOD("sci0", R9A07G044_SCI0_CLKP, R9A07G044_CLK_P0, - 0x588, 0), - DEF_MOD("sci1", R9A07G044_SCI1_CLKP, R9A07G044_CLK_P0, - 0x588, 1), - DEF_MOD("rspi0", R9A07G044_RSPI0_CLKB, R9A07G044_CLK_P0, - 0x590, 0), - DEF_MOD("rspi1", R9A07G044_RSPI1_CLKB, R9A07G044_CLK_P0, - 0x590, 1), - DEF_MOD("rspi2", R9A07G044_RSPI2_CLKB, R9A07G044_CLK_P0, - 0x590, 2), - DEF_MOD("canfd", R9A07G044_CANFD_PCLK, R9A07G044_CLK_P0, - 0x594, 0), - DEF_MOD("gpio", R9A07G044_GPIO_HCLK, R9A07G044_OSCCLK, - 0x598, 0), - DEF_MOD("adc_adclk", R9A07G044_ADC_ADCLK, R9A07G044_CLK_TSU, - 0x5a8, 0), - DEF_MOD("adc_pclk", R9A07G044_ADC_PCLK, R9A07G044_CLK_P0, - 0x5a8, 1), - DEF_MOD("tsu_pclk", R9A07G044_TSU_PCLK, R9A07G044_CLK_TSU, - 0x5ac, 0), +static const struct { + struct rzg2l_mod_clk common[62]; +#ifdef CONFIG_CLK_R9A07G054 + struct rzg2l_mod_clk drp[0]; +#endif +} mod_clks = { + .common = { + DEF_MOD("gic", R9A07G044_GIC600_GICCLK, R9A07G044_CLK_P1, + 0x514, 0), + DEF_MOD("ia55_pclk", R9A07G044_IA55_PCLK, R9A07G044_CLK_P2, + 0x518, 0), + DEF_MOD("ia55_clk", R9A07G044_IA55_CLK, R9A07G044_CLK_P1, + 0x518, 1), + DEF_MOD("dmac_aclk", R9A07G044_DMAC_ACLK, R9A07G044_CLK_P1, + 0x52c, 0), + DEF_MOD("dmac_pclk", R9A07G044_DMAC_PCLK, CLK_P1_DIV2, + 0x52c, 1), + DEF_MOD("ostm0_pclk", R9A07G044_OSTM0_PCLK, R9A07G044_CLK_P0, + 0x534, 0), + DEF_MOD("ostm1_clk", R9A07G044_OSTM1_PCLK, R9A07G044_CLK_P0, + 0x534, 1), + DEF_MOD("ostm2_pclk", R9A07G044_OSTM2_PCLK, R9A07G044_CLK_P0, + 0x534, 2), + DEF_MOD("wdt0_pclk", R9A07G044_WDT0_PCLK, R9A07G044_CLK_P0, + 0x548, 0), + DEF_MOD("wdt0_clk", R9A07G044_WDT0_CLK, R9A07G044_OSCCLK, + 0x548, 1), + DEF_MOD("wdt1_pclk", R9A07G044_WDT1_PCLK, R9A07G044_CLK_P0, + 0x548, 2), + DEF_MOD("wdt1_clk", R9A07G044_WDT1_CLK, R9A07G044_OSCCLK, + 0x548, 3), + DEF_MOD("wdt2_pclk", R9A07G044_WDT2_PCLK, R9A07G044_CLK_P0, + 0x548, 4), + DEF_MOD("wdt2_clk", R9A07G044_WDT2_CLK, R9A07G044_OSCCLK, + 0x548, 5), + DEF_MOD("spi_clk2", R9A07G044_SPI_CLK2, R9A07G044_CLK_SPI1, + 0x550, 0), + DEF_MOD("spi_clk", R9A07G044_SPI_CLK, R9A07G044_CLK_SPI0, + 0x550, 1), + DEF_MOD("sdhi0_imclk", R9A07G044_SDHI0_IMCLK, CLK_SD0_DIV4, + 0x554, 0), + DEF_MOD("sdhi0_imclk2", R9A07G044_SDHI0_IMCLK2, CLK_SD0_DIV4, + 0x554, 1), + DEF_MOD("sdhi0_clk_hs", R9A07G044_SDHI0_CLK_HS, R9A07G044_CLK_SD0, + 0x554, 2), + DEF_MOD("sdhi0_aclk", R9A07G044_SDHI0_ACLK, R9A07G044_CLK_P1, + 0x554, 3), + DEF_MOD("sdhi1_imclk", R9A07G044_SDHI1_IMCLK, CLK_SD1_DIV4, + 0x554, 4), + DEF_MOD("sdhi1_imclk2", R9A07G044_SDHI1_IMCLK2, CLK_SD1_DIV4, + 0x554, 5), + DEF_MOD("sdhi1_clk_hs", R9A07G044_SDHI1_CLK_HS, R9A07G044_CLK_SD1, + 0x554, 6), + DEF_MOD("sdhi1_aclk", R9A07G044_SDHI1_ACLK, R9A07G044_CLK_P1, + 0x554, 7), + DEF_MOD("gpu_clk", R9A07G044_GPU_CLK, R9A07G044_CLK_G, + 0x558, 0), + DEF_MOD("gpu_axi_clk", R9A07G044_GPU_AXI_CLK, R9A07G044_CLK_P1, + 0x558, 1), + DEF_MOD("gpu_ace_clk", R9A07G044_GPU_ACE_CLK, R9A07G044_CLK_P1, + 0x558, 2), + DEF_MOD("ssi0_pclk", R9A07G044_SSI0_PCLK2, R9A07G044_CLK_P0, + 0x570, 0), + DEF_MOD("ssi0_sfr", R9A07G044_SSI0_PCLK_SFR, R9A07G044_CLK_P0, + 0x570, 1), + DEF_MOD("ssi1_pclk", R9A07G044_SSI1_PCLK2, R9A07G044_CLK_P0, + 0x570, 2), + DEF_MOD("ssi1_sfr", R9A07G044_SSI1_PCLK_SFR, R9A07G044_CLK_P0, + 0x570, 3), + DEF_MOD("ssi2_pclk", R9A07G044_SSI2_PCLK2, R9A07G044_CLK_P0, + 0x570, 4), + DEF_MOD("ssi2_sfr", R9A07G044_SSI2_PCLK_SFR, R9A07G044_CLK_P0, + 0x570, 5), + DEF_MOD("ssi3_pclk", R9A07G044_SSI3_PCLK2, R9A07G044_CLK_P0, + 0x570, 6), + DEF_MOD("ssi3_sfr", R9A07G044_SSI3_PCLK_SFR, R9A07G044_CLK_P0, + 0x570, 7), + DEF_MOD("usb0_host", R9A07G044_USB_U2H0_HCLK, R9A07G044_CLK_P1, + 0x578, 0), + DEF_MOD("usb1_host", R9A07G044_USB_U2H1_HCLK, R9A07G044_CLK_P1, + 0x578, 1), + DEF_MOD("usb0_func", R9A07G044_USB_U2P_EXR_CPUCLK, R9A07G044_CLK_P1, + 0x578, 2), + DEF_MOD("usb_pclk", R9A07G044_USB_PCLK, R9A07G044_CLK_P1, + 0x578, 3), + DEF_COUPLED("eth0_axi", R9A07G044_ETH0_CLK_AXI, R9A07G044_CLK_M0, + 0x57c, 0), + DEF_COUPLED("eth0_chi", R9A07G044_ETH0_CLK_CHI, R9A07G044_CLK_ZT, + 0x57c, 0), + DEF_COUPLED("eth1_axi", R9A07G044_ETH1_CLK_AXI, R9A07G044_CLK_M0, + 0x57c, 1), + DEF_COUPLED("eth1_chi", R9A07G044_ETH1_CLK_CHI, R9A07G044_CLK_ZT, + 0x57c, 1), + DEF_MOD("i2c0", R9A07G044_I2C0_PCLK, R9A07G044_CLK_P0, + 0x580, 0), + DEF_MOD("i2c1", R9A07G044_I2C1_PCLK, R9A07G044_CLK_P0, + 0x580, 1), + DEF_MOD("i2c2", R9A07G044_I2C2_PCLK, R9A07G044_CLK_P0, + 0x580, 2), + DEF_MOD("i2c3", R9A07G044_I2C3_PCLK, R9A07G044_CLK_P0, + 0x580, 3), + DEF_MOD("scif0", R9A07G044_SCIF0_CLK_PCK, R9A07G044_CLK_P0, + 0x584, 0), + DEF_MOD("scif1", R9A07G044_SCIF1_CLK_PCK, R9A07G044_CLK_P0, + 0x584, 1), + DEF_MOD("scif2", R9A07G044_SCIF2_CLK_PCK, R9A07G044_CLK_P0, + 0x584, 2), + DEF_MOD("scif3", R9A07G044_SCIF3_CLK_PCK, R9A07G044_CLK_P0, + 0x584, 3), + DEF_MOD("scif4", R9A07G044_SCIF4_CLK_PCK, R9A07G044_CLK_P0, + 0x584, 4), + DEF_MOD("sci0", R9A07G044_SCI0_CLKP, R9A07G044_CLK_P0, + 0x588, 0), + DEF_MOD("sci1", R9A07G044_SCI1_CLKP, R9A07G044_CLK_P0, + 0x588, 1), + DEF_MOD("rspi0", R9A07G044_RSPI0_CLKB, R9A07G044_CLK_P0, + 0x590, 0), + DEF_MOD("rspi1", R9A07G044_RSPI1_CLKB, R9A07G044_CLK_P0, + 0x590, 1), + DEF_MOD("rspi2", R9A07G044_RSPI2_CLKB, R9A07G044_CLK_P0, + 0x590, 2), + DEF_MOD("canfd", R9A07G044_CANFD_PCLK, R9A07G044_CLK_P0, + 0x594, 0), + DEF_MOD("gpio", R9A07G044_GPIO_HCLK, R9A07G044_OSCCLK, + 0x598, 0), + DEF_MOD("adc_adclk", R9A07G044_ADC_ADCLK, R9A07G044_CLK_TSU, + 0x5a8, 0), + DEF_MOD("adc_pclk", R9A07G044_ADC_PCLK, R9A07G044_CLK_P0, + 0x5a8, 1), + DEF_MOD("tsu_pclk", R9A07G044_TSU_PCLK, R9A07G044_CLK_TSU, + 0x5ac, 0), + }, +#ifdef CONFIG_CLK_R9A07G054 + .drp = { + }, +#endif }; static struct rzg2l_reset r9a07g044_resets[] = { @@ -336,8 +359,8 @@ static const unsigned int r9a07g044_crit_mod_clks[] __initconst = { const struct rzg2l_cpg_info r9a07g044_cpg_info = { /* Core Clocks */ - .core_clks = r9a07g044_core_clks, - .num_core_clks = ARRAY_SIZE(r9a07g044_core_clks), + .core_clks = core_clks.common, + .num_core_clks = ARRAY_SIZE(core_clks.common), .last_dt_core_clk = LAST_DT_CORE_CLK, .num_total_core_clks = MOD_CLK_BASE, @@ -346,11 +369,34 @@ const struct rzg2l_cpg_info r9a07g044_cpg_info = { .num_crit_mod_clks = ARRAY_SIZE(r9a07g044_crit_mod_clks), /* Module Clocks */ - .mod_clks = r9a07g044_mod_clks, - .num_mod_clks = ARRAY_SIZE(r9a07g044_mod_clks), + .mod_clks = mod_clks.common, + .num_mod_clks = ARRAY_SIZE(mod_clks.common), .num_hw_mod_clks = R9A07G044_TSU_PCLK + 1, /* Resets */ .resets = r9a07g044_resets, - .num_resets = ARRAY_SIZE(r9a07g044_resets), + .num_resets = R9A07G044_TSU_PRESETN + 1, /* Last reset ID + 1 */ }; + +#ifdef CONFIG_CLK_R9A07G054 +const struct rzg2l_cpg_info r9a07g054_cpg_info = { + /* Core Clocks */ + .core_clks = core_clks.common, + .num_core_clks = ARRAY_SIZE(core_clks.common) + ARRAY_SIZE(core_clks.drp), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Critical Module Clocks */ + .crit_mod_clks = r9a07g044_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r9a07g044_crit_mod_clks), + + /* Module Clocks */ + .mod_clks = mod_clks.common, + .num_mod_clks = ARRAY_SIZE(mod_clks.common) + ARRAY_SIZE(mod_clks.drp), + .num_hw_mod_clks = R9A07G054_STPAI_ACLK_DRP + 1, + + /* Resets */ + .resets = r9a07g044_resets, + .num_resets = R9A07G054_STPAI_ARESETN + 1, /* Last reset ID + 1 */ +}; +#endif diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index edd0abe34a37..486d0656c58a 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -952,6 +952,12 @@ static const struct of_device_id rzg2l_cpg_match[] = { .compatible = "renesas,r9a07g044-cpg", .data = &r9a07g044_cpg_info, }, +#endif +#ifdef CONFIG_CLK_R9A07G054 + { + .compatible = "renesas,r9a07g054-cpg", + .data = &r9a07g054_cpg_info, + }, #endif { /* sentinel */ } }; diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 5729d102034b..ce657beaf160 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -203,5 +203,6 @@ struct rzg2l_cpg_info { }; extern const struct rzg2l_cpg_info r9a07g044_cpg_info; +extern const struct rzg2l_cpg_info r9a07g054_cpg_info; #endif From 691419f90f7fb8a6f247b477cb539644e11431da Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 7 Jan 2022 15:34:36 +0100 Subject: [PATCH 19/26] clk: renesas: r8a779f0: Fix RSW2 clock divider According to Section 8.1.2 Figure 8.1.1 ("Block Diagram of CPG"), Note 22 ("RSW2 divider"), and Table 8.1.4d ("Lists of CPG clocks generated from CPGMA1"), the RSwitch2 and PCI Express clock is generated from PLL5 by dividing by two, followed by the RSW2 divider. As PLL5 runs at 3200 MHz, and RSW2 is fixed to 320 MHz, the RSW2 divider must be 5. Correct the parent and the fixed divider. Fixes: 24aaff6a6ce4c4de ("clk: renesas: cpg-mssr: Add support for R-Car S4-8") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/d6a406f31e6f02f892e0253f4e8a9a2f68fd652e.1641566003.git.geert+renesas@glider.be --- drivers/clk/renesas/r8a779f0-cpg-mssr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c index 8cc7457564db..4100078406d6 100644 --- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c @@ -103,7 +103,7 @@ static const struct cpg_core_clk r8a779f0_core_clks[] __initconst = { DEF_FIXED("s0d12_hsc", R8A779F0_CLK_S0D12_HSC, CLK_S0, 12, 1), DEF_FIXED("cl16m_hsc", R8A779F0_CLK_CL16M_HSC, CLK_S0, 48, 1), DEF_FIXED("s0d2_cc", R8A779F0_CLK_S0D2_CC, CLK_S0, 2, 1), - DEF_FIXED("rsw2", R8A779F0_CLK_RSW2, CLK_PLL5, 2, 1), + DEF_FIXED("rsw2", R8A779F0_CLK_RSW2, CLK_PLL5_DIV2, 5, 1), DEF_FIXED("cbfusa", R8A779F0_CLK_CBFUSA, CLK_EXTAL, 2, 1), DEF_FIXED("cpex", R8A779F0_CLK_CPEX, CLK_EXTAL, 2, 1), From 78789705581dcb2138302de11dce2ee2642e758e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 18 Jan 2022 18:09:01 +0100 Subject: [PATCH 20/26] clk: renesas: r8a779f0: Add WDT clock Add the module clock used by the RCLK Watchdog Timer (RWDT) on the Renesas R-Car S4-8 (r8a779f0) SoC. Mark it as a critical clock, to ensure uninterrupted watchdog operation. Signed-off-by: Geert Uytterhoeven Acked-by: Guenter Roeck Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/8d9b280065a663f2cf31db7b21a010aa781a0af1.1642525158.git.geert+renesas@glider.be --- drivers/clk/renesas/r8a779f0-cpg-mssr.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c index 4100078406d6..e48c5af73414 100644 --- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c @@ -121,6 +121,11 @@ static const struct mssr_mod_clk r8a779f0_mod_clks[] __initconst = { DEF_MOD("scif4", 705, R8A779F0_CLK_S0D12_PER), DEF_MOD("sys-dmac0", 709, R8A779F0_CLK_S0D3_PER), DEF_MOD("sys-dmac1", 710, R8A779F0_CLK_S0D3_PER), + DEF_MOD("wdt", 907, R8A779F0_CLK_R), +}; + +static const unsigned int r8a779f0_crit_mod_clks[] __initconst = { + MOD_CLK_ID(907), /* WDT */ }; /* @@ -177,6 +182,10 @@ const struct cpg_mssr_info r8a779f0_cpg_mssr_info __initconst = { .num_mod_clks = ARRAY_SIZE(r8a779f0_mod_clks), .num_hw_mod_clks = 28 * 32, + /* Critical Module Clocks */ + .crit_mod_clks = r8a779f0_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r8a779f0_crit_mod_clks), + /* Callbacks */ .init = r8a779f0_cpg_mssr_init, .cpg_clk_register = rcar_gen4_cpg_clk_register, From 5447d32c55592610969fa7e825a591c4104f0134 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 3 Feb 2022 15:34:28 +0100 Subject: [PATCH 21/26] clk: renesas: r8a779f0: Add I2C clocks Add the module clocks used by the I2C Bus Interfaces on the Renesas R-Car S4-8 (R8A779F0) SoC. Extracted from a larger patch in the BSP by LUU HOAI. Signed-off-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Link: https://lore.kernel.org/r/e4dcee5f6f521dccd7ac7f2fb6c86cfe4a24d032.1643898820.git.geert+renesas@glider.be --- drivers/clk/renesas/r8a779f0-cpg-mssr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c index e48c5af73414..123c1b01550d 100644 --- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c @@ -115,6 +115,12 @@ static const struct cpg_core_clk r8a779f0_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a779f0_mod_clks[] __initconst = { + DEF_MOD("i2c0", 518, R8A779F0_CLK_S0D6_PER), + DEF_MOD("i2c1", 519, R8A779F0_CLK_S0D6_PER), + DEF_MOD("i2c2", 520, R8A779F0_CLK_S0D6_PER), + DEF_MOD("i2c3", 521, R8A779F0_CLK_S0D6_PER), + DEF_MOD("i2c4", 522, R8A779F0_CLK_S0D6_PER), + DEF_MOD("i2c5", 523, R8A779F0_CLK_S0D6_PER), DEF_MOD("scif0", 702, R8A779F0_CLK_S0D12_PER), DEF_MOD("scif1", 703, R8A779F0_CLK_S0D12_PER), DEF_MOD("scif3", 704, R8A779F0_CLK_S0D12_PER), From 73421f2a48e6bd1d1024a09aedbc9c662cb88e77 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 21 Feb 2022 16:35:56 +0100 Subject: [PATCH 22/26] clk: renesas: r8a779f0: Add PFC clock Add the module clock used by the Pin Function (PFC/GPIO) controller on the Renesas R-Car S4-8 (R8A779F0) SoC. Extracted from a larger patch in the BSP by LUU HOAI. Signed-off-by: Geert Uytterhoeven Reviewed-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/4ef3d3dfe714ad75112e4886efea0b66e40a33bc.1645457502.git.geert+renesas@glider.be --- drivers/clk/renesas/r8a779f0-cpg-mssr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c index 123c1b01550d..76b441965037 100644 --- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c @@ -128,6 +128,7 @@ static const struct mssr_mod_clk r8a779f0_mod_clks[] __initconst = { DEF_MOD("sys-dmac0", 709, R8A779F0_CLK_S0D3_PER), DEF_MOD("sys-dmac1", 710, R8A779F0_CLK_S0D3_PER), DEF_MOD("wdt", 907, R8A779F0_CLK_R), + DEF_MOD("pfc0", 915, R8A779F0_CLK_CL16M), }; static const unsigned int r8a779f0_crit_mod_clks[] __initconst = { From 26c1bc67aa2fff563223f02612191405a7fa7cb7 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 26 Feb 2022 05:07:21 +0100 Subject: [PATCH 23/26] dt-bindings: clk: rs9: Add Renesas 9-series I2C PCIe clock generator Add binding for Renesas 9-series PCIe clock generators. This binding is designed to support 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ series I2C PCIe clock generators, currently the only tested and supported chip is 9FGV0241. Signed-off-by: Marek Vasut Cc: Michael Turquette Cc: Rob Herring Cc: Stephen Boyd Cc: devicetree@vger.kernel.org Link: https://lore.kernel.org/r/20220226040723.143705-1-marex@denx.de Reviewed-by: Rob Herring Signed-off-by: Stephen Boyd --- .../bindings/clock/renesas,9series.yaml | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/renesas,9series.yaml diff --git a/Documentation/devicetree/bindings/clock/renesas,9series.yaml b/Documentation/devicetree/bindings/clock/renesas,9series.yaml new file mode 100644 index 000000000000..102eb95cb3fc --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,9series.yaml @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/renesas,9series.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Binding for Renesas 9-series I2C PCIe clock generators + +description: | + The Renesas 9-series are I2C PCIe clock generators providing + from 1 to 20 output clocks. + + When referencing the provided clock in the DT using phandle + and clock specifier, the following mapping applies: + + - 9FGV0241: + 0 -- DIF0 + 1 -- DIF1 + +maintainers: + - Marek Vasut + +properties: + compatible: + enum: + - renesas,9fgv0241 + + reg: + description: I2C device address + enum: [ 0x68, 0x6a ] + + '#clock-cells': + const: 1 + + clocks: + items: + - description: XTal input clock + + renesas,out-amplitude-microvolt: + enum: [ 600000, 700000, 800000, 900000 ] + description: Output clock signal amplitude + + renesas,out-spread-spectrum: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 100000, 99750, 99500 ] + description: Output clock down spread in pcm (1/1000 of percent) + +patternProperties: + "^DIF[0-19]$": + type: object + description: + Description of one of the outputs (DIF0..DIF19). + + properties: + renesas,slew-rate: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 2000000, 3000000 ] + description: Output clock slew rate select in V/ns + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - '#clock-cells' + +additionalProperties: false + +examples: + - | + /* 25MHz reference crystal */ + ref25: ref25m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + + i2c@0 { + reg = <0x0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + + rs9: clock-generator@6a { + compatible = "renesas,9fgv0241"; + reg = <0x6a>; + #clock-cells = <1>; + + clocks = <&ref25m>; + + DIF0 { + renesas,slew-rate = <3000000>; + }; + }; + }; + +... From 0c125f87a84097c182c481be7497af9f816e5db5 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 26 Feb 2022 05:07:22 +0100 Subject: [PATCH 24/26] clk: fixed-factor: Introduce devm_clk_hw_register_fixed_factor_index() Add an API for a fixed factor clk that uses an index for the parent instead of a string name. This allows us to move drivers away from the string based method of describing parents and use the DT/firmware based method instead. Signed-off-by: Marek Vasut Cc: Michael Turquette Cc: Rob Herring Cc: Stephen Boyd Cc: devicetree@vger.kernel.org Link: https://lore.kernel.org/r/20220226040723.143705-2-marex@denx.de [sboyd@kernel.org: Expose a new API instead of internal function] Signed-off-by: Stephen Boyd --- drivers/clk/clk-fixed-factor.c | 22 ++++++++++++++++++++++ include/linux/clk-provider.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 4e4b6d367612..54942d758ee6 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -131,6 +131,28 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, return hw; } +/** + * devm_clk_hw_register_fixed_factor_index - Register a fixed factor clock with + * parent from DT index + * @dev: device that is registering this clock + * @name: name of this clock + * @index: index of phandle in @dev 'clocks' property + * @flags: fixed factor flags + * @mult: multiplier + * @div: divider + * + * Return: Pointer to fixed factor clk_hw structure that was registered or + * an error pointer. + */ +struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev, + const char *name, unsigned int index, unsigned long flags, + unsigned int mult, unsigned int div) +{ + return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, index, + flags, mult, div, true); +} +EXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index); + struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned int mult, unsigned int div) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 2faa6f7aa8a8..b7a7923f6bbb 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -1003,6 +1003,9 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw); struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned int mult, unsigned int div); +struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev, + const char *name, unsigned int index, unsigned long flags, + unsigned int mult, unsigned int div); /** * struct clk_fractional_divider - adjustable fractional divider clock * From 892e0ddea1aa6f70b68cb2dd8e16bf271e20e72f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 26 Feb 2022 05:07:23 +0100 Subject: [PATCH 25/26] clk: rs9: Add Renesas 9-series PCIe clock generator driver Add driver for Renesas 9-series PCIe clock generators. This driver is designed to support 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ series I2C PCIe clock generators, currently the only tested and supported chip is 9FGV0241. The driver is capable of configuring per-chip spread spectrum mode and output amplitude, as well as per-output slew rate. Signed-off-by: Marek Vasut Cc: Michael Turquette Cc: Rob Herring Cc: Stephen Boyd Cc: devicetree@vger.kernel.org Link: https://lore.kernel.org/r/20220226040723.143705-3-marex@denx.de [sboyd@kernel.org: Use non-underscore API for fixed factor] Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 9 + drivers/clk/Makefile | 1 + drivers/clk/clk-renesas-pcie.c | 322 +++++++++++++++++++++++++++++++++ 3 files changed, 332 insertions(+) create mode 100644 drivers/clk/clk-renesas-pcie.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index ad4256d54361..fb390e7fa641 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -340,6 +340,15 @@ config COMMON_CLK_OXNAS help Support for the OXNAS SoC Family clocks. +config COMMON_CLK_RS9_PCIE + tristate "Clock driver for Renesas 9-series PCIe clock generators" + depends on I2C + depends on OF + select REGMAP_I2C + help + This driver supports the Renesas 9-series PCIe clock generator + models 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ. + config COMMON_CLK_VC5 tristate "Clock driver for IDT VersaClock 5,6 devices" depends on I2C diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 16e588630472..cfa671325feb 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o +obj-$(CONFIG_COMMON_CLK_RS9_PCIE) += clk-renesas-pcie.o obj-$(CONFIG_COMMON_CLK_VC5) += clk-versaclock5.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c new file mode 100644 index 000000000000..59d9cf0053eb --- /dev/null +++ b/drivers/clk/clk-renesas-pcie.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Renesas 9-series PCIe clock generator driver + * + * The following series can be supported: + * - 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ + * Currently supported: + * - 9FGV0241 + * + * Copyright (C) 2022 Marek Vasut + */ + +#include +#include +#include +#include +#include +#include + +#define RS9_REG_OE 0x0 +#define RS9_REG_OE_DIF_OE(n) BIT((n) + 1) +#define RS9_REG_SS 0x1 +#define RS9_REG_SS_AMP_0V6 0x0 +#define RS9_REG_SS_AMP_0V7 0x1 +#define RS9_REG_SS_AMP_0V8 0x2 +#define RS9_REG_SS_AMP_0V9 0x3 +#define RS9_REG_SS_AMP_MASK 0x3 +#define RS9_REG_SS_SSC_100 0 +#define RS9_REG_SS_SSC_M025 (1 << 3) +#define RS9_REG_SS_SSC_M050 (3 << 3) +#define RS9_REG_SS_SSC_MASK (3 << 3) +#define RS9_REG_SS_SSC_LOCK BIT(5) +#define RS9_REG_SR 0x2 +#define RS9_REG_SR_2V0_DIF(n) 0 +#define RS9_REG_SR_3V0_DIF(n) BIT((n) + 1) +#define RS9_REG_SR_DIF_MASK(n) BIT((n) + 1) +#define RS9_REG_REF 0x3 +#define RS9_REG_REF_OE BIT(4) +#define RS9_REG_REF_OD BIT(5) +#define RS9_REG_REF_SR_SLOWEST 0 +#define RS9_REG_REF_SR_SLOW (1 << 6) +#define RS9_REG_REF_SR_FAST (2 << 6) +#define RS9_REG_REF_SR_FASTER (3 << 6) +#define RS9_REG_VID 0x5 +#define RS9_REG_DID 0x6 +#define RS9_REG_BCP 0x7 + +/* Supported Renesas 9-series models. */ +enum rs9_model { + RENESAS_9FGV0241, +}; + +/* Structure to describe features of a particular 9-series model */ +struct rs9_chip_info { + const enum rs9_model model; + unsigned int num_clks; +}; + +struct rs9_driver_data { + struct i2c_client *client; + struct regmap *regmap; + const struct rs9_chip_info *chip_info; + struct clk *pin_xin; + struct clk_hw *clk_dif[2]; + u8 pll_amplitude; + u8 pll_ssc; + u8 clk_dif_sr; +}; + +/* + * Renesas 9-series i2c regmap + */ +static const struct regmap_range rs9_readable_ranges[] = { + regmap_reg_range(RS9_REG_OE, RS9_REG_REF), + regmap_reg_range(RS9_REG_VID, RS9_REG_BCP), +}; + +static const struct regmap_access_table rs9_readable_table = { + .yes_ranges = rs9_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(rs9_readable_ranges), +}; + +static const struct regmap_range rs9_writeable_ranges[] = { + regmap_reg_range(RS9_REG_OE, RS9_REG_REF), + regmap_reg_range(RS9_REG_BCP, RS9_REG_BCP), +}; + +static const struct regmap_access_table rs9_writeable_table = { + .yes_ranges = rs9_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(rs9_writeable_ranges), +}; + +static const struct regmap_config rs9_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_FLAT, + .max_register = 0x8, + .rd_table = &rs9_readable_table, + .wr_table = &rs9_writeable_table, +}; + +static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx) +{ + struct i2c_client *client = rs9->client; + unsigned char name[5] = "DIF0"; + struct device_node *np; + int ret; + u32 sr; + + /* Set defaults */ + rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx); + rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx); + + snprintf(name, 5, "DIF%d", idx); + np = of_get_child_by_name(client->dev.of_node, name); + if (!np) + return 0; + + /* Output clock slew rate */ + ret = of_property_read_u32(np, "renesas,slew-rate", &sr); + of_node_put(np); + if (!ret) { + if (sr == 2000000) { /* 2V/ns */ + rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx); + rs9->clk_dif_sr |= RS9_REG_SR_2V0_DIF(idx); + } else if (sr == 3000000) { /* 3V/ns (default) */ + rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx); + rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx); + } else + ret = dev_err_probe(&client->dev, -EINVAL, + "Invalid renesas,slew-rate value\n"); + } + + return ret; +} + +static int rs9_get_common_config(struct rs9_driver_data *rs9) +{ + struct i2c_client *client = rs9->client; + struct device_node *np = client->dev.of_node; + unsigned int amp, ssc; + int ret; + + /* Set defaults */ + rs9->pll_amplitude = RS9_REG_SS_AMP_0V7; + rs9->pll_ssc = RS9_REG_SS_SSC_100; + + /* Output clock amplitude */ + ret = of_property_read_u32(np, "renesas,out-amplitude-microvolt", + &); + if (!ret) { + if (amp == 600000) /* 0.6V */ + rs9->pll_amplitude = RS9_REG_SS_AMP_0V6; + else if (amp == 700000) /* 0.7V (default) */ + rs9->pll_amplitude = RS9_REG_SS_AMP_0V7; + else if (amp == 800000) /* 0.8V */ + rs9->pll_amplitude = RS9_REG_SS_AMP_0V8; + else if (amp == 900000) /* 0.9V */ + rs9->pll_amplitude = RS9_REG_SS_AMP_0V9; + else + return dev_err_probe(&client->dev, -EINVAL, + "Invalid renesas,out-amplitude-microvolt value\n"); + } + + /* Output clock spread spectrum */ + ret = of_property_read_u32(np, "renesas,out-spread-spectrum", &ssc); + if (!ret) { + if (ssc == 100000) /* 100% ... no spread (default) */ + rs9->pll_ssc = RS9_REG_SS_SSC_100; + else if (ssc == 99750) /* -0.25% ... down spread */ + rs9->pll_ssc = RS9_REG_SS_SSC_M025; + else if (ssc == 99500) /* -0.50% ... down spread */ + rs9->pll_ssc = RS9_REG_SS_SSC_M050; + else + return dev_err_probe(&client->dev, -EINVAL, + "Invalid renesas,out-spread-spectrum value\n"); + } + + return 0; +} + +static void rs9_update_config(struct rs9_driver_data *rs9) +{ + int i; + + /* If amplitude is non-default, update it. */ + if (rs9->pll_amplitude != RS9_REG_SS_AMP_0V7) { + regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_AMP_MASK, + rs9->pll_amplitude); + } + + /* If SSC is non-default, update it. */ + if (rs9->pll_ssc != RS9_REG_SS_SSC_100) { + regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_SSC_MASK, + rs9->pll_ssc); + } + + for (i = 0; i < rs9->chip_info->num_clks; i++) { + if (rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i)) + continue; + + regmap_update_bits(rs9->regmap, RS9_REG_SR, RS9_REG_SR_3V0_DIF(i), + rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i)); + } +} + +static struct clk_hw * +rs9_of_clk_get(struct of_phandle_args *clkspec, void *data) +{ + struct rs9_driver_data *rs9 = data; + unsigned int idx = clkspec->args[0]; + + return rs9->clk_dif[idx]; +} + +static int rs9_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + unsigned char name[5] = "DIF0"; + struct rs9_driver_data *rs9; + struct clk_hw *hw; + int i, ret; + + rs9 = devm_kzalloc(&client->dev, sizeof(*rs9), GFP_KERNEL); + if (!rs9) + return -ENOMEM; + + i2c_set_clientdata(client, rs9); + rs9->client = client; + rs9->chip_info = device_get_match_data(&client->dev); + if (!rs9->chip_info) + return -EINVAL; + + /* Fetch common configuration from DT (if specified) */ + ret = rs9_get_common_config(rs9); + if (ret) + return ret; + + /* Fetch DIFx output configuration from DT (if specified) */ + for (i = 0; i < rs9->chip_info->num_clks; i++) { + ret = rs9_get_output_config(rs9, i); + if (ret) + return ret; + } + + rs9->regmap = devm_regmap_init_i2c(client, &rs9_regmap_config); + if (IS_ERR(rs9->regmap)) + return dev_err_probe(&client->dev, PTR_ERR(rs9->regmap), + "Failed to allocate register map\n"); + + /* Register clock */ + for (i = 0; i < rs9->chip_info->num_clks; i++) { + snprintf(name, 5, "DIF%d", i); + hw = devm_clk_hw_register_fixed_factor_index(&client->dev, name, + 0, 0, 4, 1); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + rs9->clk_dif[i] = hw; + } + + ret = devm_of_clk_add_hw_provider(&client->dev, rs9_of_clk_get, rs9); + if (!ret) + rs9_update_config(rs9); + + return ret; +} + +static int __maybe_unused rs9_suspend(struct device *dev) +{ + struct rs9_driver_data *rs9 = dev_get_drvdata(dev); + + regcache_cache_only(rs9->regmap, true); + regcache_mark_dirty(rs9->regmap); + + return 0; +} + +static int __maybe_unused rs9_resume(struct device *dev) +{ + struct rs9_driver_data *rs9 = dev_get_drvdata(dev); + int ret; + + regcache_cache_only(rs9->regmap, false); + ret = regcache_sync(rs9->regmap); + if (ret) + dev_err(dev, "Failed to restore register map: %d\n", ret); + return ret; +} + +static const struct rs9_chip_info renesas_9fgv0241_info = { + .model = RENESAS_9FGV0241, + .num_clks = 2, +}; + +static const struct i2c_device_id rs9_id[] = { + { "9fgv0241", .driver_data = RENESAS_9FGV0241 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rs9_id); + +static const struct of_device_id clk_rs9_of_match[] = { + { .compatible = "renesas,9fgv0241", .data = &renesas_9fgv0241_info }, + { } +}; +MODULE_DEVICE_TABLE(of, clk_rs9_of_match); + +static SIMPLE_DEV_PM_OPS(rs9_pm_ops, rs9_suspend, rs9_resume); + +static struct i2c_driver rs9_driver = { + .driver = { + .name = "clk-renesas-pcie-9series", + .pm = &rs9_pm_ops, + .of_match_table = clk_rs9_of_match, + }, + .probe = rs9_probe, + .id_table = rs9_id, +}; +module_i2c_driver(rs9_driver); + +MODULE_AUTHOR("Marek Vasut "); +MODULE_DESCRIPTION("Renesas 9-series PCIe clock generator driver"); +MODULE_LICENSE("GPL"); From 3b1db05cee0738166cdd0f335ea93e8b0ecf6e08 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Mar 2022 13:03:59 -0600 Subject: [PATCH 26/26] dt-bindings: clock: renesas: Make example 'clocks' parsable 'clocks' in the example is not parsable with the 0 phandle value because the number of #clock-cells is unknown in the previous entry. Solve this by adding the clock provider node. Only 'cpg_clocks' is needed as the examples are built with fixups which can be used to identify phandles. This is in preparation to support schema validation on .dtb files. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220301190400.1644150-1-robh@kernel.org Acked-by: Geert Uytterhoeven Reviewed-by: Geert Uytterhoeven Acked-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd --- .../bindings/clock/renesas,cpg-div6-clock.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml index c55a7c494e01..2197c952e21d 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml @@ -51,6 +51,18 @@ additionalProperties: false examples: - | #include + + cpg_clocks: cpg_clocks@e6150000 { + compatible = "renesas,r8a73a4-cpg-clocks"; + reg = <0xe6150000 0x10000>; + clocks = <&extal1_clk>, <&extal2_clk>; + #clock-cells = <1>; + clock-output-names = "main", "pll0", "pll1", "pll2", + "pll2s", "pll2h", "z", "z2", + "i", "m3", "b", "m1", "m2", + "zx", "zs", "hp"; + }; + sdhi2_clk: sdhi2_clk@e615007c { compatible = "renesas,r8a73a4-div6-clock", "renesas,cpg-div6-clock"; reg = <0xe615007c 4>;