]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
clk: spacemit: fix i2s clock
authorTroy Mitchell <troy.mitchell@linux.spacemit.com>
Thu, 11 Sep 2025 03:34:05 +0000 (11:34 +0800)
committerStephen Boyd <sboyd@kernel.org>
Sat, 20 Sep 2025 05:54:46 +0000 (22:54 -0700)
Defining i2s_bclk and i2s_sysclk as fixed-rate clocks is insufficient
for real I2S use cases.

Moreover, the current I2S clock configuration does not work as expected
due to missing parent clocks.

This patch adds the missing parent clocks, defines i2s_sysclk as
a DDN clock, and i2s_bclk as a DIV clock.

A special note for i2s_bclk:

From the register definition, the i2s_bclk divider always implies
an additional 1/2 factor.

The following table shows the correspondence between index
and frequency division coefficients:

| index |  div  |
|-------|-------|
|   0   |   2   |
|   1   |   4   |
|   2   |   6   |
|   3   |   8   |

From a software perspective, introducing i2s_bclk_factor as the
parent of i2s_bclk is sufficient to address the issue.

The I2S-related clock registers can be found here [1].

Link:
https://developer.spacemit.com/documentation?token=LCrKwWDasiJuROkVNusc2pWTnEb
[1]

Fixes: 1b72c59db0add ("clk: spacemit: Add clock support for SpacemiT K1 SoC")
Co-developer: Jinmei Wei <weijinmei@linux.spacemit.com>
Suggested-by: Haylen Chu <heylenay@4d2.org>
Signed-off-by: Jinmei Wei <weijinmei@linux.spacemit.com>
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/spacemit/ccu-k1.c
include/soc/spacemit/k1-syscon.h

index 14a88d0372dde922a451b337897147e02a1db5aa..f5a9fe6ba185913ada82a41b93679a629c86b066 100644 (file)
@@ -141,8 +141,28 @@ CCU_DDN_DEFINE(slow_uart2_48, pll1_d4_614p4, MPMU_SUCCR_1, 16, 13, 0, 13, 2, 0);
 
 CCU_GATE_DEFINE(wdt_clk, CCU_PARENT_HW(pll1_d96_25p6), MPMU_WDTPCR, BIT(1), 0);
 
-CCU_FACTOR_GATE_DEFINE(i2s_sysclk, CCU_PARENT_HW(pll1_d16_153p6), MPMU_ISCCR, BIT(31), 50, 1);
-CCU_FACTOR_GATE_DEFINE(i2s_bclk, CCU_PARENT_HW(i2s_sysclk), MPMU_ISCCR, BIT(29), 1, 1);
+CCU_FACTOR_DEFINE(i2s_153p6, CCU_PARENT_HW(pll1_d8_307p2), 2, 1);
+
+static const struct clk_parent_data i2s_153p6_base_parents[] = {
+       CCU_PARENT_HW(i2s_153p6),
+       CCU_PARENT_HW(pll1_d8_307p2),
+};
+CCU_MUX_DEFINE(i2s_153p6_base, i2s_153p6_base_parents, MPMU_FCCR, 29, 1, 0);
+
+static const struct clk_parent_data i2s_sysclk_src_parents[] = {
+       CCU_PARENT_HW(pll1_d96_25p6),
+       CCU_PARENT_HW(i2s_153p6_base)
+};
+CCU_MUX_GATE_DEFINE(i2s_sysclk_src, i2s_sysclk_src_parents, MPMU_ISCCR, 30, 1, BIT(31), 0);
+
+CCU_DDN_DEFINE(i2s_sysclk, i2s_sysclk_src, MPMU_ISCCR, 0, 15, 15, 12, 1, 0);
+
+CCU_FACTOR_DEFINE(i2s_bclk_factor, CCU_PARENT_HW(i2s_sysclk), 2, 1);
+/*
+ * Divider of i2s_bclk always implies a 1/2 factor, which is
+ * described by i2s_bclk_factor.
+ */
+CCU_DIV_GATE_DEFINE(i2s_bclk, CCU_PARENT_HW(i2s_bclk_factor), MPMU_ISCCR, 27, 2, BIT(29), 0);
 
 static const struct clk_parent_data apb_parents[] = {
        CCU_PARENT_HW(pll1_d96_25p6),
@@ -775,6 +795,10 @@ static struct clk_hw *k1_ccu_mpmu_hws[] = {
        [CLK_I2S_BCLK]          = &i2s_bclk.common.hw,
        [CLK_APB]               = &apb_clk.common.hw,
        [CLK_WDT_BUS]           = &wdt_bus_clk.common.hw,
+       [CLK_I2S_153P6]         = &i2s_153p6.common.hw,
+       [CLK_I2S_153P6_BASE]    = &i2s_153p6_base.common.hw,
+       [CLK_I2S_SYSCLK_SRC]    = &i2s_sysclk_src.common.hw,
+       [CLK_I2S_BCLK_FACTOR]   = &i2s_bclk_factor.common.hw,
 };
 
 static const struct spacemit_ccu_data k1_ccu_mpmu_data = {
index c59bd7a38e5b4219121341b9c0d9ffda13a9c3e2..354751562c55523ef8a22be931ddd8aca9651084 100644 (file)
@@ -30,6 +30,7 @@ to_spacemit_ccu_adev(struct auxiliary_device *adev)
 
 /* MPMU register offset */
 #define MPMU_POSR                      0x0010
+#define MPMU_FCCR                      0x0008
 #define  POSR_PLL1_LOCK                        BIT(27)
 #define  POSR_PLL2_LOCK                        BIT(28)
 #define  POSR_PLL3_LOCK                        BIT(29)