summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2024-10-18 23:01:45 +0300
committerMark Brown <broonie@kernel.org>2024-10-18 23:01:45 +0300
commit478fc2f4212e1dc1c247f3bff6856146305850df (patch)
tree7343964f57ddd0b1f011d0b0a26ab46812fc229e
parent42fb51612f8298d24232b1ac2cf7ce303d4cfc7e (diff)
parente92edcf8023d425c7abcf1d7abb5dcac53d106f5 (diff)
downloadlinux-478fc2f4212e1dc1c247f3bff6856146305850df.tar.xz
ASoC/soundwire: add initial support for SDCA
Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>: We need to get rt712 version by reading SDCA version and functions. This patch series adds initial support for SDCA and add a helper to tell if the codec is RT712_VB. This series may go via the ASoC tree with Vinod's Acked-by tag. Bard Liao (1): soundwire: sdw_intel: include linux/acpi.h Pierre-Louis Bossart (10): ASoC/soundwire: remove sdw_slave_extended_id ASoC: SDCA: add initial module soundwire: slave: lookup SDCA version and functions ASoC: SDCA: add quirk function for RT712_VB match ASoC: rt712-sdca: detect the SMART_MIC function during the probe stage ASoC: soc-acpi: introduce new 'machine check' callback ASoC: sdw_utils: add SmartMic DAI for RT712 VB ASoC: sdw_utils: add SmartMic DAI for RT713 VB ASoC: Intel: soc-acpi: add is_device_rt712_vb() helper ASoC: SOF: Intel: hda: use machine_check() for SoundWire drivers/soundwire/Kconfig | 1 + drivers/soundwire/amd_init.c | 12 +- drivers/soundwire/intel_init.c | 13 +- drivers/soundwire/slave.c | 14 ++ include/linux/soundwire/sdw.h | 9 +- include/linux/soundwire/sdw_amd.h | 7 +- include/linux/soundwire/sdw_intel.h | 8 +- include/sound/sdca.h | 62 +++++++ include/sound/sdca_function.h | 55 ++++++ include/sound/soc-acpi.h | 8 +- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/amd/ps/pci-ps.c | 3 +- sound/soc/codecs/rt712-sdca-sdw.c | 1 + sound/soc/codecs/rt712-sdca.c | 38 +++- sound/soc/codecs/rt712-sdca.h | 1 + sound/soc/intel/Kconfig | 5 + sound/soc/intel/common/Makefile | 3 + .../intel/common/soc-acpi-intel-mtl-match.c | 51 ++++++ .../intel/common/soc-acpi-intel-sdca-quirks.c | 42 +++++ .../intel/common/soc-acpi-intel-sdca-quirks.h | 14 ++ sound/soc/sdca/Kconfig | 11 ++ sound/soc/sdca/Makefile | 5 + sound/soc/sdca/sdca_device.c | 67 +++++++ sound/soc/sdca/sdca_functions.c | 173 ++++++++++++++++++ sound/soc/sdw_utils/soc_sdw_utils.c | 18 +- sound/soc/soc-acpi.c | 30 +-- sound/soc/sof/amd/acp-common.c | 3 +- sound/soc/sof/intel/hda.c | 19 +- 29 files changed, 610 insertions(+), 65 deletions(-) create mode 100644 include/sound/sdca.h create mode 100644 include/sound/sdca_function.h create mode 100644 sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c create mode 100644 sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h create mode 100644 sound/soc/sdca/Kconfig create mode 100644 sound/soc/sdca/Makefile create mode 100644 sound/soc/sdca/sdca_device.c create mode 100644 sound/soc/sdca/sdca_functions.c -- 2.43.0
-rw-r--r--drivers/soundwire/Kconfig1
-rw-r--r--drivers/soundwire/amd_init.c12
-rw-r--r--drivers/soundwire/intel_init.c13
-rw-r--r--drivers/soundwire/slave.c14
-rw-r--r--include/linux/soundwire/sdw.h9
-rw-r--r--include/linux/soundwire/sdw_amd.h7
-rw-r--r--include/linux/soundwire/sdw_intel.h8
-rw-r--r--include/sound/sdca.h62
-rw-r--r--include/sound/sdca_function.h55
-rw-r--r--include/sound/soc-acpi.h8
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/amd/ps/pci-ps.c3
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c1
-rw-r--r--sound/soc/codecs/rt712-sdca.c38
-rw-r--r--sound/soc/codecs/rt712-sdca.h1
-rw-r--r--sound/soc/intel/Kconfig5
-rw-r--r--sound/soc/intel/common/Makefile3
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c51
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c42
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h14
-rw-r--r--sound/soc/sdca/Kconfig11
-rw-r--r--sound/soc/sdca/Makefile5
-rw-r--r--sound/soc/sdca/sdca_device.c67
-rw-r--r--sound/soc/sdca/sdca_functions.c173
-rw-r--r--sound/soc/sdw_utils/soc_sdw_utils.c18
-rw-r--r--sound/soc/soc-acpi.c30
-rw-r--r--sound/soc/sof/amd/acp-common.c3
-rw-r--r--sound/soc/sof/intel/hda.c19
29 files changed, 610 insertions, 65 deletions
diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig
index 4d8f3b7024ae..f66f869dff2e 100644
--- a/drivers/soundwire/Kconfig
+++ b/drivers/soundwire/Kconfig
@@ -6,6 +6,7 @@
menuconfig SOUNDWIRE
tristate "SoundWire support"
depends on ACPI || OF
+ depends on SND_SOC_SDCA_OPTIONAL
help
SoundWire is a 2-Pin interface with data and clock line ratified
by the MIPI Alliance. SoundWire is used for transporting data
diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c
index db040f435059..53d1d707ca1a 100644
--- a/drivers/soundwire/amd_init.c
+++ b/drivers/soundwire/amd_init.c
@@ -177,7 +177,7 @@ EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT);
void sdw_amd_exit(struct sdw_amd_ctx *ctx)
{
sdw_amd_cleanup(ctx);
- kfree(ctx->ids);
+ kfree(ctx->peripherals);
kfree(ctx);
}
EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT);
@@ -204,10 +204,11 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
num_slaves++;
}
- ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
- if (!ctx->ids)
+ ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves),
+ GFP_KERNEL);
+ if (!ctx->peripherals)
return -ENOMEM;
- ctx->num_slaves = num_slaves;
+ ctx->peripherals->num_peripherals = num_slaves;
for (index = 0; index < ctx->count; index++) {
if (!(ctx->link_mask & BIT(index)))
continue;
@@ -215,8 +216,7 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
if (amd_manager) {
bus = &amd_manager->bus;
list_for_each_entry(slave, &bus->slaves, node) {
- ctx->ids[i].id = slave->id;
- ctx->ids[i].link_id = bus->link_id;
+ ctx->peripherals->array[i] = slave;
i++;
}
}
diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c
index a09134b97cd6..12e7a98f319f 100644
--- a/drivers/soundwire/intel_init.c
+++ b/drivers/soundwire/intel_init.c
@@ -252,17 +252,16 @@ static struct sdw_intel_ctx
num_slaves++;
}
- ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
- if (!ctx->ids)
+ ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves),
+ GFP_KERNEL);
+ if (!ctx->peripherals)
goto err;
-
- ctx->num_slaves = num_slaves;
+ ctx->peripherals->num_peripherals = num_slaves;
i = 0;
list_for_each_entry(link, &ctx->link_list, list) {
bus = &link->cdns->bus;
list_for_each_entry(slave, &bus->slaves, node) {
- ctx->ids[i].id = slave->id;
- ctx->ids[i].link_id = bus->link_id;
+ ctx->peripherals->array[i] = slave;
i++;
}
}
@@ -371,7 +370,7 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx)
}
sdw_intel_cleanup(ctx);
- kfree(ctx->ids);
+ kfree(ctx->peripherals);
kfree(ctx->ldev);
kfree(ctx);
}
diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
index f1a4df6cfebd..97cf8bcca047 100644
--- a/drivers/soundwire/slave.c
+++ b/drivers/soundwire/slave.c
@@ -5,6 +5,7 @@
#include <linux/of.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
+#include <sound/sdca.h>
#include "bus.h"
#include "sysfs_local.h"
@@ -70,6 +71,17 @@ int sdw_slave_add(struct sdw_bus *bus,
list_add_tail(&slave->node, &bus->slaves);
mutex_unlock(&bus->bus_lock);
+ /*
+ * The Soundwire driver probe may optionally register SDCA
+ * sub-devices, one per Function. This means the information
+ * on the SDCA revision and the number/type of Functions need
+ * to be extracted from platform firmware before the SoundWire
+ * driver probe, and as a consequence before the SoundWire
+ * device_register() below.
+ */
+ sdca_lookup_interface_revision(slave);
+ sdca_lookup_functions(slave);
+
ret = device_register(&slave->dev);
if (ret) {
dev_err(bus->dev, "Failed to add slave: ret %d\n", ret);
@@ -259,3 +271,5 @@ int sdw_of_find_slaves(struct sdw_bus *bus)
return 0;
}
+
+MODULE_IMPORT_NS(SND_SOC_SDCA);
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index 5e0dd47a0412..49d690f3d29a 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -10,6 +10,7 @@
#include <linux/irqdomain.h>
#include <linux/mod_devicetable.h>
#include <linux/bitfield.h>
+#include <sound/sdca.h>
struct sdw_bus;
struct sdw_slave;
@@ -488,9 +489,9 @@ struct sdw_slave_id {
__u8 sdw_version:4;
};
-struct sdw_extended_slave_id {
- int link_id;
- struct sdw_slave_id id;
+struct sdw_peripherals {
+ int num_peripherals;
+ struct sdw_slave *array[];
};
/*
@@ -663,6 +664,7 @@ struct sdw_slave_ops {
* @is_mockup_device: status flag used to squelch errors in the command/control
* protocol for SoundWire mockup devices
* @sdw_dev_lock: mutex used to protect callbacks/remove races
+ * @sdca_data: structure containing all device data for SDCA helpers
*/
struct sdw_slave {
struct sdw_slave_id id;
@@ -686,6 +688,7 @@ struct sdw_slave {
bool first_interrupt_done;
bool is_mockup_device;
struct mutex sdw_dev_lock; /* protect callbacks/remove races */
+ struct sdca_device_data sdca_data;
};
#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h
index 28a4eb77717f..585b4c58a8a6 100644
--- a/include/linux/soundwire/sdw_amd.h
+++ b/include/linux/soundwire/sdw_amd.h
@@ -115,19 +115,16 @@ struct sdw_amd_acpi_info {
* struct sdw_amd_ctx - context allocated by the controller driver probe
*
* @count: link count
- * @num_slaves: total number of devices exposed across all enabled links
* @link_mask: bit-wise mask listing SoundWire links reported by the
* Controller
- * @ids: array of slave_id, representing Slaves exposed across all enabled
- * links
* @pdev: platform device structure
+ * @peripherals: array representing Peripherals exposed across all enabled links
*/
struct sdw_amd_ctx {
int count;
- int num_slaves;
u32 link_mask;
- struct sdw_extended_slave_id *ids;
struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT];
+ struct sdw_peripherals *peripherals;
};
/**
diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h
index 37ae69365fe2..491ddd27270f 100644
--- a/include/linux/soundwire/sdw_intel.h
+++ b/include/linux/soundwire/sdw_intel.h
@@ -4,6 +4,7 @@
#ifndef __SDW_INTEL_H
#define __SDW_INTEL_H
+#include <linux/acpi.h>
#include <linux/irqreturn.h>
#include <linux/soundwire/sdw.h>
@@ -286,31 +287,28 @@ struct hdac_bus;
* hardware capabilities after all power dependencies are settled.
* @link_mask: bit-wise mask listing SoundWire links reported by the
* Controller
- * @num_slaves: total number of devices exposed across all enabled links
* @handle: ACPI parent handle
* @ldev: information for each link (controller-specific and kept
* opaque here)
- * @ids: array of slave_id, representing Slaves exposed across all enabled
- * links
* @link_list: list to handle interrupts across all links
* @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers.
* @shim_mask: flags to track initialization of SHIM shared registers
* @shim_base: sdw shim base.
* @alh_base: sdw alh base.
+ * @peripherals: array representing Peripherals exposed across all enabled links
*/
struct sdw_intel_ctx {
int count;
void __iomem *mmio_base;
u32 link_mask;
- int num_slaves;
acpi_handle handle;
struct sdw_intel_link_dev **ldev;
- struct sdw_extended_slave_id *ids;
struct list_head link_list;
struct mutex shim_lock; /* lock for access to shared SHIM registers */
u32 shim_mask;
u32 shim_base;
u32 alh_base;
+ struct sdw_peripherals *peripherals;
};
/**
diff --git a/include/sound/sdca.h b/include/sound/sdca.h
new file mode 100644
index 000000000000..7e138229e8f3
--- /dev/null
+++ b/include/sound/sdca.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ *
+ * Copyright(c) 2024 Intel Corporation
+ */
+
+#ifndef __SDCA_H__
+#define __SDCA_H__
+
+struct sdw_slave;
+
+#define SDCA_MAX_FUNCTION_COUNT 8
+
+/**
+ * sdca_device_desc - short descriptor for an SDCA Function
+ * @adr: ACPI address (used for SDCA register access)
+ * @type: Function topology type
+ * @name: human-readable string
+ */
+struct sdca_function_desc {
+ u64 adr;
+ u32 type;
+ const char *name;
+};
+
+/**
+ * sdca_device_data - structure containing all SDCA related information
+ * @sdca_interface_revision: value read from _DSD property, mainly to check
+ * for changes between silicon versions
+ * @num_functions: total number of supported SDCA functions. Invalid/unsupported
+ * functions will be skipped.
+ * @sdca_func: array of function descriptors
+ */
+struct sdca_device_data {
+ u32 interface_revision;
+ int num_functions;
+ struct sdca_function_desc sdca_func[SDCA_MAX_FUNCTION_COUNT];
+};
+
+enum sdca_quirk {
+ SDCA_QUIRKS_RT712_VB,
+};
+
+#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA)
+
+void sdca_lookup_functions(struct sdw_slave *slave);
+void sdca_lookup_interface_revision(struct sdw_slave *slave);
+bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk);
+
+#else
+
+static inline void sdca_lookup_functions(struct sdw_slave *slave) {}
+static inline void sdca_lookup_interface_revision(struct sdw_slave *slave) {}
+static inline bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
+{
+ return false;
+}
+#endif
+
+#endif
diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h
new file mode 100644
index 000000000000..a01eec86b9a6
--- /dev/null
+++ b/include/sound/sdca_function.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ *
+ * Copyright(c) 2024 Intel Corporation
+ */
+
+#ifndef __SDCA_FUNCTION_H__
+#define __SDCA_FUNCTION_H__
+
+/*
+ * SDCA Function Types from SDCA specification v1.0a Section 5.1.2
+ * all Function types not described are reserved
+ * Note that SIMPLE_AMP, SIMPLE_MIC and SIMPLE_JACK Function Types
+ * are NOT defined in SDCA 1.0a, but they were defined in earlier
+ * drafts and are planned for 1.1.
+ */
+
+enum sdca_function_type {
+ SDCA_FUNCTION_TYPE_SMART_AMP = 0x01, /* Amplifier with protection features */
+ SDCA_FUNCTION_TYPE_SIMPLE_AMP = 0x02, /* subset of SmartAmp */
+ SDCA_FUNCTION_TYPE_SMART_MIC = 0x03, /* Smart microphone with acoustic triggers */
+ SDCA_FUNCTION_TYPE_SIMPLE_MIC = 0x04, /* subset of SmartMic */
+ SDCA_FUNCTION_TYPE_SPEAKER_MIC = 0x05, /* Combination of SmartMic and SmartAmp */
+ SDCA_FUNCTION_TYPE_UAJ = 0x06, /* 3.5mm Universal Audio jack */
+ SDCA_FUNCTION_TYPE_RJ = 0x07, /* Retaskable jack */
+ SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08, /* Subset of UAJ */
+ SDCA_FUNCTION_TYPE_HID = 0x0A, /* Human Interface Device, for e.g. buttons */
+ SDCA_FUNCTION_TYPE_IMP_DEF = 0x1F, /* Implementation-defined function */
+};
+
+/* Human-readable names used for kernel logs and Function device registration/bind */
+#define SDCA_FUNCTION_TYPE_SMART_AMP_NAME "SmartAmp"
+#define SDCA_FUNCTION_TYPE_SIMPLE_AMP_NAME "SimpleAmp"
+#define SDCA_FUNCTION_TYPE_SMART_MIC_NAME "SmartMic"
+#define SDCA_FUNCTION_TYPE_SIMPLE_MIC_NAME "SimpleMic"
+#define SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME "SpeakerMic"
+#define SDCA_FUNCTION_TYPE_UAJ_NAME "UAJ"
+#define SDCA_FUNCTION_TYPE_RJ_NAME "RJ"
+#define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack"
+#define SDCA_FUNCTION_TYPE_HID_NAME "HID"
+
+enum sdca_entity0_controls {
+ SDCA_CONTROL_ENTITY_0_COMMIT_GROUP_MASK = 0x01,
+ SDCA_CONTROL_ENTITY_0_INTSTAT_CLEAR = 0x02,
+ SDCA_CONTROL_ENTITY_0_INT_ENABLE = 0x03,
+ SDCA_CONTROL_ENTITY_0_FUNCTION_SDCA_VERSION = 0x04,
+ SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY = 0x05,
+ SDCA_CONTROL_ENTITY_0_FUNCTION_MANUFACTURER_ID = 0x06,
+ SDCA_CONTROL_ENTITY_0_FUNCTION_ID = 0x07,
+ SDCA_CONTROL_ENTITY_0_FUNCTION_VERSION = 0x08
+};
+
+#endif
diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h
index 60d3b86a4660..72e371a21767 100644
--- a/include/sound/soc-acpi.h
+++ b/include/sound/soc-acpi.h
@@ -185,6 +185,10 @@ struct snd_soc_acpi_link_adr {
* ACPI ID alone is not sufficient, wrong or misleading
* @quirk_data: data used to uniquely identify a machine, usually a list of
* audio codecs whose presence if checked with ACPI
+ * @machine_check: pointer to quirk function. The functionality is similar to
+ * the use of @machine_quirk, except that the return value is a boolean: the intent
+ * is to skip a machine if the additional hardware/firmware verification invalidates
+ * the initial selection in the snd_soc_acpi_mach table.
* @pdata: intended for platform data or machine specific-ops. This structure
* is not constant since this field may be updated at run-time
* @sof_tplg_filename: Sound Open Firmware topology file name, if enabled
@@ -203,6 +207,7 @@ struct snd_soc_acpi_mach {
const char *board;
struct snd_soc_acpi_mach * (*machine_quirk)(void *arg);
const void *quirk_data;
+ bool (*machine_check)(void *arg);
void *pdata;
struct snd_soc_acpi_mach_params mach_params;
const char *sof_tplg_filename;
@@ -233,7 +238,6 @@ static inline bool snd_soc_acpi_sof_parent(struct device *dev)
bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
const struct snd_soc_acpi_link_adr *link,
- struct sdw_extended_slave_id *ids,
- int num_slaves);
+ struct sdw_peripherals *peripherals);
#endif
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index e87bd15a8b43..8e01b421fe8d 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -108,6 +108,7 @@ source "sound/soc/pxa/Kconfig"
source "sound/soc/qcom/Kconfig"
source "sound/soc/rockchip/Kconfig"
source "sound/soc/samsung/Kconfig"
+source "sound/soc/sdca/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/sof/Kconfig"
source "sound/soc/spear/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 775bb38c2ed4..5307b0b62a93 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += qcom/
obj-$(CONFIG_SND_SOC) += rockchip/
obj-$(CONFIG_SND_SOC) += samsung/
+obj-$(CONFIG_SND_SOC) += sdca/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += sof/
obj-$(CONFIG_SND_SOC) += spear/
diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c
index c72d666d51bd..4365499c8f82 100644
--- a/sound/soc/amd/ps/pci-ps.c
+++ b/sound/soc/amd/ps/pci-ps.c
@@ -302,8 +302,7 @@ static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev)
link = mach->links;
for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) {
if (!snd_soc_acpi_sdw_link_slaves_found(dev, link,
- acp_data->sdw->ids,
- acp_data->sdw->num_slaves))
+ acp_data->sdw->peripherals))
break;
}
if (i == acp_data->info.count || !link->num_adr)
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 90d5aaddbd5b..549aa31faed4 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -507,3 +507,4 @@ module_sdw_driver(rt712_sdca_sdw_driver);
MODULE_DESCRIPTION("ASoC RT712 SDCA SDW driver");
MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(SND_SOC_SDCA);
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index e210c574bb74..78dbf9eed494 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdca.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/slab.h>
#include <sound/soc-dapm.h>
@@ -1652,6 +1653,17 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
if (ret < 0)
return ret;
+ /* only add the dmic component if a SMART_MIC function is exposed in ACPI */
+ if (sdca_device_quirk_match(slave, SDCA_QUIRKS_RT712_VB)) {
+ ret = devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt712_dmic,
+ rt712_sdca_dmic_dai,
+ ARRAY_SIZE(rt712_sdca_dmic_dai));
+ if (ret < 0)
+ return ret;
+ rt712->dmic_function_found = true;
+ }
+
/* set autosuspend parameters */
pm_runtime_set_autosuspend_delay(dev, 3000);
pm_runtime_use_autosuspend(dev);
@@ -1799,7 +1811,6 @@ static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712)
int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
- int ret = 0;
unsigned int val;
struct sdw_slave_prop *prop = &slave->prop;
@@ -1829,15 +1840,22 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
rt712->version_id = (val & 0x0f00) >> 8;
dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id);
- if (rt712->version_id == RT712_VA)
+ if (rt712->version_id == RT712_VA) {
+ if (rt712->dmic_function_found) {
+ dev_err(&slave->dev, "%s RT712 VA detected but SMART_MIC function exposed in ACPI\n",
+ __func__);
+ goto suspend;
+ }
+
rt712_sdca_va_io_init(rt712);
- else {
- /* multilanes and DMIC are supported by rt712vb */
- ret = devm_snd_soc_register_component(dev,
- &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai));
- if (ret < 0)
- return ret;
+ } else {
+ if (!rt712->dmic_function_found) {
+ dev_err(&slave->dev, "%s RT712 VB detected but no SMART_MIC function exposed in ACPI\n",
+ __func__);
+ goto suspend;
+ }
+ /* multilanes and DMIC are supported by rt712vb */
prop->lane_control_support = true;
rt712_sdca_vb_io_init(rt712);
}
@@ -1862,10 +1880,12 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
/* Mark Slave initialization complete */
rt712->hw_init = true;
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+
+suspend:
pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put_autosuspend(&slave->dev);
- dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
return 0;
}
diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h
index 2169f2f726b9..a08491496d90 100644
--- a/sound/soc/codecs/rt712-sdca.h
+++ b/sound/soc/codecs/rt712-sdca.h
@@ -36,6 +36,7 @@ struct rt712_sdca_priv {
unsigned int scp_sdca_stat2;
unsigned int hw_id;
unsigned int version_id;
+ bool dmic_function_found;
bool fu0f_dapm_mute;
bool fu0f_mixer_l_mute;
bool fu0f_mixer_r_mute;
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 5bb7047c170f..14461dee3e52 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -71,9 +71,14 @@ if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
config SND_SOC_ACPI_INTEL_MATCH
tristate
select SND_SOC_ACPI if ACPI
+ select SND_SOC_ACPI_INTEL_SDCA_QUIRKS
# this option controls the compilation of ACPI matching tables and
# helpers and is not meant to be selected by the user.
+config SND_SOC_ACPI_INTEL_SDCA_QUIRKS
+ tristate
+ imply SND_SOC_SDCA
+
endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
config SND_SOC_INTEL_KEEMBAY
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index da551144ec0f..0afd114be9e5 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -16,4 +16,7 @@ snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-matc
snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o
+snd-soc-acpi-intel-sdca-quirks-y += soc-acpi-intel-sdca-quirks.o
+
obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o
+obj-$(CONFIG_SND_SOC_ACPI_INTEL_SDCA_QUIRKS) += snd-soc-acpi-intel-sdca-quirks.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index fd02c864e25e..0b37465b6c53 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -6,9 +6,12 @@
*
*/
+#include <linux/soundwire/sdw_intel.h>
+#include <sound/sdca.h>
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
#include <sound/soc-acpi-intel-ssp-common.h>
+#include "soc-acpi-intel-sdca-quirks.h"
#include "soc-acpi-intel-sdw-mockup-match.h"
static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = {
@@ -133,6 +136,27 @@ static const struct snd_soc_acpi_endpoint rt712_endpoints[] = {
},
};
+static const struct snd_soc_acpi_endpoint rt712_vb_endpoints[] = {
+ {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ {
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ {
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
/*
* RT722 is a multi-function codec, three endpoints are created for
* its headset, amp and dmic functions.
@@ -190,6 +214,15 @@ static const struct snd_soc_acpi_adr_device rt712_0_single_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt712_vb_0_single_adr[] = {
+ {
+ .adr = 0x000030025D071201ull,
+ .num_endpoints = ARRAY_SIZE(rt712_vb_endpoints),
+ .endpoints = rt712_vb_endpoints,
+ .name_prefix = "rt712"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = {
{
.adr = 0x000330025D171201ull,
@@ -363,6 +396,15 @@ static const struct snd_soc_acpi_link_adr mtl_712_l0[] = {
{}
};
+static const struct snd_soc_acpi_link_adr mtl_712_vb_l0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt712_vb_0_single_adr),
+ .adr_d = rt712_vb_0_single_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
{ /* Jack Playback Endpoint */
.num = 0,
@@ -776,6 +818,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
},
{
.link_mask = BIT(0),
+ .links = mtl_712_vb_l0,
+ .drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .sof_tplg_filename = "sof-mtl-rt712-vb-l0.tplg",
+ },
+ {
+ .link_mask = BIT(0),
.links = mtl_712_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt712-l0.tplg",
@@ -843,3 +892,5 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
+
+MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_SDCA_QUIRKS);
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
new file mode 100644
index 000000000000..0b7076606d66
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-acpi-intel-sdca-quirks.c - tables and support for SDCA quirks
+ *
+ * Copyright (c) 2024, Intel Corporation.
+ *
+ */
+
+#include <linux/soundwire/sdw_intel.h>
+#include <sound/sdca.h>
+#include <sound/soc-acpi.h>
+#include "soc-acpi-intel-sdca-quirks.h"
+
+/*
+ * Pretend machine quirk. The argument type is not the traditional
+ * 'struct snd_soc_acpi_mach' pointer but instead the sdw_intel_ctx
+ * which contains the peripheral information required for the
+ * SoundWire/SDCA filter on the SMART_MIC setup and interface
+ * revision. When the return value is false, the entry in the
+ * 'snd_soc_acpi_mach' table needs to be skipped.
+ */
+bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg)
+{
+ struct sdw_intel_ctx *ctx = arg;
+ int i;
+
+ if (!ctx)
+ return false;
+
+ for (i = 0; i < ctx->peripherals->num_peripherals; i++) {
+ if (sdca_device_quirk_match(ctx->peripherals->array[i],
+ SDCA_QUIRKS_RT712_VB))
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_sdca_is_device_rt712_vb, SND_SOC_ACPI_INTEL_SDCA_QUIRKS);
+
+MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(SND_SOC_SDCA);
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
new file mode 100644
index 000000000000..bead5ec6243f
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * soc-acpi-intel-sdca-quirks.h - tables and support for SDCA quirks
+ *
+ * Copyright (c) 2024, Intel Corporation.
+ *
+ */
+
+#ifndef _SND_SOC_ACPI_INTEL_SDCA_QUIRKS
+#define _SND_SOC_ACPI_INTEL_SDCA_QUIRKS
+
+bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg);
+
+#endif
diff --git a/sound/soc/sdca/Kconfig b/sound/soc/sdca/Kconfig
new file mode 100644
index 000000000000..07f6822fa614
--- /dev/null
+++ b/sound/soc/sdca/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config SND_SOC_SDCA
+ tristate "ASoC SDCA library"
+ depends on ACPI
+ help
+ This option enables support for the MIPI SoundWire Device
+ Class for Audio (SDCA).
+
+config SND_SOC_SDCA_OPTIONAL
+ def_tristate SND_SOC_SDCA || !SND_SOC_SDCA
diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile
new file mode 100644
index 000000000000..c296bd5a0a7c
--- /dev/null
+++ b/sound/soc/sdca/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+snd-soc-sdca-objs := sdca_functions.o sdca_device.o
+
+obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o
diff --git a/sound/soc/sdca/sdca_device.c b/sound/soc/sdca/sdca_device.c
new file mode 100644
index 000000000000..c44dc21cb634
--- /dev/null
+++ b/sound/soc/sdca/sdca_device.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// Copyright(c) 2024 Intel Corporation
+
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ */
+
+#include <linux/acpi.h>
+#include <linux/soundwire/sdw.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+
+void sdca_lookup_interface_revision(struct sdw_slave *slave)
+{
+ struct fwnode_handle *fwnode = slave->dev.fwnode;
+
+ /*
+ * if this property is not present, then the sdca_interface_revision will
+ * remain zero, which will be considered as 'not defined' or 'invalid'.
+ */
+ fwnode_property_read_u32(fwnode, "mipi-sdw-sdca-interface-revision",
+ &slave->sdca_data.interface_revision);
+}
+EXPORT_SYMBOL_NS(sdca_lookup_interface_revision, SND_SOC_SDCA);
+
+static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave)
+{
+ struct sdw_slave_id *id = &slave->id;
+ int i;
+
+ /*
+ * The RT712_VA relies on the v06r04 draft, and the
+ * RT712_VB on a more recent v08r01 draft.
+ */
+ if (slave->sdca_data.interface_revision < 0x0801)
+ return false;
+
+ if (id->mfg_id != 0x025d)
+ return false;
+
+ if (id->part_id != 0x712 &&
+ id->part_id != 0x713 &&
+ id->part_id != 0x716 &&
+ id->part_id != 0x717)
+ return false;
+
+ for (i = 0; i < slave->sdca_data.num_functions; i++) {
+ if (slave->sdca_data.sdca_func[i].type ==
+ SDCA_FUNCTION_TYPE_SMART_MIC)
+ return true;
+ }
+
+ return false;
+}
+
+bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
+{
+ switch (quirk) {
+ case SDCA_QUIRKS_RT712_VB:
+ return sdca_device_quirk_rt712_vb(slave);
+ default:
+ break;
+ }
+ return false;
+}
+EXPORT_SYMBOL_NS(sdca_device_quirk_match, SND_SOC_SDCA);
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
new file mode 100644
index 000000000000..a6ad57430dd4
--- /dev/null
+++ b/sound/soc/sdca/sdca_functions.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// Copyright(c) 2024 Intel Corporation
+
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ */
+
+#include <linux/acpi.h>
+#include <linux/soundwire/sdw.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+
+static int patch_sdca_function_type(struct device *dev,
+ u32 interface_revision,
+ u32 *function_type,
+ const char **function_name)
+{
+ unsigned long function_type_patch = 0;
+
+ /*
+ * Unfortunately early SDCA specifications used different indices for Functions,
+ * for backwards compatibility we have to reorder the values found
+ */
+ if (interface_revision >= 0x0801)
+ goto skip_early_draft_order;
+
+ switch (*function_type) {
+ case 1:
+ function_type_patch = SDCA_FUNCTION_TYPE_SMART_AMP;
+ break;
+ case 2:
+ function_type_patch = SDCA_FUNCTION_TYPE_SMART_MIC;
+ break;
+ case 3:
+ function_type_patch = SDCA_FUNCTION_TYPE_SPEAKER_MIC;
+ break;
+ case 4:
+ function_type_patch = SDCA_FUNCTION_TYPE_UAJ;
+ break;
+ case 5:
+ function_type_patch = SDCA_FUNCTION_TYPE_RJ;
+ break;
+ case 6:
+ function_type_patch = SDCA_FUNCTION_TYPE_HID;
+ break;
+ default:
+ dev_warn(dev, "%s: SDCA version %#x unsupported function type %d, skipped\n",
+ __func__, interface_revision, *function_type);
+ return -EINVAL;
+ }
+
+skip_early_draft_order:
+ if (function_type_patch)
+ *function_type = function_type_patch;
+
+ /* now double-check the values */
+ switch (*function_type) {
+ case SDCA_FUNCTION_TYPE_SMART_AMP:
+ *function_name = SDCA_FUNCTION_TYPE_SMART_AMP_NAME;
+ break;
+ case SDCA_FUNCTION_TYPE_SMART_MIC:
+ *function_name = SDCA_FUNCTION_TYPE_SMART_MIC_NAME;
+ break;
+ case SDCA_FUNCTION_TYPE_UAJ:
+ *function_name = SDCA_FUNCTION_TYPE_UAJ_NAME;
+ break;
+ case SDCA_FUNCTION_TYPE_HID:
+ *function_name = SDCA_FUNCTION_TYPE_HID_NAME;
+ break;
+ case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
+ case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
+ case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
+ case SDCA_FUNCTION_TYPE_RJ:
+ case SDCA_FUNCTION_TYPE_IMP_DEF:
+ dev_warn(dev, "%s: found unsupported SDCA function type %d, skipped\n",
+ __func__, *function_type);
+ return -EINVAL;
+ default:
+ dev_err(dev, "%s: found invalid SDCA function type %d, skipped\n",
+ __func__, *function_type);
+ return -EINVAL;
+ }
+
+ dev_info(dev, "%s: found SDCA function %s (type %d)\n",
+ __func__, *function_name, *function_type);
+
+ return 0;
+}
+
+static int find_sdca_function(struct acpi_device *adev, void *data)
+{
+ struct fwnode_handle *function_node = acpi_fwnode_handle(adev);
+ struct sdca_device_data *sdca_data = data;
+ struct device *dev = &adev->dev;
+ struct fwnode_handle *control5; /* used to identify function type */
+ const char *function_name;
+ u32 function_type;
+ int func_index;
+ u64 addr;
+ int ret;
+
+ if (sdca_data->num_functions >= SDCA_MAX_FUNCTION_COUNT) {
+ dev_err(dev, "%s: maximum number of functions exceeded\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * The number of functions cannot exceed 8, we could use
+ * acpi_get_local_address() but the value is stored as u64 so
+ * we might as well avoid casts and intermediate levels
+ */
+ ret = acpi_get_local_u64_address(adev->handle, &addr);
+ if (ret < 0)
+ return ret;
+
+ if (!addr) {
+ dev_err(dev, "%s: no addr\n", __func__);
+ return -ENODEV;
+ }
+
+ /*
+ * Extracting the topology type for an SDCA function is a
+ * convoluted process.
+ * The Function type is only visible as a result of a read
+ * from a control. In theory this would mean reading from the hardware,
+ * but the SDCA/DisCo specs defined the notion of "DC value" - a constant
+ * represented with a DSD subproperty.
+ * Drivers have to query the properties for the control
+ * SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY (0x05)
+ */
+ control5 = fwnode_get_named_child_node(function_node,
+ "mipi-sdca-control-0x5-subproperties");
+ if (!control5)
+ return -ENODEV;
+
+ ret = fwnode_property_read_u32(control5, "mipi-sdca-control-dc-value",
+ &function_type);
+
+ fwnode_handle_put(control5);
+
+ if (ret < 0) {
+ dev_err(dev, "%s: the function type can only be determined from ACPI information\n",
+ __func__);
+ return ret;
+ }
+
+ ret = patch_sdca_function_type(dev, sdca_data->interface_revision,
+ &function_type, &function_name);
+ if (ret < 0)
+ return ret;
+
+ /* store results */
+ func_index = sdca_data->num_functions;
+ sdca_data->sdca_func[func_index].adr = addr;
+ sdca_data->sdca_func[func_index].type = function_type;
+ sdca_data->sdca_func[func_index].name = function_name;
+ sdca_data->num_functions++;
+
+ return 0;
+}
+
+void sdca_lookup_functions(struct sdw_slave *slave)
+{
+ struct device *dev = &slave->dev;
+ struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
+
+ acpi_dev_for_each_child(adev, find_sdca_function, &slave->sdca_data);
+}
+EXPORT_SYMBOL_NS(sdca_lookup_functions, SND_SOC_SDCA);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SDCA library");
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index 6f6bff0f69fc..8196177ff5e7 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -144,8 +144,15 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.widgets = generic_spk_widgets,
.num_widgets = ARRAY_SIZE(generic_spk_widgets),
},
+ {
+ .direction = {false, true},
+ .dai_name = "rt712-sdca-aif3",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
},
- .dai_num = 2,
+ .dai_num = 3,
},
{
.part_id = 0x1712,
@@ -178,8 +185,15 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.widgets = generic_jack_widgets,
.num_widgets = ARRAY_SIZE(generic_jack_widgets),
},
+ {
+ .direction = {false, true},
+ .dai_name = "rt712-sdca-aif3",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ .rtd_init = asoc_sdw_rt_dmic_rtd_init,
+ },
},
- .dai_num = 1,
+ .dai_num = 2,
},
{
.part_id = 0x1713,
diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c
index 6d693b2ad5a3..270f9777942f 100644
--- a/sound/soc/soc-acpi.c
+++ b/sound/soc/soc-acpi.c
@@ -131,8 +131,7 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list);
/* Check if all Slaves defined on the link can be found */
bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
const struct snd_soc_acpi_link_adr *link,
- struct sdw_extended_slave_id *ids,
- int num_slaves)
+ struct sdw_peripherals *peripherals)
{
unsigned int part_id, link_id, unique_id, mfg_id, version;
int i, j, k;
@@ -146,22 +145,25 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
link_id = SDW_DISCO_LINK_ID(adr);
version = SDW_VERSION(adr);
- for (j = 0; j < num_slaves; j++) {
+ for (j = 0; j < peripherals->num_peripherals; j++) {
+ struct sdw_slave *peripheral = peripherals->array[j];
+
/* find out how many identical parts were reported on that link */
- if (ids[j].link_id == link_id &&
- ids[j].id.part_id == part_id &&
- ids[j].id.mfg_id == mfg_id &&
- ids[j].id.sdw_version == version)
+ if (peripheral->bus->link_id == link_id &&
+ peripheral->id.part_id == part_id &&
+ peripheral->id.mfg_id == mfg_id &&
+ peripheral->id.sdw_version == version)
reported_part_count++;
}
- for (j = 0; j < num_slaves; j++) {
+ for (j = 0; j < peripherals->num_peripherals; j++) {
+ struct sdw_slave *peripheral = peripherals->array[j];
int expected_part_count = 0;
- if (ids[j].link_id != link_id ||
- ids[j].id.part_id != part_id ||
- ids[j].id.mfg_id != mfg_id ||
- ids[j].id.sdw_version != version)
+ if (peripheral->bus->link_id != link_id ||
+ peripheral->id.part_id != part_id ||
+ peripheral->id.mfg_id != mfg_id ||
+ peripheral->id.sdw_version != version)
continue;
/* find out how many identical parts are expected */
@@ -180,7 +182,7 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
*/
unique_id = SDW_UNIQUE_ID(adr);
if (reported_part_count == 1 ||
- ids[j].id.unique_id == unique_id) {
+ peripheral->id.unique_id == unique_id) {
dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id);
break;
}
@@ -189,7 +191,7 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
part_id, reported_part_count, expected_part_count, link_id);
}
}
- if (j == num_slaves) {
+ if (j == peripherals->num_peripherals) {
dev_dbg(dev, "Slave part_id %#x not found\n", part_id);
return false;
}
diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c
index dbcaac84cb73..fc792956bb97 100644
--- a/sound/soc/sof/amd/acp-common.c
+++ b/sound/soc/sof/amd/acp-common.c
@@ -145,8 +145,7 @@ static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev *
link = mach->links;
for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) {
if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
- acp_data->sdw->ids,
- acp_data->sdw->num_slaves))
+ acp_data->sdw->peripherals))
break;
}
if (i == acp_data->info.count || !link->num_adr)
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index e4cb4ffc7270..38921c0db84e 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1064,7 +1064,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct snd_soc_acpi_link_adr *link;
- struct sdw_extended_slave_id *ids;
+ struct sdw_peripherals *peripherals;
struct snd_soc_acpi_mach *mach;
struct sof_intel_hda_dev *hdev;
u32 link_mask;
@@ -1083,7 +1083,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
return NULL;
}
- if (!hdev->sdw->num_slaves) {
+ if (!hdev->sdw->peripherals || !hdev->sdw->peripherals->num_peripherals) {
dev_warn(sdev->dev, "No SoundWire peripheral detected in ACPI tables\n");
return NULL;
}
@@ -1119,13 +1119,13 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
* are not found on this link.
*/
if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
- hdev->sdw->ids,
- hdev->sdw->num_slaves))
+ hdev->sdw->peripherals))
break;
}
/* Found if all Slaves are checked */
if (i == hdev->info.count || !link->num_adr)
- break;
+ if (!mach->machine_check || mach->machine_check(hdev->sdw))
+ break;
}
if (mach && mach->link_mask) {
mach->mach_params.links = mach->links;
@@ -1136,10 +1136,13 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
}
dev_info(sdev->dev, "No SoundWire machine driver found for the ACPI-reported configuration:\n");
- ids = hdev->sdw->ids;
- for (i = 0; i < hdev->sdw->num_slaves; i++)
+ peripherals = hdev->sdw->peripherals;
+ for (i = 0; i < peripherals->num_peripherals; i++)
dev_info(sdev->dev, "link %d mfg_id 0x%04x part_id 0x%04x version %#x\n",
- ids[i].link_id, ids[i].id.mfg_id, ids[i].id.part_id, ids[i].id.sdw_version);
+ peripherals->array[i]->bus->link_id,
+ peripherals->array[i]->id.mfg_id,
+ peripherals->array[i]->id.part_id,
+ peripherals->array[i]->id.sdw_version);
return NULL;
}