[PATCH 7/7] ASoC: spacemit: add K3 SoC support with additional clocks

Troy Mitchell
2026-04-29T01:39:30Z

Add support for the SpacemiT K3 SoC I2S controller, which shares the
same IP as K1 but requires additional clocks: sysclk_div, c_sysclk,
and c_bclk. These clocks only exist on K3 and are not present on K1.
The sysclk_div clock is present on most K3 I2S controllers except I2S1.
The c_sysclk and c_bclk clocks are shared across multiple I2S
controllers on K3.

Use devm_clk_get_optional_enabled() to acquire these clocks so that
the driver works on both K1 (where they are absent) and K3 without
needing SoC-specific match data. For K3, the sysclk_div rate is set
before sysclk in set_sysclk, and the common clock rates are configured
in hw_params based on the sample rate.

Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
sound/soc/spacemit/k1_i2s.c | 36 +++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c
index 7d0794d21ea6..c2a2b99d91f8 100644
--- a/sound/soc/spacemit/k1_i2s.c
+++ b/sound/soc/spacemit/k1_i2s.c
@@ -54,6 +54,9 @@ struct spacemit_i2s_dev {
struct clk *sysclk;
struct clk *bclk;
struct clk *sspa_clk;
+ struct clk *sysclk_div;
+ struct clk *c_sysclk;
+ struct clk *c_bclk;

unsigned int fixed_sample_rate;

@@ -217,6 +220,14 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
params_rate(params) *
data_bits;

+ ret = clk_set_rate(i2s->c_sysclk, bclk_rate * 2);
+ if (ret)
+ return ret;
+
+ ret = clk_set_rate(i2s->c_bclk, bclk_rate);
+ if (ret)
+ return ret;
+
ret = clk_set_rate(i2s->bclk, bclk_rate);
if (ret)
return ret;
@@ -228,10 +239,17 @@ static int spacemit_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
unsigned int freq, int dir)
{
struct spacemit_i2s_dev *i2s = dev_get_drvdata(cpu_dai->dev);
+ int ret;

if (freq == 0)
return 0;

+ if (i2s->sysclk_div) {
+ ret = clk_set_rate(i2s->sysclk_div, freq);
+ if (ret)
+ return ret;
+ }
+
return clk_set_rate(i2s->sysclk, freq);
}

@@ -450,6 +468,21 @@ static int spacemit_i2s_probe(struct platform_device *pdev)
of_property_read_u32(i2s->dev->of_node, "spacemit,fixed-sample-rate",
&i2s->fixed_sample_rate);

+ i2s->sysclk_div = devm_clk_get_optional_enabled(i2s->dev, "sysclk_div");
+ if (IS_ERR(i2s->sysclk_div))
+ return dev_err_probe(i2s->dev, PTR_ERR(i2s->sysclk_div),
+ "failed to enable sysclk_div clock\n");
+
+ i2s->c_sysclk = devm_clk_get_optional_enabled(i2s->dev, "c_sysclk");
+ if (IS_ERR(i2s->c_sysclk))
+ return dev_err_probe(i2s->dev, PTR_ERR(i2s->c_sysclk),
+ "failed to enable c_sysclk clock\n");
+
+ i2s->c_bclk = devm_clk_get_optional_enabled(i2s->dev, "c_bclk");
+ if (IS_ERR(i2s->c_bclk))
+ return dev_err_probe(i2s->dev, PTR_ERR(i2s->c_bclk),
+ "failed to enable c_bclk clock\n");
+
i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(i2s->base))
return dev_err_probe(i2s->dev, PTR_ERR(i2s->base), "failed to map registers\n");
@@ -476,6 +509,7 @@ static int spacemit_i2s_probe(struct platform_device *pdev)

static const struct of_device_id spacemit_i2s_of_match[] = {
{ .compatible = "spacemit,k1-i2s", },
+ { .compatible = "spacemit,k3-i2s", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, spacemit_i2s_of_match);
@@ -490,4 +524,4 @@ static struct platform_driver spacemit_i2s_driver = {
module_platform_driver(spacemit_i2s_driver);

MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("I2S bus driver for SpacemiT K1 SoC");
+MODULE_DESCRIPTION("I2S bus driver for SpacemiT K1/K3 SoC");

--
2.54.0