* [PATCH v2 0/2] ASoC: spacemit: add i2s support to K1 SoC
@ 2025-08-28 3:37 Troy Mitchell
2025-08-28 3:37 ` [PATCH v2 1/2] ASoC: dt-bindings: Add bindings for SpacemiT K1 Troy Mitchell
2025-08-28 3:37 ` [PATCH v2 2/2] ASoC: spacemit: add i2s support for K1 SoC Troy Mitchell
0 siblings, 2 replies; 7+ messages in thread
From: Troy Mitchell @ 2025-08-28 3:37 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Yixun Lan, Jaroslav Kysela, Takashi Iwai,
Philipp Zabel
Cc: linux-sound, devicetree, linux-riscv, spacemit, linux-kernel,
Troy Mitchell, Jinmei Wei
On the K1 SoC, there is a full-duplex I2S controller.
The I2S is programmable, with the sample width configurable
to 8, 16, 18, or 32 bits.
A dedicated FIFO is provided for transmit (TXFIFO) and another
for receive (RXFIFO). In non-packed mode, both FIFOs are 32
entries deep and 32 bits wide, giving a total of 32 samples each.
The register definitions can be found here[1]
Link:
https://developer.spacemit.com/documentation?token=Rn9Kw3iFHirAMgkIpTAcV2Arnkf#18.2-spi%2Fi2s [1]
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
Changes in v2:
- Patch 1/2:
- modify commit message
- remove unused third cell from pdma dmas property
- update SPDX license in spacemit,k1-i2s.yaml to (GPL-2.0-only OR BSD-2-Clause)
- Patch 2/2:
- modify commit message
- reset_assert in dai_ops::remove
- select CMA and DMA_CMA in Kconfig
- use devm_reset_control_get_exclusive
- Link to v1: https://lore.kernel.org/r/20250814-k1-i2s-v1-0-c31149b29041@linux.spacemit.com
---
Troy Mitchell (2):
ASoC: dt-bindings: Add bindings for SpacemiT K1
ASoC: spacemit: add i2s support for K1 SoC
.../devicetree/bindings/sound/spacemit,k1-i2s.yaml | 88 ++++
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/spacemit/Kconfig | 16 +
sound/soc/spacemit/Makefile | 5 +
sound/soc/spacemit/k1_i2s.c | 452 +++++++++++++++++++++
6 files changed, 563 insertions(+)
---
base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
change-id: 20250813-k1-i2s-115bf65eaac8
prerequisite-change-id: 20250804-k1-clk-i2s-generation-eee7049ee17a:v4
prerequisite-patch-id: b46d4007c5b20f11845db739fc78ffccc54f4dab
prerequisite-patch-id: 1e193c412de1206c024a674e2dd7da88092976b9
prerequisite-patch-id: af07a4bca4109b13a74c0b20a12f96af863090ef
prerequisite-change-id: 20250701-working_dma_0701_v2-7d2cf506aad7:v5
prerequisite-patch-id: 3fe97698036c32c20d03b1b835a5735e8ee8126c
prerequisite-patch-id: bf64cb2fbb9699d2ace64ae517532f13c6f8d277
prerequisite-patch-id: 49263c65c84a0b045f9b5ae6831dc011c4dea52f
prerequisite-patch-id: 2b43599bf7568e6432faa2f6aca5b2db792cd1c1
prerequisite-patch-id: 1b840918a99543f4497b6475ee52977bdb59f1c3
prerequisite-patch-id: 2f77be523fd5423bd011e3081a3635d130410096
prerequisite-patch-id: 78bcc660796fc4f73b884d17a1b63e62f99dfdd0
prerequisite-patch-id: 62d0b3678cf825bca51424ad85cf35ebdd6dc171
prerequisite-message-id: <20250824-k1-clk-i2s-v5-0-217b6b7cea06@linux.spacemit.com>
prerequisite-patch-id: 6f2626811da4833395f52f712d9f2a5fb553cb48
prerequisite-patch-id: d2594982f7a8f39c2aa4f21490a19e93ab67254d
Best regards,
--
Troy Mitchell <troy.mitchell@linux.spacemit.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] ASoC: dt-bindings: Add bindings for SpacemiT K1
2025-08-28 3:37 [PATCH v2 0/2] ASoC: spacemit: add i2s support to K1 SoC Troy Mitchell
@ 2025-08-28 3:37 ` Troy Mitchell
2025-08-29 17:16 ` Rob Herring
2025-08-28 3:37 ` [PATCH v2 2/2] ASoC: spacemit: add i2s support for K1 SoC Troy Mitchell
1 sibling, 1 reply; 7+ messages in thread
From: Troy Mitchell @ 2025-08-28 3:37 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Yixun Lan, Jaroslav Kysela, Takashi Iwai,
Philipp Zabel
Cc: linux-sound, devicetree, linux-riscv, spacemit, linux-kernel,
Troy Mitchell
Add dt-binding for the i2s driver of SpacemiT's K1 SoC.
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
.../devicetree/bindings/sound/spacemit,k1-i2s.yaml | 88 ++++++++++++++++++++++
1 file changed, 88 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..042001c38ed8d434889183831e44289ea9c5aef2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/spacemit,k1-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: K1 I2S controller
+
+description:
+ The I2S bus (Inter-IC sound bus) is a serial link for digital
+ audio data transfer between devices in the system.
+
+maintainers:
+ - Troy Mitchell <troy.mitchell@linux.spacemit.com>
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: spacemit,k1-i2s
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: clock for I2S sysclk
+ - description: clock for I2S bclk
+ - description: clock for I2S bus
+ - description: clock for I2S controller
+
+ clock-names:
+ items:
+ - const: sysclk
+ - const: bclk
+ - const: bus
+ - const: func
+
+ dmas:
+ minItems: 1
+ maxItems: 2
+
+ dma-names:
+ oneOf:
+ - const: rx
+ - items:
+ - const: tx
+ - const: rx
+
+ resets:
+ maxItems: 1
+
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
+ "#sound-dai-cells":
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - dmas
+ - dma-names
+ - resets
+ - "#sound-dai-cells"
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/spacemit,k1-syscon.h>
+ i2s@d4026000 {
+ compatible = "spacemit,k1-i2s";
+ reg = <0xd4026000 0x30>;
+ clocks = <&syscon_mpmu CLK_I2S_SYSCLK>,
+ <&syscon_mpmu CLK_I2S_BCLK>,
+ <&syscon_apbc CLK_SSPA0_BUS>,
+ <&syscon_apbc CLK_SSPA0>;
+ clock-names = "sysclk", "bclk", "bus", "func";
+ dmas = <&pdma0 21>, <&pdma0 22>;
+ dma-names = "tx", "rx";
+ resets = <&syscon_apbc RESET_SSPA0>;
+ #sound-dai-cells = <0>;
+ };
--
2.50.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] ASoC: spacemit: add i2s support for K1 SoC
2025-08-28 3:37 [PATCH v2 0/2] ASoC: spacemit: add i2s support to K1 SoC Troy Mitchell
2025-08-28 3:37 ` [PATCH v2 1/2] ASoC: dt-bindings: Add bindings for SpacemiT K1 Troy Mitchell
@ 2025-08-28 3:37 ` Troy Mitchell
2025-08-28 9:04 ` Mark Brown
1 sibling, 1 reply; 7+ messages in thread
From: Troy Mitchell @ 2025-08-28 3:37 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Yixun Lan, Jaroslav Kysela, Takashi Iwai,
Philipp Zabel
Cc: linux-sound, devicetree, linux-riscv, spacemit, linux-kernel,
Troy Mitchell, Jinmei Wei
Add ASoC platform driver for the SpacemiT K1 SoC full-duplex I2S
controller.
Co-developer: Jinmei Wei <weijinmei@linux.spacemit.com>
Signed-off-by: Jinmei Wei <weijinmei@linux.spacemit.com>
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/spacemit/Kconfig | 16 ++
sound/soc/spacemit/Makefile | 5 +
sound/soc/spacemit/k1_i2s.c | 452 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 475 insertions(+)
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index ce74818bd7152dbe110b9fff7d908b0ddf34a9f5..36e0d443ba0ebe584ffe797c378c838f448ffcb9 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -127,6 +127,7 @@ source "sound/soc/renesas/Kconfig"
source "sound/soc/rockchip/Kconfig"
source "sound/soc/samsung/Kconfig"
source "sound/soc/sdca/Kconfig"
+source "sound/soc/spacemit/Kconfig"
source "sound/soc/spear/Kconfig"
source "sound/soc/sprd/Kconfig"
source "sound/soc/starfive/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 462322c38aa42d4c394736239de0317d5918d5a7..8c0480e6484e75eb0b6db306630ba77d259ba8e3 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_SND_SOC) += rockchip/
obj-$(CONFIG_SND_SOC) += samsung/
obj-$(CONFIG_SND_SOC) += sdca/
obj-$(CONFIG_SND_SOC) += sof/
+obj-$(CONFIG_SND_SOC) += spacemit/
obj-$(CONFIG_SND_SOC) += spear/
obj-$(CONFIG_SND_SOC) += sprd/
obj-$(CONFIG_SND_SOC) += starfive/
diff --git a/sound/soc/spacemit/Kconfig b/sound/soc/spacemit/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..2179f94f3f179c54cd06e6ced5523ed3f5225cf4
--- /dev/null
+++ b/sound/soc/spacemit/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "SpacemiT"
+ depends on COMPILE_TEST || ARCH_SPACEMIT
+ depends on HAVE_CLK
+
+config SND_SOC_K1_I2S
+ tristate "K1 I2S Device Driver"
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select CMA
+ select DMA_CMA
+ help
+ Say Y or M if you want to add support for I2S driver for
+ K1 I2S controller. The device supports up to maximum of
+ 2 channels each for play and record.
+
+endmenu
diff --git a/sound/soc/spacemit/Makefile b/sound/soc/spacemit/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..9069de8ef89c84db8cc7d3a4d3b154fff9bd7aff
--- /dev/null
+++ b/sound/soc/spacemit/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+# K1 Platform Support
+snd-soc-k1-i2s-y := k1_i2s.o
+
+obj-$(CONFIG_SND_SOC_K1_I2S) += snd-soc-k1-i2s.o
diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c
new file mode 100644
index 0000000000000000000000000000000000000000..1657e2db6f36edeeeb1a6dc1fc4cca6be08a5bed
--- /dev/null
+++ b/sound/soc/spacemit/k1_i2s.c
@@ -0,0 +1,452 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Troy Mitchell <troy.mitchell@linux.spacemit.com> */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#define SSCR 0x00 /* SPI/I2S top control register */
+#define SSFCR 0x04 /* SPI/I2S FIFO control register */
+#define SSINTEN 0x08 /* SPI/I2S interrupt enable register */
+#define SSDATR 0x10 /* SPI/I2S data register */
+#define SSPSP 0x18 /* SPI/I2S programmable serial protocol control register */
+#define SSRWT 0x24 /* SPI/I2S root control register */
+
+/* SPI/I2S Work data size, register bits value 0~31 indicated data size 1~32 bits */
+#define SSCR_FIELD_DSS GENMASK(9, 5)
+#define SSCR_DW_8BYTE FIELD_PREP(SSCR_FIELD_DSS, 0x7)
+#define SSCR_DW_16BYTE FIELD_PREP(SSCR_FIELD_DSS, 0xf)
+#define SSCR_DW_18BYTE FIELD_PREP(SSCR_FIELD_DSS, 0x11)
+#define SSCR_DW_32BYTE FIELD_PREP(SSCR_FIELD_DSS, 0x1f)
+
+#define SSCR_SSE BIT(0) /* SPI/I2S Enable */
+#define SSCR_FRF_PSP GENMASK(2, 1) /* Frame Format*/
+#define SSCR_TRAIL BIT(13) /* Trailing Byte */
+
+#define SSFCR_FIELD_TFT GENMASK(3, 0) /* TXFIFO Trigger Threshold */
+#define SSFCR_FIELD_RFT GENMASK(8, 5) /* RXFIFO Trigger Threshold */
+#define SSFCR_TSRE BIT(10) /* Transmit Service Request Enable */
+#define SSFCR_RSRE BIT(11) /* Receive Service Request Enable */
+
+#define SSPSP_FSRT BIT(3) /* Frame Sync Relative Timing Bit */
+#define SSPSP_SFRMP BIT(4) /* Serial Frame Polarity */
+#define SSPSP_FIELD_SFRMWDTH GENMASK(17, 12) /* Serial Frame Width field */
+
+#define SSRWT_RWOT BIT(0) /* Receive Without Transmit */
+
+#define SPACEMIT_PCM_RATES SNDRV_PCM_RATE_8000_192000
+#define SPACEMIT_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define SPACEMIT_I2S_PERIOD_SIZE 1024
+
+struct spacemit_i2s_dev {
+ struct device *dev;
+
+ void __iomem *base;
+
+ struct reset_control *reset;
+
+ struct clk *sysclk;
+ struct clk *bclk;
+ struct clk *sspa_clk;
+
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
+ struct snd_dmaengine_dai_dma_data playback_dma_data;
+
+ bool has_capture;
+ bool has_playback;
+
+ int dai_fmt;
+
+ int started_count;
+};
+
+static const struct snd_pcm_hardware spacemit_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BATCH,
+ .formats = SPACEMIT_PCM_FORMATS,
+ .rates = SPACEMIT_PCM_RATES,
+ .rate_min = SNDRV_PCM_RATE_8000,
+ .rate_max = SNDRV_PCM_RATE_192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = SPACEMIT_I2S_PERIOD_SIZE * 4 * 4,
+ .period_bytes_min = SPACEMIT_I2S_PERIOD_SIZE * 2,
+ .period_bytes_max = SPACEMIT_I2S_PERIOD_SIZE * 4,
+ .periods_min = 2,
+ .periods_max = 4,
+};
+
+static const struct snd_dmaengine_pcm_config spacemit_dmaengine_pcm_config = {
+ .pcm_hardware = &spacemit_pcm_hardware,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+ .chan_names = {"tx", "rx"},
+ .prealloc_buffer_size = 32 * 1024,
+};
+
+static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s)
+{
+ u32 sscr_val, sspsp_val, ssfcr_val, ssrwt_val;
+
+ sscr_val = SSCR_TRAIL | SSCR_FRF_PSP;
+ ssfcr_val = FIELD_PREP(SSFCR_FIELD_TFT, 5) |
+ FIELD_PREP(SSFCR_FIELD_RFT, 5) |
+ SSFCR_RSRE | SSFCR_TSRE;
+ ssrwt_val = SSRWT_RWOT;
+
+ /* SSPSP register was set by set_fmt */
+ sspsp_val = readl(i2s->base + SSPSP);
+ sspsp_val |= SSPSP_SFRMP;
+
+ writel(sscr_val, i2s->base + SSCR);
+ writel(ssfcr_val, i2s->base + SSFCR);
+ writel(sspsp_val, i2s->base + SSPSP);
+ writel(ssrwt_val, i2s->base + SSRWT);
+ writel(0, i2s->base + SSINTEN);
+}
+
+static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
+ struct snd_dmaengine_dai_dma_data *dma_data;
+ u32 data_width, data_bits;
+ unsigned long bclk_rate;
+ u32 val;
+ int ret;
+
+ val = readl(i2s->base + SSCR);
+ if (val & SSCR_SSE)
+ return 0;
+
+ dma_data = &i2s->playback_dma_data;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ dma_data = &i2s->capture_dma_data;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ data_bits = 8;
+ data_width = SSCR_DW_8BYTE;
+ dma_data->maxburst = 8;
+ dma_data->addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ data_bits = 16;
+ data_width = SSCR_DW_16BYTE;
+ dma_data->maxburst = 16;
+ dma_data->addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ if ((i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) {
+ data_width = SSCR_DW_32BYTE;
+ dma_data->maxburst = 32;
+ dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ }
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ data_bits = 32;
+ data_width = SSCR_DW_32BYTE;
+ dma_data->maxburst = 32;
+ dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ break;
+ default:
+ dev_dbg(i2s->dev, "unexpected data width type");
+ return -EINVAL;
+ }
+
+ val = readl(i2s->base + SSCR);
+ val &= ~SSCR_DW_32BYTE;
+ val |= data_width;
+ writel(val, i2s->base + SSCR);
+
+ bclk_rate = params_channels(params) *
+ params_rate(params) *
+ data_bits;
+
+ ret = clk_set_rate(i2s->bclk, bclk_rate);
+ if (ret)
+ return ret;
+
+ return clk_set_rate(i2s->sspa_clk, bclk_rate);
+}
+
+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);
+
+ if (freq == 0)
+ return 0;
+
+ return clk_set_rate(i2s->sysclk, freq);
+}
+
+static int spacemit_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct spacemit_i2s_dev *i2s = dev_get_drvdata(cpu_dai->dev);
+ u32 sspsp_val;
+
+ sspsp_val = readl(i2s->base + SSPSP);
+ sspsp_val &= ~SSPSP_FIELD_SFRMWDTH;
+
+ i2s->dai_fmt = fmt;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ cpu_dai->driver->playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ cpu_dai->driver->capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
+ sspsp_val |= FIELD_PREP(SSPSP_FIELD_SFRMWDTH, 0x10) |
+ SSPSP_FSRT;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ cpu_dai->driver->playback.channels_min = 1;
+ cpu_dai->driver->playback.channels_max = 1;
+ cpu_dai->driver->capture.channels_min = 1;
+ cpu_dai->driver->capture.channels_max = 1;
+ cpu_dai->driver->playback.formats = SNDRV_PCM_FMTBIT_S32_LE;
+ cpu_dai->driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE;
+ sspsp_val |= FIELD_PREP(SSPSP_FIELD_SFRMWDTH, 0x1);
+ break;
+ default:
+ dev_dbg(i2s->dev, "unexpected format type");
+ return -EINVAL;
+ }
+
+ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A)
+ sspsp_val |= SSPSP_FSRT;
+
+ writel(sspsp_val, i2s->base + SSPSP);
+
+ return 0;
+}
+
+static int spacemit_i2s_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
+ u32 val;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!i2s->started_count) {
+ val = readl(i2s->base + SSCR);
+ val |= SSCR_SSE;
+ writel(val, i2s->base + SSCR);
+ }
+ i2s->started_count++;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (i2s->started_count)
+ i2s->started_count--;
+
+ if (!i2s->started_count) {
+ val = readl(i2s->base + SSCR);
+ val &= ~SSCR_SSE;
+ writel(val, i2s->base + SSCR);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spacemit_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai,
+ i2s->has_playback ? &i2s->playback_dma_data : NULL,
+ i2s->has_capture ? &i2s->capture_dma_data : NULL);
+
+ reset_control_deassert(i2s->reset);
+
+ spacemit_i2s_init(i2s);
+
+ return 0;
+}
+
+static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai)
+{
+ struct spacemit_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
+
+ reset_control_assert(i2s->reset);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
+ .probe = spacemit_i2s_dai_probe,
+ .remove = spacemit_i2s_dai_remove,
+ .hw_params = spacemit_i2s_hw_params,
+ .set_sysclk = spacemit_i2s_set_sysclk,
+ .set_fmt = spacemit_i2s_set_fmt,
+ .trigger = spacemit_i2s_trigger,
+};
+
+static struct snd_soc_dai_driver spacemit_i2s_dai = {
+ .ops = &spacemit_i2s_dai_ops,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SPACEMIT_PCM_RATES,
+ .rate_min = SNDRV_PCM_RATE_8000,
+ .rate_max = SNDRV_PCM_RATE_192000,
+ .formats = SPACEMIT_PCM_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SPACEMIT_PCM_RATES,
+ .rate_min = SNDRV_PCM_RATE_8000,
+ .rate_max = SNDRV_PCM_RATE_192000,
+ .formats = SPACEMIT_PCM_FORMATS,
+ },
+ .symmetric_rate = 1,
+};
+
+static int spacemit_i2s_init_dai(struct spacemit_i2s_dev *i2s,
+ struct snd_soc_dai_driver **dp,
+ dma_addr_t addr)
+{
+ struct device_node *node = i2s->dev->of_node;
+ struct snd_soc_dai_driver *dai;
+ struct property *dma_names;
+ const char *dma_name;
+
+ of_property_for_each_string(node, "dma-names", dma_names, dma_name) {
+ if (!strcmp(dma_name, "tx"))
+ i2s->has_playback = true;
+ if (!strcmp(dma_name, "rx"))
+ i2s->has_capture = true;
+ }
+
+ dai = devm_kmemdup(i2s->dev, &spacemit_i2s_dai,
+ sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ if (i2s->has_playback) {
+ dai->playback.stream_name = "Playback";
+ dai->playback.channels_min = 1;
+ dai->playback.channels_max = 2;
+ dai->playback.rates = SPACEMIT_PCM_RATES;
+ dai->playback.formats = SPACEMIT_PCM_FORMATS;
+
+ i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ i2s->playback_dma_data.maxburst = 32;
+ i2s->playback_dma_data.addr = addr;
+ }
+
+ if (i2s->has_capture) {
+ dai->capture.stream_name = "Capture";
+ dai->capture.channels_min = 1;
+ dai->capture.channels_max = 2;
+ dai->capture.rates = SPACEMIT_PCM_RATES;
+ dai->capture.formats = SPACEMIT_PCM_FORMATS;
+
+ i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ i2s->capture_dma_data.maxburst = 32;
+ i2s->capture_dma_data.addr = addr;
+ }
+
+ if (dp)
+ *dp = dai;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver spacemit_i2s_component = {
+ .name = "i2s-k1",
+ .legacy_dai_naming = 1,
+};
+
+static int spacemit_i2s_probe(struct platform_device *pdev)
+{
+ struct snd_soc_dai_driver *dai;
+ struct spacemit_i2s_dev *i2s;
+ struct resource *res;
+ struct clk *clk;
+ int ret;
+
+ i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+ if (!i2s)
+ return -ENOMEM;
+
+ i2s->dev = &pdev->dev;
+
+ i2s->sysclk = devm_clk_get_enabled(i2s->dev, "sysclk");
+ if (IS_ERR(i2s->sysclk))
+ return dev_err_probe(i2s->dev, PTR_ERR(i2s->sysclk),
+ "failed to enable sysbase clock\n");
+
+ i2s->bclk = devm_clk_get_enabled(i2s->dev, "bclk");
+ if (IS_ERR(i2s->bclk))
+ return dev_err_probe(i2s->dev, PTR_ERR(i2s->bclk), "failed to enable bit clock\n");
+
+ clk = devm_clk_get_enabled(i2s->dev, "sspa_bus");
+ if (IS_ERR(clk))
+ return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable sspa_bus clock\n");
+
+ i2s->sspa_clk = devm_clk_get_enabled(i2s->dev, "sspa");
+ if (IS_ERR(clk))
+ return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable sspa 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");
+
+ i2s->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(i2s->reset))
+ return dev_err_probe(i2s->dev, PTR_ERR(i2s->reset),
+ "failed to get reset control");
+
+ dev_set_drvdata(i2s->dev, i2s);
+
+ spacemit_i2s_init_dai(i2s, &dai, res->start + SSDATR);
+
+ ret = devm_snd_soc_register_component(i2s->dev,
+ &spacemit_i2s_component,
+ dai, 1);
+ if (ret)
+ return dev_err_probe(i2s->dev, ret, "failed to register component");
+
+ return devm_snd_dmaengine_pcm_register(&pdev->dev, &spacemit_dmaengine_pcm_config, 0);
+}
+
+static void spacemit_i2s_remove(struct platform_device *pdev)
+{
+ /* resources auto-freed by devm_ */
+}
+
+static const struct of_device_id spacemit_i2s_of_match[] = {
+ { .compatible = "spacemit,k1-i2s", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spacemit_i2s_of_match);
+
+static struct platform_driver spacemit_i2s_driver = {
+ .probe = spacemit_i2s_probe,
+ .remove = spacemit_i2s_remove,
+ .driver = {
+ .name = "i2s-k1",
+ .of_match_table = spacemit_i2s_of_match,
+ },
+};
+module_platform_driver(spacemit_i2s_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("I2S bus driver for SpacemiT K1 SoC");
--
2.50.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] ASoC: spacemit: add i2s support for K1 SoC
2025-08-28 3:37 ` [PATCH v2 2/2] ASoC: spacemit: add i2s support for K1 SoC Troy Mitchell
@ 2025-08-28 9:04 ` Mark Brown
2025-09-02 1:39 ` Troy Mitchell
0 siblings, 1 reply; 7+ messages in thread
From: Mark Brown @ 2025-08-28 9:04 UTC (permalink / raw)
To: Troy Mitchell
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Yixun Lan, Jaroslav Kysela, Takashi Iwai, Philipp Zabel,
linux-sound, devicetree, linux-riscv, spacemit, linux-kernel,
Jinmei Wei
[-- Attachment #1: Type: text/plain, Size: 593 bytes --]
On Thu, Aug 28, 2025 at 11:37:33AM +0800, Troy Mitchell wrote:
> + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> + case SND_SOC_DAIFMT_DSP_A:
> + case SND_SOC_DAIFMT_DSP_B:
> + cpu_dai->driver->playback.channels_min = 1;
> + cpu_dai->driver->playback.channels_max = 1;
> + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A)
> + sspsp_val |= SSPSP_FSRT;
It's weird and confusing that this isn't part of the above switch case.
> +static void spacemit_i2s_remove(struct platform_device *pdev)
> +{
> + /* resources auto-freed by devm_ */
> +}
If this can be empty remove it.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] ASoC: dt-bindings: Add bindings for SpacemiT K1
2025-08-28 3:37 ` [PATCH v2 1/2] ASoC: dt-bindings: Add bindings for SpacemiT K1 Troy Mitchell
@ 2025-08-29 17:16 ` Rob Herring
2025-09-02 1:36 ` Troy Mitchell
0 siblings, 1 reply; 7+ messages in thread
From: Rob Herring @ 2025-08-29 17:16 UTC (permalink / raw)
To: Troy Mitchell
Cc: Liam Girdwood, Mark Brown, Krzysztof Kozlowski, Conor Dooley,
Yixun Lan, Jaroslav Kysela, Takashi Iwai, Philipp Zabel,
linux-sound, devicetree, linux-riscv, spacemit, linux-kernel
On Thu, Aug 28, 2025 at 11:37:32AM +0800, Troy Mitchell wrote:
> Add dt-binding for the i2s driver of SpacemiT's K1 SoC.
>
> Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
> ---
> .../devicetree/bindings/sound/spacemit,k1-i2s.yaml | 88 ++++++++++++++++++++++
> 1 file changed, 88 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..042001c38ed8d434889183831e44289ea9c5aef2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
> @@ -0,0 +1,88 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/spacemit,k1-i2s.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: K1 I2S controller
> +
> +description:
> + The I2S bus (Inter-IC sound bus) is a serial link for digital
> + audio data transfer between devices in the system.
> +
> +maintainers:
> + - Troy Mitchell <troy.mitchell@linux.spacemit.com>
> +
> +allOf:
> + - $ref: dai-common.yaml#
> +
> +properties:
> + compatible:
> + const: spacemit,k1-i2s
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + items:
> + - description: clock for I2S sysclk
> + - description: clock for I2S bclk
> + - description: clock for I2S bus
> + - description: clock for I2S controller
> +
> + clock-names:
> + items:
> + - const: sysclk
> + - const: bclk
> + - const: bus
> + - const: func
> +
> + dmas:
> + minItems: 1
> + maxItems: 2
> +
> + dma-names:
> + oneOf:
> + - const: rx
> + - items:
> + - const: tx
> + - const: rx
If tx is optional, wouldn't this be simpler:
minItems: 1
items:
- const: rx
- const: tx
> +
> + resets:
> + maxItems: 1
> +
> + port:
> + $ref: audio-graph-port.yaml#
> + unevaluatedProperties: false
> +
> + "#sound-dai-cells":
> + const: 0
> +
> +required:
> + - compatible
> + - reg
> + - clocks
> + - clock-names
> + - dmas
> + - dma-names
> + - resets
> + - "#sound-dai-cells"
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/spacemit,k1-syscon.h>
> + i2s@d4026000 {
> + compatible = "spacemit,k1-i2s";
> + reg = <0xd4026000 0x30>;
> + clocks = <&syscon_mpmu CLK_I2S_SYSCLK>,
> + <&syscon_mpmu CLK_I2S_BCLK>,
> + <&syscon_apbc CLK_SSPA0_BUS>,
> + <&syscon_apbc CLK_SSPA0>;
> + clock-names = "sysclk", "bclk", "bus", "func";
> + dmas = <&pdma0 21>, <&pdma0 22>;
> + dma-names = "tx", "rx";
> + resets = <&syscon_apbc RESET_SSPA0>;
> + #sound-dai-cells = <0>;
> + };
>
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] ASoC: dt-bindings: Add bindings for SpacemiT K1
2025-08-29 17:16 ` Rob Herring
@ 2025-09-02 1:36 ` Troy Mitchell
0 siblings, 0 replies; 7+ messages in thread
From: Troy Mitchell @ 2025-09-02 1:36 UTC (permalink / raw)
To: Rob Herring, Troy Mitchell
Cc: Liam Girdwood, Mark Brown, Krzysztof Kozlowski, Conor Dooley,
Yixun Lan, Jaroslav Kysela, Takashi Iwai, Philipp Zabel,
linux-sound, devicetree, linux-riscv, spacemit, linux-kernel
On Fri, Aug 29, 2025 at 12:16:24PM -0500, Rob Herring wrote:
> On Thu, Aug 28, 2025 at 11:37:32AM +0800, Troy Mitchell wrote:
> > Add dt-binding for the i2s driver of SpacemiT's K1 SoC.
> >
> > Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
> > ---
> > .../devicetree/bindings/sound/spacemit,k1-i2s.yaml | 88 ++++++++++++++++++++++
> > 1 file changed, 88 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..042001c38ed8d434889183831e44289ea9c5aef2
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
[...]
> > + dmas:
> > + minItems: 1
> > + maxItems: 2
> > +
> > + dma-names:
> > + oneOf:
> > + - const: rx
> > + - items:
> > + - const: tx
> > + - const: rx
>
> If tx is optional, wouldn't this be simpler:
>
> minItems: 1
> items:
> - const: rx
> - const: tx
>
Thanks! I will simplify this in the next version
- Troy
>
> > +
> > + resets:
> > + maxItems: 1
> > +
> > + port:
> > + $ref: audio-graph-port.yaml#
> > + unevaluatedProperties: false
> > +
> > + "#sound-dai-cells":
> > + const: 0
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - clocks
> > + - clock-names
> > + - dmas
> > + - dma-names
> > + - resets
> > + - "#sound-dai-cells"
> > +
> > +unevaluatedProperties: false
> > +
> > +examples:
> > + - |
> > + #include <dt-bindings/clock/spacemit,k1-syscon.h>
> > + i2s@d4026000 {
> > + compatible = "spacemit,k1-i2s";
> > + reg = <0xd4026000 0x30>;
> > + clocks = <&syscon_mpmu CLK_I2S_SYSCLK>,
> > + <&syscon_mpmu CLK_I2S_BCLK>,
> > + <&syscon_apbc CLK_SSPA0_BUS>,
> > + <&syscon_apbc CLK_SSPA0>;
> > + clock-names = "sysclk", "bclk", "bus", "func";
> > + dmas = <&pdma0 21>, <&pdma0 22>;
> > + dma-names = "tx", "rx";
> > + resets = <&syscon_apbc RESET_SSPA0>;
> > + #sound-dai-cells = <0>;
> > + };
> >
> > --
> > 2.50.1
> >
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] ASoC: spacemit: add i2s support for K1 SoC
2025-08-28 9:04 ` Mark Brown
@ 2025-09-02 1:39 ` Troy Mitchell
0 siblings, 0 replies; 7+ messages in thread
From: Troy Mitchell @ 2025-09-02 1:39 UTC (permalink / raw)
To: Mark Brown, Troy Mitchell
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Yixun Lan, Jaroslav Kysela, Takashi Iwai, Philipp Zabel,
linux-sound, devicetree, linux-riscv, spacemit, linux-kernel,
Jinmei Wei
On Thu, Aug 28, 2025 at 11:04:19AM +0200, Mark Brown wrote:
> On Thu, Aug 28, 2025 at 11:37:33AM +0800, Troy Mitchell wrote:
>
> > + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> > + case SND_SOC_DAIFMT_DSP_A:
> > + case SND_SOC_DAIFMT_DSP_B:
> > + cpu_dai->driver->playback.channels_min = 1;
> > + cpu_dai->driver->playback.channels_max = 1;
>
> > + if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A)
> > + sspsp_val |= SSPSP_FSRT;
>
> It's weird and confusing that this isn't part of the above switch case.
Thanks! I'll change it.
>
> > +static void spacemit_i2s_remove(struct platform_device *pdev)
> > +{
> > + /* resources auto-freed by devm_ */
> > +}
>
> If this can be empty remove it.
Yes, I will remove it in the next version.
Best regards,
Troy
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-09-02 1:40 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-28 3:37 [PATCH v2 0/2] ASoC: spacemit: add i2s support to K1 SoC Troy Mitchell
2025-08-28 3:37 ` [PATCH v2 1/2] ASoC: dt-bindings: Add bindings for SpacemiT K1 Troy Mitchell
2025-08-29 17:16 ` Rob Herring
2025-09-02 1:36 ` Troy Mitchell
2025-08-28 3:37 ` [PATCH v2 2/2] ASoC: spacemit: add i2s support for K1 SoC Troy Mitchell
2025-08-28 9:04 ` Mark Brown
2025-09-02 1:39 ` Troy Mitchell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).