]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ASoC: spacemit: add K3 SoC support with additional clocks
authorTroy Mitchell <troy.mitchell@linux.spacemit.com>
Fri, 22 May 2026 13:12:15 +0000 (21:12 +0800)
committerMark Brown <broonie@kernel.org>
Mon, 1 Jun 2026 15:00:44 +0000 (16:00 +0100)
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>
Link: https://patch.msgid.link/20260522-k3-i2s-v3-2-08e3eb811d93@linux.spacemit.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/spacemit/k1_i2s.c

index 5420ca2aefbd87e61109cc028422e435abd5a594..8871fc15b29cc005b144452c6ea3e6d18a86635a 100644 (file)
@@ -53,6 +53,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;
 
        struct snd_dmaengine_dai_dma_data capture_dma_data;
        struct snd_dmaengine_dai_dma_data playback_dma_data;
@@ -206,6 +209,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;
@@ -217,10 +228,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);
 }
 
@@ -436,6 +454,21 @@ static int spacemit_i2s_probe(struct platform_device *pdev)
                return dev_err_probe(i2s->dev, PTR_ERR(i2s->sspa_clk),
                                     "failed to enable sspa clock\n");
 
+       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");
@@ -462,6 +495,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);
@@ -476,4 +510,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");