From: Cezary Rojewski <cezary.rojewski@intel.com>
To: linux-sound@vger.kernel.org
Cc: broonie@kernel.org, tiwai@suse.com, perex@perex.cz,
amade@asmblr.net, linux-kernel@vger.kernel.org,
yung-chuan.liao@linux.intel.com, pierre-louis.bossart@linux.dev,
vkoul@kernel.org, Cezary Rojewski <cezary.rojewski@intel.com>
Subject: [PATCH 5/7] ASoC: Intel: avs: SoundWire support
Date: Mon, 2 Nov 2026 19:10:40 +0100 [thread overview]
Message-ID: <20261102181042.1922005-6-cezary.rojewski@intel.com> (raw)
In-Reply-To: <20261102181042.1922005-1-cezary.rojewski@intel.com>
The SoundWire device is part of the Intel HDAudio PCI device. To support
transfer over SoundWire interface it has to be accounted for when
probing the parent device.
Most of the actual job is done by the SoundWire library which is already
part of the kernel. Utilize it in the core functions of the driver to
enumerate SoundWire component and service its interrupts.
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
---
sound/soc/intel/Kconfig | 1 +
sound/soc/intel/avs/Makefile | 4 ++
sound/soc/intel/avs/avs.h | 1 +
sound/soc/intel/avs/cnl.c | 23 ++++++-
sound/soc/intel/avs/core.c | 22 +++++++
sound/soc/intel/avs/loader.c | 3 +
sound/soc/intel/avs/registers.h | 4 ++
sound/soc/intel/avs/soundwire.c | 112 ++++++++++++++++++++++++++++++++
sound/soc/intel/avs/soundwire.h | 56 ++++++++++++++++
9 files changed, 224 insertions(+), 2 deletions(-)
create mode 100644 sound/soc/intel/avs/soundwire.c
create mode 100644 sound/soc/intel/avs/soundwire.h
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 63367364916a..4e453b55fc04 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -106,6 +106,7 @@ config SND_SOC_INTEL_AVS
select SND_HDA_EXT_CORE
select SND_HDA_DSP_LOADER
select SND_INTEL_DSP_CONFIG
+ select SND_INTEL_SOUNDWIRE_ACPI if SOUNDWIRE_INTEL != n
select WANT_DEV_COREDUMP
help
Enable support for Intel(R) cAVS 1.5 platforms with DSP
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile
index 576dc0da381d..1d48953c7a31 100644
--- a/sound/soc/intel/avs/Makefile
+++ b/sound/soc/intel/avs/Makefile
@@ -14,6 +14,10 @@ ifneq ($(CONFIG_DEBUG_FS),)
snd-soc-avs-y += probes.o debugfs.o
endif
+ifneq ($(CONFIG_SOUNDWIRE_INTEL),)
+snd-soc-avs-y += soundwire.o
+endif
+
obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
# Machine support
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index b3af2c4126be..40e65639adb2 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -136,6 +136,7 @@ struct avs_dev {
void __iomem *dsp_ba;
const struct avs_spec *spec;
struct avs_ipc *ipc;
+ struct sdw_intel_ctx *sdw;
struct avs_fw_cfg fw_cfg;
struct avs_hw_cfg hw_cfg;
diff --git a/sound/soc/intel/avs/cnl.c b/sound/soc/intel/avs/cnl.c
index 31fd9f251d6c..7090b91572d8 100644
--- a/sound/soc/intel/avs/cnl.c
+++ b/sound/soc/intel/avs/cnl.c
@@ -6,11 +6,16 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_intel.h>
#include <sound/hdaudio_ext.h>
#include "avs.h"
#include "debug.h"
#include "messages.h"
#include "registers.h"
+#include "soundwire.h"
static void avs_cnl_ipc_interrupt(struct avs_dev *adev)
{
@@ -61,16 +66,30 @@ static void avs_cnl_ipc_interrupt(struct avs_dev *adev)
irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev, int irq)
{
u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
+ u32 adspis2 = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS2);
irqreturn_t ret = IRQ_NONE;
- if (adspis == UINT_MAX)
+ if (adspis == UINT_MAX && adspis2 == UINT_MAX)
return ret;
- if (adspis & AVS_ADSP_ADSPIS_IPC) {
+ if (adspis != UINT_MAX && (adspis & AVS_ADSP_ADSPIS_IPC)) {
avs_cnl_ipc_interrupt(adev);
ret = IRQ_HANDLED;
}
+ if (adev->sdw) {
+ u32 wakests;
+
+ if (adspis2 != UINT_MAX && (adspis2 & AVS_ADSP_ADSPIS2_SNDW))
+ ret = avs_sdw_thread(irq, adev);
+
+ wakests = snd_hdac_adsp_readl(adev, adev->sdw->shim_base + SDW_SHIM_WAKESTS);
+ if (wakests) {
+ avs_sdw_process_wakeen_event(adev);
+ ret = IRQ_HANDLED;
+ }
+ }
+
return ret;
}
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 9413027e1e32..f9f25f651a9e 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -31,6 +31,7 @@
#include "debug.h"
#include "messages.h"
#include "pcm.h"
+#include "soundwire.h"
static u32 pgctl_mask = AZX_PGCTL_LSRMD_MASK;
module_param(pgctl_mask, uint, 0444);
@@ -230,6 +231,11 @@ static void avs_hda_probe_work(struct work_struct *work)
list_for_each_entry(hlink, &bus->hlink_list, list)
snd_hdac_ext_bus_link_put(bus, hlink);
+ /* Soundwire component is optional */
+ ret = avs_sdw_probe(adev);
+ if (ret && ret != -ENODEV)
+ dev_err(adev->dev, "failed to probe sdw: %d\n", ret);
+
snd_hdac_ext_bus_ppcap_enable(bus, true);
snd_hdac_ext_bus_ppcap_int_enable(bus, true);
avs_debugfs_init(adev);
@@ -240,6 +246,14 @@ static void avs_hda_probe_work(struct work_struct *work)
acpi_nhlt_get_gbl_table();
+ ret = avs_sdw_startup(adev);
+ if (ret) {
+ dev_err(adev->dev, "failed to startup sdw: %d\n", ret);
+ return;
+ }
+
+ avs_sdw_enable_irq(adev, true);
+
avs_register_all_boards(adev);
/* configure PM */
@@ -561,6 +575,8 @@ static void avs_pci_shutdown(struct pci_dev *pci)
snd_hdac_bus_stop_chip(bus);
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
+ avs_sdw_enable_irq(adev, false);
+
pci_free_irq(pci, 0, adev);
pci_free_irq(pci, 0, bus);
pci_free_irq_vectors(pci);
@@ -587,6 +603,9 @@ static void avs_pci_remove(struct pci_dev *pci)
avs_dsp_op(adev, int_control, false);
snd_hdac_ext_bus_ppcap_int_enable(bus, false);
+ avs_sdw_enable_irq(adev, false);
+ avs_sdw_exit(adev);
+
/* it is safe to remove all codecs from the system now */
list_for_each_entry_safe(hdev, save, &bus->codec_list, list)
snd_hda_codec_unregister(hdac_to_hda_codec(hdev));
@@ -661,6 +680,7 @@ static int avs_suspend_common(struct avs_dev *adev, bool low_power)
}
avs_ipc_block(adev->ipc);
+ avs_sdw_enable_irq(adev, false);
avs_dsp_op(adev, int_control, false);
snd_hdac_ext_bus_ppcap_int_enable(bus, false);
@@ -720,6 +740,8 @@ static int avs_resume_common(struct avs_dev *adev, bool low_power, bool purge)
return ret;
}
+ avs_sdw_enable_irq(adev, true);
+
return 0;
}
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index bebdc79ec88e..27d09a3bb5ef 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -18,6 +18,7 @@
#include "messages.h"
#include "registers.h"
#include "topology.h"
+#include "soundwire.h"
#define AVS_ROM_STS_MASK 0xFF
#define AVS_ROM_INIT_DONE 0x1
@@ -345,6 +346,8 @@ static int avs_imr_load_basefw(struct avs_dev *adev)
if (ret < 0)
return ret;
+ avs_sdw_process_wakeen_event(adev);
+
ret = wait_for_completion_timeout(&adev->fw_ready,
msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS));
if (!ret) {
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index 97767882ffa1..9e403cfb04fa 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -25,11 +25,15 @@
#define AVS_ADSP_REG_ADSPCS (AVS_ADSP_GEN_BASE + 0x04)
#define AVS_ADSP_REG_ADSPIC (AVS_ADSP_GEN_BASE + 0x08)
#define AVS_ADSP_REG_ADSPIS (AVS_ADSP_GEN_BASE + 0x0C)
+#define AVS_ADSP_REG_ADSPIC2 (AVS_ADSP_GEN_BASE + 0x10)
+#define AVS_ADSP_REG_ADSPIS2 (AVS_ADSP_GEN_BASE + 0x14)
#define AVS_ADSP_ADSPIC_IPC BIT(0)
#define AVS_ADSP_ADSPIC_CLDMA BIT(1)
#define AVS_ADSP_ADSPIS_IPC BIT(0)
#define AVS_ADSP_ADSPIS_CLDMA BIT(1)
+#define AVS_ADSP_ADSPIC2_SNDW BIT(5)
+#define AVS_ADSP_ADSPIS2_SNDW BIT(5)
#define AVS_ADSPCS_CRST_MASK(cm) (cm)
#define AVS_ADSPCS_CSTALL_MASK(cm) ((cm) << 8)
diff --git a/sound/soc/intel/avs/soundwire.c b/sound/soc/intel/avs/soundwire.c
new file mode 100644
index 000000000000..c2a6db08a3af
--- /dev/null
+++ b/sound/soc/intel/avs/soundwire.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2026 Intel Corporation
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/acpi.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_intel.h>
+#include <sound/hdaudio_ext.h>
+#include "avs.h"
+#include "registers.h"
+#include "soundwire.h"
+
+static struct sdw_intel_hw_ops avs_sdw_cnl_ops;
+
+int avs_sdw_probe(struct avs_dev *adev)
+{
+ struct hdac_bus *hbus = &adev->base.core;
+ struct sdw_intel_acpi_info info;
+ struct sdw_intel_ctx *ctx;
+ struct sdw_intel_res res;
+ int ret;
+
+ ret = sdw_intel_acpi_scan(ACPI_HANDLE(adev->dev), &info);
+ if (ret < 0)
+ return -ENODEV;
+
+ memset(&res, 0, sizeof(res));
+ res.mmio_base = adev->dsp_ba;
+ res.shim_base = SDW_SHIM_BASE;
+ res.alh_base = SDW_ALH_BASE;
+ res.ext = false;
+ res.irq = adev->base.core.irq;
+ res.handle = info.handle;
+ res.parent = adev->dev;
+ res.dev = adev->dev;
+ res.clock_stop_quirks = SDW_INTEL_CLK_STOP_BUS_RESET;
+ res.hbus = hbus;
+
+ memcpy(&avs_sdw_cnl_ops, &sdw_intel_cnl_hw_ops, sizeof(avs_sdw_cnl_ops));
+ avs_sdw_cnl_ops.register_dai = NULL;
+ res.hw_ops = &avs_sdw_cnl_ops;
+
+ /* we could filter links here if needed, e.g.: for quirks */
+ res.count = info.count;
+ res.link_mask = info.link_mask;
+
+ ctx = sdw_intel_probe(&res);
+ if (!ctx) {
+ dev_err(adev->dev, "SoundWire probe failed\n");
+ return -EINVAL;
+ }
+
+ adev->sdw = ctx;
+ return 0;
+}
+
+int avs_sdw_startup(struct avs_dev *adev)
+{
+ if (adev->sdw)
+ return sdw_intel_startup(adev->sdw);
+ return 0;
+}
+
+void avs_sdw_exit(struct avs_dev *adev)
+{
+ if (adev->sdw) {
+ sdw_intel_exit(adev->sdw);
+ adev->sdw = NULL;
+ }
+}
+
+// TODO split tgl vs mtl
+static void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable)
+{
+ u32 val;
+
+ val = readl(mmio_base + AVS_ADSP_REG_ADSPIC2);
+
+ if (enable)
+ val |= AVS_ADSP_ADSPIC2_SNDW;
+ else
+ val &= ~AVS_ADSP_ADSPIC2_SNDW;
+
+ writel(val, mmio_base + AVS_ADSP_REG_ADSPIC2);
+}
+
+void avs_sdw_enable_irq(struct avs_dev *adev, bool enable)
+{
+ if (adev->sdw)
+ sdw_intel_enable_irq(adev->dsp_ba, enable);
+}
+
+void avs_sdw_process_wakeen_event(struct avs_dev *adev)
+{
+ if (adev->sdw)
+ sdw_intel_process_wakeen_event(adev->sdw);
+}
+
+irqreturn_t avs_sdw_thread(int irq, struct avs_dev *adev)
+{
+ if (adev->sdw)
+ return sdw_intel_thread(irq, adev->sdw);
+ return IRQ_HANDLED;
+}
+
+MODULE_IMPORT_NS("SOUNDWIRE_INTEL");
+MODULE_IMPORT_NS("SOUNDWIRE_INTEL_INIT");
+MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI");
diff --git a/sound/soc/intel/avs/soundwire.h b/sound/soc/intel/avs/soundwire.h
new file mode 100644
index 000000000000..96ce29ab21a3
--- /dev/null
+++ b/sound/soc/intel/avs/soundwire.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2021-2026 Intel Corporation
+ *
+ * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+ * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+ */
+
+#ifndef __SOUND_SOC_INTEL_AVS_SOUNDWIRE_H
+#define __SOUND_SOC_INTEL_AVS_SOUNDWIRE_H
+
+#include <linux/irqreturn.h>
+
+struct avs_dev;
+
+#if IS_ENABLED(CONFIG_SOUNDWIRE_INTEL)
+
+int avs_sdw_probe(struct avs_dev *adev);
+int avs_sdw_startup(struct avs_dev *adev);
+void avs_sdw_exit(struct avs_dev *adev);
+void avs_sdw_enable_irq(struct avs_dev *adev, bool enable);
+void avs_sdw_process_wakeen_event(struct avs_dev *adev);
+irqreturn_t avs_sdw_thread(int irq, struct avs_dev *adev);
+
+#else
+
+static inline int avs_sdw_probe(struct avs_dev *adev)
+{
+ return 0;
+}
+
+static inline int avs_sdw_startup(struct avs_dev *adev)
+{
+ return 0;
+}
+
+static inline void avs_sdw_exit(struct avs_dev *adev)
+{
+}
+
+static inline void avs_sdw_enable_irq(struct avs_dev *adev, bool enable)
+{
+}
+
+static inline void avs_sdw_process_wakeen_event(struct avs_dev *adev)
+{
+}
+
+static inline irqreturn_t avs_sdw_thread(int irq, struct avs_dev *adev)
+{
+ return IRQ_HANDLED;
+}
+
+#endif
+
+#endif /* __SOUND_SOC_INTEL_AVS_SOUNDWIRE_H */
--
2.34.1
next prev parent reply other threads:[~2026-11-02 18:03 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 18:10 [PATCH 0/7] ASoC: Intel: avs: Soundwire support Cezary Rojewski
2026-11-02 18:10 ` [PATCH 1/7] soundwire: intel: Define stubs when library is disabled Cezary Rojewski
2026-11-02 18:10 ` [PATCH 2/7] soundwire: intel: Allow for dynamic assignment of PDIs Cezary Rojewski
2026-11-02 18:10 ` [PATCH 3/7] soundwire: intel: Split PDIs and DAIs initialization Cezary Rojewski
2026-11-02 18:10 ` [PATCH 4/7] ASoC: Intel: avs: Pass irq to dsp_interrupt callback Cezary Rojewski
2026-11-02 18:10 ` Cezary Rojewski [this message]
2026-11-02 18:10 ` [PATCH 6/7] ASoC: Intel: avs: Expose common PCM functions Cezary Rojewski
2026-11-02 18:18 ` Amadeusz Sławiński
2026-11-02 18:20 ` Cezary Rojewski
2026-11-02 18:10 ` [PATCH 7/7] ASoC: Intel: avs: SoundWire PCM BE operations Cezary Rojewski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261102181042.1922005-6-cezary.rojewski@intel.com \
--to=cezary.rojewski@intel.com \
--cc=amade@asmblr.net \
--cc=broonie@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=perex@perex.cz \
--cc=pierre-louis.bossart@linux.dev \
--cc=tiwai@suse.com \
--cc=vkoul@kernel.org \
--cc=yung-chuan.liao@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®