summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-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
19 files changed, 449 insertions, 37 deletions
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;
}