From nobody Thu Oct 2 20:46:43 2025 Received: from bg1.exmail.qq.com (bg1.exmail.qq.com [114.132.77.159]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B568329F29; Thu, 11 Sep 2025 05:47:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=114.132.77.159 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757569673; cv=none; b=gKQXfcq4D8tPzPN5ay7PsT5jIhZ1yHsNk6M0Cn5Zc4Xo+jzHFjtQKBmMpBRn6bPRI/NdWfcyc1bj90Bj4KbUiz4jor+gwkajRFJI0c9qAXrqpCa/nLlb7bsl1qntolJs6TOVobCKCZWcbSrH43CvKx4jFiGuQXH57j/w7DEaXIA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757569673; c=relaxed/simple; bh=MZyNehkEDO+xrWPj2ZXjZEeu4YgI8vPyjedZrtrtDWs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cY9XpVVKaM1N+HJ8ufvYrLaFz4yqEzzbaZYzYEGJ+/slzUTNsjyUty7UnhXFmkpHdjFQVkj731MSZ+tcoLovTsrOBECti4zXq5aM85flsPDgmE4NR24RpjgQUFerwqzSZsFN/xfnVa+5nQjq5C56jFwvZjR02E5rqTLpR93wZAw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.spacemit.com; spf=none smtp.mailfrom=linux.spacemit.com; dkim=pass (1024-bit key) header.d=linux.spacemit.com header.i=@linux.spacemit.com header.b=RYRfsaYM; arc=none smtp.client-ip=114.132.77.159 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.spacemit.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.spacemit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.spacemit.com header.i=@linux.spacemit.com header.b="RYRfsaYM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.spacemit.com; s=mxsw2412; t=1757569650; bh=Pd8E5nwso3tDIIp7ab7uxQOFaM7OtDLMcKjQtOfLAWA=; h=From:Date:Subject:MIME-Version:Message-Id:To; b=RYRfsaYMsG9WaX6QfF9V2PDpNBsqfSgVgPVZBRMmsOhWHRArJut60gKPcyZgkPEfe KJ2QdjdVrr9k0b24O4u3qJara7moqvF1xIPS3i0BVSf6ZwjGL9Mq6Of6BRjjtsFf2D QHK07tQvQC+K8OIOw3uIYHB3TtqNz5GK694fTrP0= X-QQ-mid: esmtpsz18t1757569645tbae29400 X-QQ-Originating-IP: sDZRU4N6vZL21xBIP2dp/dXDI3uIkBybEVLTmW+dvvg= Received: from = ( [61.145.255.150]) by bizesmtp.qq.com (ESMTP) with id ; Thu, 11 Sep 2025 13:47:22 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 16154328192209350849 EX-QQ-RecipientCnt: 15 From: Troy Mitchell Date: Thu, 11 Sep 2025 13:47:10 +0800 Subject: [PATCH v3 1/2] ASoC: dt-bindings: Add bindings for SpacemiT K1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250911-k1-i2s-v3-1-57f173732f9c@linux.spacemit.com> References: <20250911-k1-i2s-v3-0-57f173732f9c@linux.spacemit.com> In-Reply-To: <20250911-k1-i2s-v3-0-57f173732f9c@linux.spacemit.com> To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Jaroslav Kysela , Takashi Iwai , Philipp Zabel Cc: linux-sound@vger.kernel.org, devicetree@vger.kernel.org, linux-riscv@lists.infradead.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, Troy Mitchell X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1757569637; l=2552; i=troy.mitchell@linux.spacemit.com; s=20250710; h=from:subject:message-id; bh=MZyNehkEDO+xrWPj2ZXjZEeu4YgI8vPyjedZrtrtDWs=; b=mGBVFiExQ0QO9T+P2Au+nmTf7TOKFhgkQB2q33d8wdm16gjBqxAViQU8m01yMF5WAg6AZEqQc 303tdXTjQNQAxEPHGlPxDVxIdss5utvuKzTiMVT/N24cLnQ0LhOoc8z X-Developer-Key: i=troy.mitchell@linux.spacemit.com; a=ed25519; pk=lQa7BzLrq8DfZnChqmwJ5qQk8fP2USmY/4xZ2/MSsXc= X-QQ-SENDSIZE: 520 Feedback-ID: esmtpsz:linux.spacemit.com:qybglogicsvrsz:qybglogicsvrsz3a-0 X-QQ-XMAILINFO: N23fUA7tbDKk8aTdHiDiRP8Aps/pnmoZlhs9HVmCq2v9v/pKcxi/TWE9 kSUKsUTRzuSrx7UjcjfH7AI1tV2VLcAQqeoj7FR5pDBTEqCvu8Xle+9/Zk41olQ3KQIZcBw L79GCQC9b/FIaENGIAVZldBpt5el+EjG736OdLyv8wdHLlfRT2Dej1qTWRV9mG5yWEm2DWB 0eCRk4u+MPNL1J6R8MHFySJeLWRV7LRqxzBjbSqEo1Gf+EGTbGxqNTMVQ9sOtz0RM5K3CXg TsG400gbiQNsY5iRckFN3yb658pwTpaxrxvV0RKEdHtBFq69ytnU2zF6inkAPNrGmKmdt1o nCio5NDyOE4TUWcW0pfONBzsOqmQli3fZxz1zFLUhK3Irrk+JGYAEgGyp9HD8R5yghxf4by 9KEQazxFvdRgo67He1hoO1pIT8t4AL1XUUbo/ZjFpZfZ5Efi2BOa2LvhaVfd1UkYzhFiH4M o8/hRFjUNHD2I6Aiv1Eb+cXi4oj99Elnox+OtCOxz2lFdhnPFFNkS6GmhDInic8y0VPRnny Gvb5F574LVvWEMJF1canEP1c1HarolLreAaJOAy7/uI52wuYYd4s0IodZkecp9cXhZgbdwD Vu3z0hhilD9bZ3/eHX77WsWK5ikfxaFOAldj3Asrwc/ACeG/2hkotWexLtyI6wugFMUTFMS Ugo0BtmX2/DwKAr0AYobve8yPVI5lBpL6Lvc/kGE6yN04unGKT9Tv/nscurMNGwIqIYpnRF pKDsbJ5eWOvs7DeZGkbwwFYWGSNCFd0V+8LuyiWyYdyJOt1+PHhp9d4zyPBs7wzuVOSrIWu RAOzculnPJ0Y/Egqo9yBPVHhz6E9Zv7DH/neCBdcnitVxSThwTEGjeWzgkfCFR44RPI397C Mfq9EdvdIpqx7KWJu7/4+BkTcz5tXBs7aAdPdhhZV1vDHVwIgetpi3qNxf9e5PP9hnIo+vS rP2/AcgPppilzk+ueSQ1x/N0pPbtXMNkG6op/db6O4vsJjZqgHI/fM2JovPkjEiug3hlc8b ghe+xEYtCXY09M52AYtQuHYvGAA6ykXL1pvAVBUDYkD0hJLbYFm7waufok1n4w9tS7WwmM5 YcB298fvd/ubMa25ZDxqaI= X-QQ-XMRINFO: NyFYKkN4Ny6FSmKK/uo/jdU= X-QQ-RECHKSPAM: 0 Add dt-binding for the i2s driver of SpacemiT's K1 SoC. Signed-off-by: Troy Mitchell Reviewed-by: Krzysztof Kozlowski --- .../devicetree/bindings/sound/spacemit,k1-i2s.yaml | 87 ++++++++++++++++++= ++++ 1 file changed, 87 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..55bd0b307d22b3611d0fefb1e92= 5e56812848dd1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml @@ -0,0 +1,87 @@ +# 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 + +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: + minItems: 1 + 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 + i2s@d4026000 { + compatible =3D "spacemit,k1-i2s"; + reg =3D <0xd4026000 0x30>; + clocks =3D <&syscon_mpmu CLK_I2S_SYSCLK>, + <&syscon_mpmu CLK_I2S_BCLK>, + <&syscon_apbc CLK_SSPA0_BUS>, + <&syscon_apbc CLK_SSPA0>; + clock-names =3D "sysclk", "bclk", "bus", "func"; + dmas =3D <&pdma0 21>, <&pdma0 22>; + dma-names =3D "tx", "rx"; + resets =3D <&syscon_apbc RESET_SSPA0>; + #sound-dai-cells =3D <0>; + }; --=20 2.51.0 From nobody Thu Oct 2 20:46:43 2025 Received: from smtpbgeu2.qq.com (smtpbgeu2.qq.com [18.194.254.142]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80B051547EE; Thu, 11 Sep 2025 05:47:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=18.194.254.142 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757569674; cv=none; b=ODL6n9hOZmt0IHHXIH+q/Qj3gAM56xQ5zl8QKIL3fJwEDasl5/s4b1t2fCBKpcuKRZQHBr/Cn3crEpIPDqCZemipd+k6xj35u+ct9cGFgsax5+Hm4IK1Dt1epLBmD38KsnWOe3xKdbmUGqU0m1H29+e1rdb/xgvAToRPxnIm8Mo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757569674; c=relaxed/simple; bh=zK8LMmHbIkTY2CxWFVEckzWhjuSEBhp0hFGvp9BouSo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UZfg8mdTCB5VyHGUwQrAe2nlE1mMrLO/s1ssumS7M41nGyFURxRq+Ii9xdl4IOejxHYhxmfBKSSM7pxhlPXLb6t6a61UxeY4wicgbsQGEEcoWsrlR3gnE5DGz+gqTQL4XUYvLhIMgMqMO8qj2R8QWCP4ZpsubEjZ+FhioHCOwhY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.spacemit.com; spf=none smtp.mailfrom=linux.spacemit.com; dkim=pass (1024-bit key) header.d=linux.spacemit.com header.i=@linux.spacemit.com header.b=LnFIe4Ix; arc=none smtp.client-ip=18.194.254.142 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.spacemit.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.spacemit.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.spacemit.com header.i=@linux.spacemit.com header.b="LnFIe4Ix" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.spacemit.com; s=mxsw2412; t=1757569654; bh=ncwgHCcAhrlegs4GgjUefcgixGpNnD5+gsnZBPYmo0c=; h=From:Date:Subject:MIME-Version:Message-Id:To; b=LnFIe4IxQNQg5pqhJ2Nm7JSej/oRSE/xfStVCBM+QY+OceALgjCyflXW40HNxQJMo gY6oAtEviV17a3X88twZQdvHwW0I6Jsv/UAm2R+LwiFfv8ApDfDhn9n0MLPY+Gcuey bXFfYaX631O27xS9ihqd5i2tQ2GmlnxTH/rptjUY= X-QQ-mid: zesmtpsz1t1757569648ta7f41e22 X-QQ-Originating-IP: Vja+2/xRh6ptXbvrjpjcQe7X9DVN6iu3VNss6D1uFv4= Received: from = ( [61.145.255.150]) by bizesmtp.qq.com (ESMTP) with id ; Thu, 11 Sep 2025 13:47:26 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 9312944315426298178 EX-QQ-RecipientCnt: 16 From: Troy Mitchell Date: Thu, 11 Sep 2025 13:47:11 +0800 Subject: [PATCH v3 2/2] ASoC: spacemit: add i2s support for K1 SoC Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250911-k1-i2s-v3-2-57f173732f9c@linux.spacemit.com> References: <20250911-k1-i2s-v3-0-57f173732f9c@linux.spacemit.com> In-Reply-To: <20250911-k1-i2s-v3-0-57f173732f9c@linux.spacemit.com> To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Yixun Lan , Jaroslav Kysela , Takashi Iwai , Philipp Zabel Cc: linux-sound@vger.kernel.org, devicetree@vger.kernel.org, linux-riscv@lists.infradead.org, spacemit@lists.linux.dev, linux-kernel@vger.kernel.org, Troy Mitchell , Jinmei Wei X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1757569637; l=16194; i=troy.mitchell@linux.spacemit.com; s=20250710; h=from:subject:message-id; bh=zK8LMmHbIkTY2CxWFVEckzWhjuSEBhp0hFGvp9BouSo=; b=uiV7AwrekF7p/xZPofxHkZ2DLiv/LIzAJcnc2dGfd01VkmYk032bwNzAWveXowP1TVxbRxbDz q+0A3G6G0baAqRwa7Erz/b7oFkwK4U03/CrYkFsQWAtyGZMxcmSlWNg X-Developer-Key: i=troy.mitchell@linux.spacemit.com; a=ed25519; pk=lQa7BzLrq8DfZnChqmwJ5qQk8fP2USmY/4xZ2/MSsXc= X-QQ-SENDSIZE: 520 Feedback-ID: zesmtpsz:linux.spacemit.com:qybglogicsvrsz:qybglogicsvrsz3a-0 X-QQ-XMAILINFO: NeEWVnpZ66Aw75s349msFNTZRioK1z9Q6N8O8vtJbLNe6kyGZUdUrnok NqQRl9RysnKHWvEjVk5uHHHVsqNJ08y+Z9du9JHnIyKsMtAEK0MBVuyom48xFYRoNqvrGXt 1tkqANDzdWhskhtZn4fbvwIY/sUTfacjqFgZWsFR9oG5a0KxXKDMxj9k7oRxNExgHyvp7wZ FmpNv2SD8IPF6DPx/YBib7diOhRvC/Xa8FXNPrblosWv2Ih8BcMMNCyVmQFoqksmECW+TnK vo7rsbxeIdYUkF3s0dPvz1wgFDvLbXm17mzgoDM6oy8t1GK0PcE+gMh1bxrKeSkHOC5WYKW DL2FDQwQy6rireXKFKXzKf+f17Z/prqU8r91B4EaWjPnuV+WV86nEgrX75FOQC1d5zYg8VL ES5X6vAnsOGaeFckJl3pp7UU7Y/RXqwSq8ZcMEpR5MA1n/szE+/thBi0+2tKsVJf51HrZEM jh4Z36/l9PcJxwJRzeINZ0euEQt7dChQ7yj1rq3VrxEfp4kXWU6tWXV8V+t7YwBb/P0vs25 W9oUU8kXdziLwQKLRRNZm+MKlTkvMPzHZIydAEpTFnld4L7XmVhd5w6CuuqgJyRN+HQ2DAr iZ9u6esOgwXQCXh1p00rmeiOAESQQGVjDaucV57dsnEs6VmMPC8lHo+p79XqRkyjgmVgUoD B41N6WyrHEU5jPsJdx+vIWSzXuELxvgee4+TtqwRVN0IUyL6fbnOFrcAfX02LRpUXNhQac+ n9d2oWuK2ArspwyJVc7CH2HlFEXGHmIPw5nvehiJDq53r8fOGSNgYMloawAMOseV3lojgD2 UHamnff6MR26FAXPVwwuMbLluZStylOzXWT4VHP1QgKmeL0Sq5SYgYNJ2tFm6MaDc3ELuxR nyhCFHI48h3zcer10bEC5cuR5bncJs0lC54uwIX7OkYYVAUwtL3sOBp/Vkoc6Hz+koxcsdx buymjoQhuXL2eFY2UWJlENg6hKfpERpytgTRPrCTZURNtG9yXYGxyajyuRBhCJaCet4q0cy ZuLNKYs03nzSDXLALgbXugmGOa6fN+7QOTsFuXdyVfoyua1pZBtsWujsmNrIka4vDdlH1k7 g/ALnMcOcdhH79CLQUWCHXkSZGG3HRCOg== X-QQ-XMRINFO: NI4Ajvh11aEj8Xl/2s1/T8w= X-QQ-RECHKSPAM: 0 Add ASoC platform driver for the SpacemiT K1 SoC full-duplex I2S controller. Co-developer: Jinmei Wei Signed-off-by: Jinmei Wei Signed-off-by: Troy Mitchell --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/spacemit/Kconfig | 16 ++ sound/soc/spacemit/Makefile | 5 + sound/soc/spacemit/k1_i2s.c | 444 ++++++++++++++++++++++++++++++++++++++++= ++++ 5 files changed, 467 insertions(+) diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index ce74818bd7152dbe110b9fff7d908b0ddf34a9f5..36e0d443ba0ebe584ffe797c378= c838f448ffcb9 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..8c0480e6484e75eb0b6db306630= ba77d259ba8e3 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_SND_SOC) +=3D rockchip/ obj-$(CONFIG_SND_SOC) +=3D samsung/ obj-$(CONFIG_SND_SOC) +=3D sdca/ obj-$(CONFIG_SND_SOC) +=3D sof/ +obj-$(CONFIG_SND_SOC) +=3D spacemit/ obj-$(CONFIG_SND_SOC) +=3D spear/ obj-$(CONFIG_SND_SOC) +=3D sprd/ obj-$(CONFIG_SND_SOC) +=3D starfive/ diff --git a/sound/soc/spacemit/Kconfig b/sound/soc/spacemit/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..2179f94f3f179c54cd06e6ced55= 23ed3f5225cf4 --- /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..9069de8ef89c84db8cc7d3a4d3b= 154fff9bd7aff --- /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 :=3D k1_i2s.o + +obj-$(CONFIG_SND_SOC_K1_I2S) +=3D 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..bd3eb178e51cb76f824d9960a09= 3eae0af55bfac --- /dev/null +++ b/sound/soc/spacemit/k1_i2s.c @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2025 Troy Mitchell */ + +#include +#include +#include +#include +#include +#include + +#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 regis= ter */ +#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 =3D { + .info =3D SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BATCH, + .formats =3D SPACEMIT_PCM_FORMATS, + .rates =3D SPACEMIT_PCM_RATES, + .rate_min =3D SNDRV_PCM_RATE_8000, + .rate_max =3D SNDRV_PCM_RATE_192000, + .channels_min =3D 1, + .channels_max =3D 2, + .buffer_bytes_max =3D SPACEMIT_I2S_PERIOD_SIZE * 4 * 4, + .period_bytes_min =3D SPACEMIT_I2S_PERIOD_SIZE * 2, + .period_bytes_max =3D SPACEMIT_I2S_PERIOD_SIZE * 4, + .periods_min =3D 2, + .periods_max =3D 4, +}; + +static const struct snd_dmaengine_pcm_config spacemit_dmaengine_pcm_config= =3D { + .pcm_hardware =3D &spacemit_pcm_hardware, + .prepare_slave_config =3D snd_dmaengine_pcm_prepare_slave_config, + .chan_names =3D {"tx", "rx"}, + .prealloc_buffer_size =3D 32 * 1024, +}; + +static void spacemit_i2s_init(struct spacemit_i2s_dev *i2s) +{ + u32 sscr_val, sspsp_val, ssfcr_val, ssrwt_val; + + sscr_val =3D SSCR_TRAIL | SSCR_FRF_PSP; + ssfcr_val =3D FIELD_PREP(SSFCR_FIELD_TFT, 5) | + FIELD_PREP(SSFCR_FIELD_RFT, 5) | + SSFCR_RSRE | SSFCR_TSRE; + ssrwt_val =3D SSRWT_RWOT; + + /* SSPSP register was set by set_fmt */ + sspsp_val =3D readl(i2s->base + SSPSP); + sspsp_val |=3D 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 =3D 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 =3D readl(i2s->base + SSCR); + if (val & SSCR_SSE) + return 0; + + dma_data =3D &i2s->playback_dma_data; + + if (substream->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE) + dma_data =3D &i2s->capture_dma_data; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + data_bits =3D 8; + data_width =3D SSCR_DW_8BYTE; + dma_data->maxburst =3D 8; + dma_data->addr_width =3D DMA_SLAVE_BUSWIDTH_1_BYTE; + break; + case SNDRV_PCM_FORMAT_S16_LE: + data_bits =3D 16; + data_width =3D SSCR_DW_16BYTE; + dma_data->maxburst =3D 16; + dma_data->addr_width =3D DMA_SLAVE_BUSWIDTH_2_BYTES; + if ((i2s->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) =3D=3D SND_SOC_DAIFMT_I2= S) { + data_width =3D SSCR_DW_32BYTE; + dma_data->maxburst =3D 32; + dma_data->addr_width =3D DMA_SLAVE_BUSWIDTH_4_BYTES; + } + break; + case SNDRV_PCM_FORMAT_S32_LE: + data_bits =3D 32; + data_width =3D SSCR_DW_32BYTE; + dma_data->maxburst =3D 32; + dma_data->addr_width =3D DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + default: + dev_dbg(i2s->dev, "unexpected data width type"); + return -EINVAL; + } + + val =3D readl(i2s->base + SSCR); + val &=3D ~SSCR_DW_32BYTE; + val |=3D data_width; + writel(val, i2s->base + SSCR); + + bclk_rate =3D params_channels(params) * + params_rate(params) * + data_bits; + + ret =3D 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 =3D dev_get_drvdata(cpu_dai->dev); + + if (freq =3D=3D 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 =3D dev_get_drvdata(cpu_dai->dev); + u32 sspsp_val; + + sspsp_val =3D readl(i2s->base + SSPSP); + sspsp_val &=3D ~SSPSP_FIELD_SFRMWDTH; + + i2s->dai_fmt =3D fmt; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + cpu_dai->driver->playback.formats =3D SNDRV_PCM_FMTBIT_S16_LE; + cpu_dai->driver->capture.formats =3D SNDRV_PCM_FMTBIT_S16_LE; + sspsp_val |=3D FIELD_PREP(SSPSP_FIELD_SFRMWDTH, 0x10) | + SSPSP_FSRT; + break; + case SND_SOC_DAIFMT_DSP_A: + sspsp_val |=3D SSPSP_FSRT; + case SND_SOC_DAIFMT_DSP_B: + cpu_dai->driver->playback.channels_min =3D 1; + cpu_dai->driver->playback.channels_max =3D 1; + cpu_dai->driver->capture.channels_min =3D 1; + cpu_dai->driver->capture.channels_max =3D 1; + cpu_dai->driver->playback.formats =3D SNDRV_PCM_FMTBIT_S32_LE; + cpu_dai->driver->capture.formats =3D SNDRV_PCM_FMTBIT_S32_LE; + sspsp_val |=3D FIELD_PREP(SSPSP_FIELD_SFRMWDTH, 0x1); + break; + default: + dev_dbg(i2s->dev, "unexpected format type"); + return -EINVAL; + } + + 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 =3D 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 =3D readl(i2s->base + SSCR); + val |=3D 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 =3D readl(i2s->base + SSCR); + val &=3D ~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 =3D 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 =3D snd_soc_dai_get_drvdata(dai); + + reset_control_assert(i2s->reset); + + return 0; +} + +static const struct snd_soc_dai_ops spacemit_i2s_dai_ops =3D { + .probe =3D spacemit_i2s_dai_probe, + .remove =3D spacemit_i2s_dai_remove, + .hw_params =3D spacemit_i2s_hw_params, + .set_sysclk =3D spacemit_i2s_set_sysclk, + .set_fmt =3D spacemit_i2s_set_fmt, + .trigger =3D spacemit_i2s_trigger, +}; + +static struct snd_soc_dai_driver spacemit_i2s_dai =3D { + .ops =3D &spacemit_i2s_dai_ops, + .playback =3D { + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D SPACEMIT_PCM_RATES, + .rate_min =3D SNDRV_PCM_RATE_8000, + .rate_max =3D SNDRV_PCM_RATE_192000, + .formats =3D SPACEMIT_PCM_FORMATS, + }, + .capture =3D { + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D SPACEMIT_PCM_RATES, + .rate_min =3D SNDRV_PCM_RATE_8000, + .rate_max =3D SNDRV_PCM_RATE_192000, + .formats =3D SPACEMIT_PCM_FORMATS, + }, + .symmetric_rate =3D 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 =3D 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 =3D true; + if (!strcmp(dma_name, "rx")) + i2s->has_capture =3D true; + } + + dai =3D devm_kmemdup(i2s->dev, &spacemit_i2s_dai, + sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + if (i2s->has_playback) { + dai->playback.stream_name =3D "Playback"; + dai->playback.channels_min =3D 1; + dai->playback.channels_max =3D 2; + dai->playback.rates =3D SPACEMIT_PCM_RATES; + dai->playback.formats =3D SPACEMIT_PCM_FORMATS; + + i2s->playback_dma_data.addr_width =3D DMA_SLAVE_BUSWIDTH_2_BYTES; + i2s->playback_dma_data.maxburst =3D 32; + i2s->playback_dma_data.addr =3D addr; + } + + if (i2s->has_capture) { + dai->capture.stream_name =3D "Capture"; + dai->capture.channels_min =3D 1; + dai->capture.channels_max =3D 2; + dai->capture.rates =3D SPACEMIT_PCM_RATES; + dai->capture.formats =3D SPACEMIT_PCM_FORMATS; + + i2s->capture_dma_data.addr_width =3D DMA_SLAVE_BUSWIDTH_2_BYTES; + i2s->capture_dma_data.maxburst =3D 32; + i2s->capture_dma_data.addr =3D addr; + } + + if (dp) + *dp =3D dai; + + return 0; +} + +static const struct snd_soc_component_driver spacemit_i2s_component =3D { + .name =3D "i2s-k1", + .legacy_dai_naming =3D 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 =3D devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) + return -ENOMEM; + + i2s->dev =3D &pdev->dev; + + i2s->sysclk =3D 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 =3D 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 =3D 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 =3D devm_clk_get_enabled(i2s->dev, "sspa"); + if (IS_ERR(clk)) + return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable sspa cloc= k\n"); + + i2s->base =3D 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 regist= ers\n"); + + i2s->reset =3D 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 =3D 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_pc= m_config, 0); +} + +static const struct of_device_id spacemit_i2s_of_match[] =3D { + { .compatible =3D "spacemit,k1-i2s", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, spacemit_i2s_of_match); + +static struct platform_driver spacemit_i2s_driver =3D { + .probe =3D spacemit_i2s_probe, + .driver =3D { + .name =3D "i2s-k1", + .of_match_table =3D spacemit_i2s_of_match, + }, +}; +module_platform_driver(spacemit_i2s_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("I2S bus driver for SpacemiT K1 SoC"); --=20 2.51.0