From e6b17a690c2f920963d6a9328642bb090f3be587 Mon Sep 17 00:00:00 2001 From: Troy Mitchell Date: Fri, 17 Jul 2026 00:26:02 -0700 Subject: [PATCH] clk: spacemit: k3: fix i2s clock topology The K3 i2s clocks were modelled as a single path behind one MPMU register: pll1_d96_25p6 / i2s_153p6_base `-- i2s_sysclk_src (mux+gate, MPMU_ISCCR) `-- i2s1_sysclk (DDN, MPMU_ISCCR) |-- i2s_bclk (div+gate, MPMU_ISCCR) `-- i2s2_sysclk (mux, parent 0) The hardware actually has two i2s clock control registers, ISCCR0 (0x0040) and ISCCR1 (0x0044): ISCCR1 drives the common sysclk shared by i2s0/2/3/4/5 and the common bclk, whose divider always implies a fixed 1/2 factor in front, while ISCCR0 drives a dedicated path for i2s1: pll1_d96_25p6 / i2s_153p6_base |-- i2s_sysclk_src (mux+gate, MPMU_ISCCR1) | `-- i2s_sysclk (DDN, MPMU_ISCCR1) | |-- i2s_bclk_factor (fixed factor, /2) | | `-- i2s_bclk (div+gate, MPMU_ISCCR1) | `-- i2s2_sysclk (mux, parent 0) `-- i2s1_sysclk_src (mux+gate, MPMU_ISCCR0) `-- i2s1_sysclk (DDN, MPMU_ISCCR0) Because of this mismatch, i2s_bclk reported twice the real rate, and the dedicated i2s1 clock path could not be described in DT at all. Model the tree as above: split the MPMU_ISCCR register macro into MPMU_ISCCR0 and MPMU_ISCCR1 to match the hardware register names, rename the common DDN to i2s_sysclk, insert the fixed 1/2 factor i2s_bclk_factor in front of i2s_bclk, and add the i2s1_sysclk_src mux and i2s1_sysclk DDN backed by MPMU_ISCCR0. CLK_MPMU_I2S1_SYSCLK now refers to the dedicated i2s1 clock; no in-tree user references this ID, so nothing is affected by the change of meaning. Fixes: e371a77255b8 ("clk: spacemit: k3: add the clock tree") Signed-off-by: Troy Mitchell Reviewed-by: Yixun Lan Link: https://patch.msgid.link/20260717-k3-clk-fix-i2s-v1-2-e95001a692ee@linux.spacemit.com Signed-off-by: Yixun Lan --- drivers/clk/spacemit/ccu-k3.c | 21 ++++++++++++++++----- include/soc/spacemit/k3-syscon.h | 3 ++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/clk/spacemit/ccu-k3.c b/drivers/clk/spacemit/ccu-k3.c index f47d26e1d642..3133b5d5ec00 100644 --- a/drivers/clk/spacemit/ccu-k3.c +++ b/drivers/clk/spacemit/ccu-k3.c @@ -218,11 +218,19 @@ 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_MUX_GATE_DEFINE(i2s_sysclk_src, i2s_sysclk_src_parents, MPMU_ISCCR1, 30, 1, BIT(31), 0); -CCU_DDN_DEFINE(i2s1_sysclk, i2s_sysclk_src, MPMU_ISCCR, 0, 15, 15, 12, 1, 0); +CCU_DDN_DEFINE(i2s_sysclk, i2s_sysclk_src, MPMU_ISCCR1, 0, 15, 15, 12, 1, 0); -CCU_DIV_GATE_DEFINE(i2s_bclk, CCU_PARENT_HW(i2s1_sysclk), MPMU_ISCCR, 27, 2, BIT(29), 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_ISCCR1, 27, 2, BIT(29), 0); + +CCU_MUX_GATE_DEFINE(i2s1_sysclk_src, i2s_sysclk_src_parents, MPMU_ISCCR0, 30, 1, BIT(31), 0); +CCU_DDN_DEFINE(i2s1_sysclk, i2s1_sysclk_src, MPMU_ISCCR0, 0, 15, 15, 12, 1, 0); static const struct clk_parent_data i2s_sysclk_parents[] = { CCU_PARENT_HW(pll1_d4_614p4), @@ -243,7 +251,7 @@ CCU_DDN_DEFINE(i2s4_sysclk_div, i2s4_sysclk_sel, MPMU_I2S4_SYSCLK, 0, 16, 16, 16 CCU_DDN_DEFINE(i2s5_sysclk_div, i2s5_sysclk_sel, MPMU_I2S5_SYSCLK, 0, 16, 16, 16, 1, 0); static const struct clk_parent_data i2s2_sysclk_parents[] = { - CCU_PARENT_HW(i2s1_sysclk), + CCU_PARENT_HW(i2s_sysclk), CCU_PARENT_HW(i2s2_sysclk_div), }; CCU_GATE_DEFINE(i2s0_sysclk, CCU_PARENT_HW(i2s0_sysclk_div), MPMU_I2S_SYSCLK_CTRL, BIT(2), 0); @@ -1162,8 +1170,11 @@ static struct clk_hw *k3_ccu_mpmu_hws[] = { [CLK_MPMU_I2S_153P6] = &i2s_153p6.common.hw, [CLK_MPMU_I2S_153P6_BASE] = &i2s_153p6_base.common.hw, [CLK_MPMU_I2S_SYSCLK_SRC] = &i2s_sysclk_src.common.hw, - [CLK_MPMU_I2S1_SYSCLK] = &i2s1_sysclk.common.hw, + [CLK_MPMU_I2S_SYSCLK] = &i2s_sysclk.common.hw, + [CLK_MPMU_I2S_BCLK_FACTOR] = &i2s_bclk_factor.common.hw, [CLK_MPMU_I2S_BCLK] = &i2s_bclk.common.hw, + [CLK_MPMU_I2S1_SYSCLK_SRC] = &i2s1_sysclk_src.common.hw, + [CLK_MPMU_I2S1_SYSCLK] = &i2s1_sysclk.common.hw, [CLK_MPMU_I2S0_SYSCLK_SEL] = &i2s0_sysclk_sel.common.hw, [CLK_MPMU_I2S2_SYSCLK_SEL] = &i2s2_sysclk_sel.common.hw, [CLK_MPMU_I2S3_SYSCLK_SEL] = &i2s3_sysclk_sel.common.hw, diff --git a/include/soc/spacemit/k3-syscon.h b/include/soc/spacemit/k3-syscon.h index a68255dd641f..959d8d0786fe 100644 --- a/include/soc/spacemit/k3-syscon.h +++ b/include/soc/spacemit/k3-syscon.h @@ -45,7 +45,8 @@ #define POSR_PLL7_LOCK BIT(30) #define POSR_PLL8_LOCK BIT(31) #define MPMU_SUCCR 0x0014 -#define MPMU_ISCCR 0x0044 +#define MPMU_ISCCR0 0x0040 +#define MPMU_ISCCR1 0x0044 #define MPMU_WDTPCR 0x0200 #define MPMU_RIPCCR 0x0210 #define MPMU_ACGR 0x1024