From cfe0012e12d7e3889b5d245f14b4ed3bf73f033a Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Sat, 15 Aug 2026 11:40:21 +0800 Subject: i2c: k1: fix wrong bus speed setting The controller bus mode should be selected according to the requested I2C bus speed. However, the driver currently passes the functional clock rate to k1_i2c_set_bus_speed(), so the selected mode does not reflect the requested bus speed. Fix this by reading the clock-frequency property from the Device Tree, defaulting to standard speed, and drop the unused clk_rate field. Fixes: 271546fb8e54 ("i2c: k1: add I2C driver support") Reviewed-by: Heiko Schocher Reviewed-by: Yao Zi Signed-off-by: Junhui Liu --- drivers/i2c/k1_i2c.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/k1_i2c.c b/drivers/i2c/k1_i2c.c index a08ff15803d..2c7a1e0d377 100644 --- a/drivers/i2c/k1_i2c.c +++ b/drivers/i2c/k1_i2c.c @@ -52,7 +52,6 @@ struct k1_i2c_priv { int id; void __iomem *base; struct clk clk; - u32 clk_rate; }; /* @@ -466,6 +465,7 @@ static int k1_i2c_probe(struct udevice *bus) { struct k1_i2c_priv *priv = dev_get_priv(bus); struct reset_ctl reset; + u32 speed; int ret; priv->id = dev_seq(bus); @@ -496,10 +496,13 @@ static int k1_i2c_probe(struct udevice *bus) debug("%s: failed to enable clock\n", __func__); return ret; } - priv->clk_rate = clk_get_rate(&priv->clk); priv->base = (void *)devfdt_get_addr_ptr(bus); - k1_i2c_set_bus_speed(bus, priv->clk_rate); + + speed = dev_read_u32_default(bus, "clock-frequency", + I2C_SPEED_STANDARD_RATE); + k1_i2c_set_bus_speed(bus, speed); + return 0; } -- cgit v1.3.1 From 0b47f7237e446cfb73b2df70aa4bc74db73400bf Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Sat, 15 Aug 2026 11:40:22 +0800 Subject: clk: spacemit: k1: add TWSI bus clocks to SPL The K1 device tree describes separate functional and bus clocks for TWSI controllers, but the SPL clock tree currently only provides their functional clocks. Add the bus clocks for TWSI2 and TWSI8, which are the TWSI controllers currently used in SPL, along with their required parent clock chain. TWSI8 uses a fixed-factor bus clock because its write-only clock control register requires the functional and bus gate bits to remain combined in a single clock instance. Reviewed-by: Yao Zi Signed-off-by: Junhui Liu --- drivers/clk/spacemit/clk-k1.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/clk/spacemit/clk-k1.c b/drivers/clk/spacemit/clk-k1.c index 07adc126ee3..e239ffe6ba0 100644 --- a/drivers/clk/spacemit/clk-k1.c +++ b/drivers/clk/spacemit/clk-k1.c @@ -154,11 +154,27 @@ CCU_GATE_DEFINE(CLK_PLL1_409P6, pll1_d6_409p6, pll1_d6_409p6, "pll1_d6", MPMU_ACGR, BIT(0), 0); CCU_GATE_DEFINE(CLK_PLL1_307P2, pll1_d8_307p2, pll1_d8_307p2, "pll1_d8", MPMU_ACGR, BIT(13), 0); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_102P4, pll1_d24_102p4, pll1_d24_102p4, + "pll1_d8", MPMU_ACGR, BIT(12), 3, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_51P2, pll1_d48_51p2, pll1_d48_51p2, + "pll1_d8", MPMU_ACGR, BIT(7), 6, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_25P6, pll1_d96_25p6, pll1_d96_25p6, + "pll1_d8", MPMU_ACGR, BIT(4), 12, 1); CCU_FACTOR_GATE_DEFINE(CLK_PLL1_31P5, pll1_d78_31p5, pll1_d78_31p5, "pll1_d4", MPMU_ACGR, BIT(6), 39, 2); CCU_DDN_DEFINE(CLK_SLOW_UART2, slow_uart2_48, slow_uart2_48, "pll1_d4_614p4", MPMU_SUCCR_1, CCU_DDN_MASK(16, 13), 16, CCU_DDN_MASK(0, 13), 0, 2, 0); + +static const char * const apb_parents[] = { + "pll1_d96_25p6", + "pll1_d48_51p2", + "pll1_d96_25p6", + "pll1_d24_102p4", +}; + +CCU_MUX_DEFINE(CLK_APB, apb_clk, apb_clk, apb_parents, ARRAY_SIZE(apb_parents), + MPMU_APBCSCR, 0, 2, 0); #else CCU_GATE_DEFINE(CLK_PLL1_307P2, pll1_d8_307p2, pll1_d8_307p2, "pll1_d8", MPMU_ACGR, BIT(13), 0); @@ -306,6 +322,9 @@ CCU_MUX_GATE_DEFINE(CLK_TWSI2, twsi2_clk, twsi2_clk, twsi_parents, */ CCU_GATE_DEFINE(CLK_TWSI8, twsi8_clk, twsi8_clk, "pll1_d78_31p5", APBC_TWSI8_CLK_RST, BIT(1) | BIT(0), 0); +CCU_GATE_DEFINE(CLK_TWSI2_BUS, twsi2_bus_clk, twsi2_bus_clk, "apb_clk", + APBC_TWSI2_CLK_RST, BIT(0), 0); +CCU_FACTOR_DEFINE(CLK_TWSI8_BUS, twsi8_bus_clk, twsi8_bus_clk, "apb_clk", 1, 1); #else static const char * const uart_clk_parents[] = { @@ -1232,8 +1251,12 @@ static struct clk *k1_ccu_mpmu_clks[] = { &pll1_d4_614p4.common.clk, &pll1_d6_409p6.common.clk, &pll1_d8_307p2.common.clk, + &pll1_d24_102p4.common.clk, + &pll1_d48_51p2.common.clk, + &pll1_d96_25p6.common.clk, &pll1_d78_31p5.common.clk, &slow_uart2_48.common.clk, + &apb_clk.common.clk, }; #else static struct clk *k1_ccu_mpmu_clks[] = { @@ -1288,6 +1311,8 @@ static struct clk *k1_ccu_apbc_clks[] = { &uart0_clk.common.clk, &twsi2_clk.common.clk, &twsi8_clk.common.clk, + &twsi2_bus_clk.common.clk, + &twsi8_bus_clk.common.clk, }; #else static struct clk *k1_ccu_apbc_clks[] = { -- cgit v1.3.1 From febfffd338e0be62d28c280ae779fd7bb88fe17c Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Sat, 15 Aug 2026 11:40:23 +0800 Subject: i2c: k1: enable both functional and bus clocks The K1 I2C controller requires both its functional clock and APB bus clock to operate. The device tree provides them as "func" and "bus", but the driver currently acquires and enables only the first clock. Acquire both clocks by name and enable them during probe. Use explicit named lookups instead of the bulk clock API to align with the K1 Linux driver and keep the roles of the two clocks clear if functional clock rate configuration is needed later. Fixes: 271546fb8e54 ("i2c: k1: add I2C driver support") Reviewed-by: Heiko Schocher Reviewed-by: Yao Zi Signed-off-by: Junhui Liu --- drivers/i2c/k1_i2c.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/k1_i2c.c b/drivers/i2c/k1_i2c.c index 2c7a1e0d377..e2e4f9e5344 100644 --- a/drivers/i2c/k1_i2c.c +++ b/drivers/i2c/k1_i2c.c @@ -51,7 +51,6 @@ struct k1_i2c { struct k1_i2c_priv { int id; void __iomem *base; - struct clk clk; }; /* @@ -465,6 +464,7 @@ static int k1_i2c_probe(struct udevice *bus) { struct k1_i2c_priv *priv = dev_get_priv(bus); struct reset_ctl reset; + struct clk clk; u32 speed; int ret; @@ -487,15 +487,21 @@ static int k1_i2c_probe(struct udevice *bus) return ret; } - ret = clk_get_by_index(bus, 0, &priv->clk); + ret = clk_get_by_name(bus, "func", &clk); if (ret) return ret; - ret = clk_enable(&priv->clk); - if (ret && ret != -ENOSYS && ret != -EOPNOTSUPP) { - debug("%s: failed to enable clock\n", __func__); + ret = clk_enable(&clk); + if (ret) + return ret; + + ret = clk_get_by_name(bus, "bus", &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) return ret; - } priv->base = (void *)devfdt_get_addr_ptr(bus); -- cgit v1.3.1 From 35c2947b5b217962e8d88e2a0b7f507a037a0676 Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Sat, 15 Aug 2026 11:40:24 +0800 Subject: clk: spacemit: k1: remove bus gate from TWSI functional clocks The TWSI functional clocks incorrectly include both the functional clock enable bit and the bus clock enable bit in their gate masks. The device tree and the full clock tree model the bus clocks separately. Remove the bus clock enable bit from the functional clock gate masks so that the functional and bus clocks are controlled independently. Keep the combined gate for TWSI8 because its clock control register is write-only and therefore cannot be safely shared by two clock instances. Fixes: 3aa2882a3e1a ("clk: spacemit: Add support for K1 SoC") Reviewed-by: Yao Zi Signed-off-by: Junhui Liu --- drivers/clk/spacemit/clk-k1.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/spacemit/clk-k1.c b/drivers/clk/spacemit/clk-k1.c index e239ffe6ba0..20b8595aa3c 100644 --- a/drivers/clk/spacemit/clk-k1.c +++ b/drivers/clk/spacemit/clk-k1.c @@ -314,7 +314,7 @@ static const char * const twsi_parents[] = { CCU_MUX_GATE_DEFINE(CLK_TWSI2, twsi2_clk, twsi2_clk, twsi_parents, ARRAY_SIZE(twsi_parents), APBC_TWSI2_CLK_RST, - 4, 3, BIT(1) | BIT(0), 0); + 4, 3, BIT(1), 0); /* * APBC_TWSI8_CLK_RST has a quirk that reading always results in zero. * Combine functional and bus bits together as a gate to avoid sharing the @@ -345,7 +345,7 @@ static const char * const twsi_parents[] = { CCU_MUX_GATE_DEFINE(CLK_TWSI2, twsi2_clk, twsi2_clk, twsi_parents, ARRAY_SIZE(twsi_parents), APBC_TWSI2_CLK_RST, - 4, 3, BIT(1) | BIT(0), 0); + 4, 3, BIT(1), 0); /* * APBC_TWSI8_CLK_RST has a quirk that reading always results in zero. * Combine functional and bus bits together as a gate to avoid sharing the @@ -467,22 +467,22 @@ CCU_GATE_DEFINE(CLK_RTC, rtc_clk, rtc_clk, "clock-32k", APBC_RTC_CLK_RST, CCU_MUX_GATE_DEFINE(CLK_TWSI0, twsi0_clk, twsi0_clk, twsi_parents, ARRAY_SIZE(twsi_parents), APBC_TWSI0_CLK_RST, - 4, 3, BIT(1) | BIT(0), 0); + 4, 3, BIT(1), 0); CCU_MUX_GATE_DEFINE(CLK_TWSI1, twsi1_clk, twsi1_clk, twsi_parents, ARRAY_SIZE(twsi_parents), APBC_TWSI1_CLK_RST, - 4, 3, BIT(1) | BIT(0), 0); + 4, 3, BIT(1), 0); CCU_MUX_GATE_DEFINE(CLK_TWSI4, twsi4_clk, twsi4_clk, twsi_parents, ARRAY_SIZE(twsi_parents), APBC_TWSI4_CLK_RST, - 4, 3, BIT(1) | BIT(0), 0); + 4, 3, BIT(1), 0); CCU_MUX_GATE_DEFINE(CLK_TWSI5, twsi5_clk, twsi5_clk, twsi_parents, ARRAY_SIZE(twsi_parents), APBC_TWSI5_CLK_RST, - 4, 3, BIT(1) | BIT(0), 0); + 4, 3, BIT(1), 0); CCU_MUX_GATE_DEFINE(CLK_TWSI6, twsi6_clk, twsi6_clk, twsi_parents, ARRAY_SIZE(twsi_parents), APBC_TWSI6_CLK_RST, - 4, 3, BIT(1) | BIT(0), 0); + 4, 3, BIT(1), 0); CCU_MUX_GATE_DEFINE(CLK_TWSI7, twsi7_clk, twsi7_clk, twsi_parents, ARRAY_SIZE(twsi_parents), APBC_TWSI7_CLK_RST, - 4, 3, BIT(1) | BIT(0), 0); + 4, 3, BIT(1), 0); static const char * const timer_parents[] = { "pll1_d192_12p8", -- cgit v1.3.1