summaryrefslogtreecommitdiffstats
path: root/sound/soc/intel/avs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel/avs')
-rw-r--r--sound/soc/intel/avs/avs.h1
-rw-r--r--sound/soc/intel/avs/board_selection.c17
-rw-r--r--sound/soc/intel/avs/boards/Kconfig10
-rw-r--r--sound/soc/intel/avs/boards/Makefile2
-rw-r--r--sound/soc/intel/avs/boards/da7219.c5
-rw-r--r--sound/soc/intel/avs/boards/es8336.c3
-rw-r--r--sound/soc/intel/avs/boards/max98357a.c2
-rw-r--r--sound/soc/intel/avs/boards/max98373.c2
-rw-r--r--sound/soc/intel/avs/boards/max98927.c4
-rw-r--r--sound/soc/intel/avs/boards/nau8825.c5
-rw-r--r--sound/soc/intel/avs/boards/pcm3168a.c143
-rw-r--r--sound/soc/intel/avs/boards/rt274.c5
-rw-r--r--sound/soc/intel/avs/boards/rt286.c5
-rw-r--r--sound/soc/intel/avs/boards/rt298.c7
-rw-r--r--sound/soc/intel/avs/boards/rt5514.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5663.c3
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c3
-rw-r--r--sound/soc/intel/avs/boards/ssm4567.c4
-rw-r--r--sound/soc/intel/avs/control.c182
-rw-r--r--sound/soc/intel/avs/control.h12
-rw-r--r--sound/soc/intel/avs/core.c24
-rw-r--r--sound/soc/intel/avs/dsp.c3
-rw-r--r--sound/soc/intel/avs/loader.c64
-rw-r--r--sound/soc/intel/avs/messages.c149
-rw-r--r--sound/soc/intel/avs/messages.h46
-rw-r--r--sound/soc/intel/avs/path.c437
-rw-r--r--sound/soc/intel/avs/path.h10
-rw-r--r--sound/soc/intel/avs/pcm.c54
-rw-r--r--sound/soc/intel/avs/tgl.c33
-rw-r--r--sound/soc/intel/avs/topology.c89
-rw-r--r--sound/soc/intel/avs/topology.h16
31 files changed, 1102 insertions, 240 deletions
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index eca6ec0428bb..585543f872fc 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -51,6 +51,7 @@ struct avs_dsp_ops {
int (* const load_basefw)(struct avs_dev *, struct firmware *);
int (* const load_lib)(struct avs_dev *, struct firmware *, u32);
int (* const transfer_mods)(struct avs_dev *, bool, struct avs_module_entry *, u32);
+ int (* const config_basefw)(struct avs_dev *);
int (* const enable_logs)(struct avs_dev *, enum avs_log_enable, u32, u32, unsigned long,
u32 *);
int (* const log_buffer_offset)(struct avs_dev *, u32);
diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 0266edeafc19..2d706edcbf92 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -312,6 +312,18 @@ static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = {
{},
};
+static struct snd_soc_acpi_mach avs_mbl_i2s_machines[] = {
+ {
+ .id = "PCM3168A",
+ .drv_name = "avs_pcm3168a",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0) | AVS_SSP(2),
+ },
+ .tplg_filename = "pcm3168a-tplg.bin",
+ },
+ {}
+};
+
static struct snd_soc_acpi_mach avs_test_i2s_machines[] = {
{
.drv_name = "avs_i2s_test",
@@ -378,10 +390,11 @@ static const struct avs_acpi_boards i2s_boards[] = {
AVS_MACH_ENTRY(HDA_ICL_LP, avs_icl_i2s_machines),
AVS_MACH_ENTRY(HDA_TGL_LP, avs_tgl_i2s_machines),
AVS_MACH_ENTRY(HDA_EHL_0, avs_tgl_i2s_machines),
+ AVS_MACH_ENTRY(HDA_ADL_N, avs_mbl_i2s_machines),
AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines),
AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines),
- AVS_MACH_ENTRY(HDA_RPL_M, avs_tgl_i2s_machines),
- {},
+ AVS_MACH_ENTRY(HDA_RPL_M, avs_mbl_i2s_machines),
+ {}
};
static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 00b0f6c176d6..ba4bee42124c 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -87,6 +87,16 @@ config SND_SOC_INTEL_AVS_MACH_NAU8825
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+config SND_SOC_INTEL_AVS_MACH_PCM3168A
+ tristate "pcm3168a I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_PCM3168A_I2C
+ help
+ This adds support for AVS with PCM3168A I2C codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
config SND_SOC_INTEL_AVS_MACH_PROBE
tristate "Probing (data) board"
depends on DEBUG_FS
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index 4fbd936ffb3e..a95256b94dc8 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -9,6 +9,7 @@ snd-soc-avs-max98927-y := max98927.o
snd-soc-avs-max98357a-y := max98357a.o
snd-soc-avs-max98373-y := max98373.o
snd-soc-avs-nau8825-y := nau8825.o
+snd-soc-avs-pcm3168a-y := pcm3168a.o
snd-soc-avs-probe-y := probe.o
snd-soc-avs-rt274-y := rt274.o
snd-soc-avs-rt286-y := rt286.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PCM3168A) += snd-soc-avs-pcm3168a.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
index 76078a7005b0..7217ae51e89c 100644
--- a/sound/soc/intel/avs/boards/da7219.c
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -113,7 +113,8 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
}
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -197,7 +198,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->be_hw_params_fixup = avs_da7219_be_fixup;
dl->init = avs_da7219_codec_init;
dl->exit = avs_da7219_codec_exit;
diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c
index 426ce37105ae..6f3c4f6c9302 100644
--- a/sound/soc/intel/avs/boards/es8336.c
+++ b/sound/soc/intel/avs/boards/es8336.c
@@ -109,7 +109,8 @@ static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime)
data = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
index 6570209c1a63..c55c1d60b777 100644
--- a/sound/soc/intel/avs/boards/max98357a.c
+++ b/sound/soc/intel/avs/boards/max98357a.c
@@ -78,7 +78,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->be_hw_params_fixup = avs_max98357a_be_fixup;
dl->nonatomic = 1;
dl->no_pcm = 1;
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
index 6f25e66344b7..970f82bf4ce8 100644
--- a/sound/soc/intel/avs/boards/max98373.c
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -111,7 +111,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->name = devm_kasprintf(dev, GFP_KERNEL,
AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
- dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c
index ad18c4e9a670..e4ce553bf1d6 100644
--- a/sound/soc/intel/avs/boards/max98927.c
+++ b/sound/soc/intel/avs/boards/max98927.c
@@ -108,7 +108,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->name = devm_kasprintf(dev, GFP_KERNEL,
AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
- dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
@@ -127,7 +127,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->be_hw_params_fixup = avs_max98927_be_fixup;
dl->nonatomic = 1;
dl->no_pcm = 1;
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
index bf902540744c..e203ceb83b87 100644
--- a/sound/soc/intel/avs/boards/nau8825.c
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -88,7 +88,8 @@ static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -203,7 +204,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_nau8825_codec_init;
dl->exit = avs_nau8825_codec_exit;
dl->be_hw_params_fixup = avs_nau8825_be_fixup;
diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c
new file mode 100644
index 000000000000..5d0e7a5bdc74
--- /dev/null
+++ b/sound/soc/intel/avs/boards/pcm3168a.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2024-2025 Intel Corporation
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL),
+ SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL),
+ SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL),
+ SND_SOC_DAPM_LINE("CPB Line Out", NULL),
+ SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL),
+ SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL),
+ SND_SOC_DAPM_LINE("CPB Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ { "CPB Stereo HP 1", NULL, "AOUT1L" },
+ { "CPB Stereo HP 1", NULL, "AOUT1R" },
+ { "CPB Stereo HP 2", NULL, "AOUT2L" },
+ { "CPB Stereo HP 2", NULL, "AOUT2R" },
+ { "CPB Stereo HP 3", NULL, "AOUT3L" },
+ { "CPB Stereo HP 3", NULL, "AOUT3R" },
+ { "CPB Line Out", NULL, "AOUT4L" },
+ { "CPB Line Out", NULL, "AOUT4R" },
+
+ { "AIN1L", NULL, "CPB Stereo Mic 1" },
+ { "AIN1R", NULL, "CPB Stereo Mic 1" },
+ { "AIN2L", NULL, "CPB Stereo Mic 2" },
+ { "AIN2R", NULL, "CPB Stereo Mic 2" },
+ { "AIN3L", NULL, "CPB Line In" },
+ { "AIN3R", NULL, "CPB Line In" },
+};
+
+static int avs_pcm3168a_be_fixup(struct snd_soc_pcm_runtime *runtime,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* Set SSP to 24 bit. */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+SND_SOC_DAILINK_DEF(pcm3168a_dac,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-PCM3168A:00", "pcm3168a-dac")));
+SND_SOC_DAILINK_DEF(pcm3168a_adc,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-PCM3168A:00", "pcm3168a-adc")));
+SND_SOC_DAILINK_DEF(cpu_ssp0, DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
+SND_SOC_DAILINK_DEF(cpu_ssp2, DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin")));
+
+static int avs_create_dai_links(struct device *dev, struct snd_soc_dai_link **links, int *num_links)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+ const int num_dl = 2;
+
+ dl = devm_kcalloc(dev, num_dl, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = dev_name(dev);
+ dl[0].num_cpus = 1;
+ dl[0].num_codecs = 1;
+ dl[0].platforms = platform;
+ dl[0].num_platforms = 1;
+ dl[0].dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+ dl[0].be_hw_params_fixup = avs_pcm3168a_be_fixup;
+ dl[0].nonatomic = 1;
+ dl[0].no_pcm = 1;
+ memcpy(&dl[1], &dl[0], sizeof(*dl));
+
+ dl[0].name = "SSP0-Codec-dac";
+ dl[0].cpus = cpu_ssp0;
+ dl[0].codecs = pcm3168a_dac;
+ dl[1].name = "SSP2-Codec-adc";
+ dl[1].cpus = cpu_ssp2;
+ dl[1].codecs = pcm3168a_adc;
+
+ *links = dl;
+ *num_links = num_dl;
+ return 0;
+}
+
+static int avs_pcm3168a_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct snd_soc_card *card;
+ int ret;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ ret = avs_create_dai_links(dev, &card->dai_link, &card->num_links);
+ if (ret)
+ return ret;
+
+ card->name = "avs_pcm3168a";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(card_routes);
+ card->fully_routed = true;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static const struct platform_device_id avs_pcm3168a_driver_ids[] = {
+ {
+ .name = "avs_pcm3168a",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_pcm3168a_driver_ids);
+
+static struct platform_driver avs_pcm3168a_driver = {
+ .probe = avs_pcm3168a_probe,
+ .driver = {
+ .name = "avs_pcm3168a",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = avs_pcm3168a_driver_ids,
+};
+
+module_platform_driver(avs_pcm3168a_driver);
+
+MODULE_DESCRIPTION("Intel pcm3168a machine driver");
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
index 4b6c02a40204..29977aee2153 100644
--- a/sound/soc/intel/avs/boards/rt274.c
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -98,7 +98,8 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -178,7 +179,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_rt274_codec_init;
dl->exit = avs_rt274_codec_exit;
dl->be_hw_params_fixup = avs_rt274_be_fixup;
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
index e40563ca99fd..6a27c6a9f394 100644
--- a/sound/soc/intel/avs/boards/rt286.c
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -59,7 +59,8 @@ static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -146,7 +147,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_rt286_codec_init;
dl->exit = avs_rt286_codec_exit;
dl->be_hw_params_fixup = avs_rt286_be_fixup;
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
index 94fce07c83f9..a7a463d6f852 100644
--- a/sound/soc/intel/avs/boards/rt298.c
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -70,7 +70,8 @@ static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -164,9 +165,9 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->num_platforms = 1;
dl->id = 0;
if (dmi_first_match(kblr_dmi_table))
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
else
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_rt298_codec_init;
dl->exit = avs_rt298_codec_exit;
dl->be_hw_params_fixup = avs_rt298_be_fixup;
diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c
index 30588d9e9ba3..d1c3e29a28ff 100644
--- a/sound/soc/intel/avs/boards/rt5514.c
+++ b/sound/soc/intel/avs/boards/rt5514.c
@@ -116,7 +116,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_rt5514_codec_init;
dl->be_hw_params_fixup = avs_rt5514_be_fixup;
dl->nonatomic = 1;
diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c
index b456b9d14665..e3310b3268ba 100644
--- a/sound/soc/intel/avs/boards/rt5663.c
+++ b/sound/soc/intel/avs/boards/rt5663.c
@@ -65,7 +65,8 @@ static int avs_rt5663_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = &priv->jack;
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
index 335960cfd7ba..339df0b944c1 100644
--- a/sound/soc/intel/avs/boards/rt5682.c
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -102,7 +102,8 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_jack_pins);
- pins = devm_kmemdup(card->dev, card_jack_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_jack_pins, num_pins,
+ sizeof(card_jack_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
index cfef00462f66..7667790d5273 100644
--- a/sound/soc/intel/avs/boards/ssm4567.c
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -97,7 +97,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->name = devm_kasprintf(dev, GFP_KERNEL,
AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
- dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
@@ -116,7 +116,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_ssm4567_codec_init;
dl->be_hw_params_fixup = avs_ssm4567_be_fixup;
dl->nonatomic = 1;
diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c
index dc7dc45e0a0a..2e01dc75a15a 100644
--- a/sound/soc/intel/avs/control.c
+++ b/sound/soc/intel/avs/control.c
@@ -6,6 +6,7 @@
// Cezary Rojewski <cezary.rojewski@intel.com>
//
+#include <linux/cleanup.h>
#include <sound/soc.h>
#include "avs.h"
#include "control.h"
@@ -31,8 +32,11 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
list_for_each_entry(path, &adev->path_list, node) {
list_for_each_entry(ppl, &path->ppl_list, node) {
list_for_each_entry(mod, &ppl->mod_list, node) {
- if (guid_equal(&mod->template->cfg_ext->type, &AVS_PEAKVOL_MOD_UUID)
- && mod->template->ctl_id == id) {
+ guid_t *type = &mod->template->cfg_ext->type;
+
+ if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) ||
+ guid_equal(type, &AVS_GAIN_MOD_UUID)) &&
+ mod->template->ctl_id == id) {
spin_unlock(&adev->path_list_lock);
return mod;
}
@@ -44,70 +48,168 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
return NULL;
}
-int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
- struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
- struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private;
- struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol);
- struct avs_volume_cfg *dspvols = NULL;
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+ struct avs_control_data *ctl_data = mc->dobj.private;
struct avs_path_module *active_module;
+ struct avs_volume_cfg *dspvols;
+ struct avs_dev *adev;
size_t num_dspvols;
- int ret = 0;
+ int ret, i;
+
+ adev = avs_get_kcontrol_adev(kctl);
- /* prevent access to modules while path is being constructed */
- mutex_lock(&adev->path_mutex);
+ /* Prevent access to modules while path is being constructed. */
+ guard(mutex)(&adev->path_mutex);
active_module = avs_get_volume_module(adev, ctl_data->id);
if (active_module) {
ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id,
active_module->instance_id, &dspvols,
&num_dspvols);
- if (!ret)
- ucontrol->value.integer.value[0] = dspvols[0].target_volume;
+ if (ret)
+ return AVS_IPC_RET(ret);
- ret = AVS_IPC_RET(ret);
+ /* Do not copy more than the control can store. */
+ num_dspvols = min_t(u32, num_dspvols, SND_SOC_TPLG_MAX_CHAN);
+ for (i = 0; i < num_dspvols; i++)
+ ctl_data->values[i] = dspvols[i].target_volume;
kfree(dspvols);
- } else {
- ucontrol->value.integer.value[0] = ctl_data->volume;
}
- mutex_unlock(&adev->path_mutex);
- return ret;
+ memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values));
+ return 0;
}
-int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
- struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
- struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private;
- struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol);
- long *volume = &ctl_data->volume;
struct avs_path_module *active_module;
- struct avs_volume_cfg dspvol = {0};
- long ctlvol = ucontrol->value.integer.value[0];
- int ret = 0, changed = 0;
+ struct avs_control_data *ctl_data;
+ struct soc_mixer_control *mc;
+ struct avs_dev *adev;
+ long *input;
+ int ret, i;
+
+ mc = (struct soc_mixer_control *)kctl->private_value;
+ ctl_data = mc->dobj.private;
+ adev = avs_get_kcontrol_adev(kctl);
+ input = uctl->value.integer.value;
+ i = 0;
+
+ /* mc->num_channels can be 0. */
+ do {
+ if (input[i] < mc->min || input[i] > mc->max)
+ return -EINVAL;
+ } while (++i < mc->num_channels);
+
+ if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values)))
+ return 0;
+
+ /* Prevent access to modules while path is being constructed. */
+ guard(mutex)(&adev->path_mutex);
- if (ctlvol < 0 || ctlvol > mc->max)
- return -EINVAL;
+ active_module = avs_get_volume_module(adev, ctl_data->id);
+ if (active_module) {
+ ret = avs_peakvol_set_volume(adev, active_module, mc, input);
+ if (ret)
+ return ret;
+ }
- /* prevent access to modules while path is being constructed */
- mutex_lock(&adev->path_mutex);
+ memcpy(ctl_data->values, input, sizeof(ctl_data->values));
+ return 1;
+}
- if (*volume != ctlvol) {
- *volume = ctlvol;
- changed = 1;
- }
+int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = max_t(u32, 1, mc->num_channels);
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mc->max;
+ return 0;
+}
+
+int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+ struct avs_control_data *ctl_data = mc->dobj.private;
+ struct avs_path_module *active_module;
+ struct avs_mute_cfg *dspmutes;
+ struct avs_dev *adev;
+ size_t num_dspmutes;
+ int ret, i;
+
+ adev = avs_get_kcontrol_adev(kctl);
+
+ /* Prevent access to modules while path is being constructed. */
+ guard(mutex)(&adev->path_mutex);
active_module = avs_get_volume_module(adev, ctl_data->id);
if (active_module) {
- dspvol.channel_id = AVS_ALL_CHANNELS_MASK;
- dspvol.target_volume = *volume;
+ ret = avs_ipc_peakvol_get_mute(adev, active_module->module_id,
+ active_module->instance_id, &dspmutes,
+ &num_dspmutes);
+ if (ret)
+ return AVS_IPC_RET(ret);
+
+ /* Do not copy more than the control can store. */
+ num_dspmutes = min_t(u32, num_dspmutes, SND_SOC_TPLG_MAX_CHAN);
+ for (i = 0; i < num_dspmutes; i++)
+ ctl_data->values[i] = !dspmutes[i].mute;
+ kfree(dspmutes);
+ }
- ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id,
- active_module->instance_id, &dspvol);
- ret = AVS_IPC_RET(ret);
+ memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values));
+ return 0;
+}
+
+int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
+{
+ struct avs_path_module *active_module;
+ struct avs_control_data *ctl_data;
+ struct soc_mixer_control *mc;
+ struct avs_dev *adev;
+ long *input;
+ int ret, i;
+
+ mc = (struct soc_mixer_control *)kctl->private_value;
+ ctl_data = mc->dobj.private;
+ adev = avs_get_kcontrol_adev(kctl);
+ input = uctl->value.integer.value;
+ i = 0;
+
+ /* mc->num_channels can be 0. */
+ do {
+ if (input[i] < mc->min || input[i] > mc->max)
+ return -EINVAL;
+ } while (++i < mc->num_channels);
+
+ if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values)))
+ return 0;
+
+ /* Prevent access to modules while path is being constructed. */
+ guard(mutex)(&adev->path_mutex);
+
+ active_module = avs_get_volume_module(adev, ctl_data->id);
+ if (active_module) {
+ ret = avs_peakvol_set_mute(adev, active_module, mc, input);
+ if (ret)
+ return ret;
}
- mutex_unlock(&adev->path_mutex);
+ memcpy(ctl_data->values, input, sizeof(ctl_data->values));
+ return 1;
+}
+
+int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
- return ret ? ret : changed;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = max_t(u32, 1, mc->num_channels);
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mc->max;
+ return 0;
}
diff --git a/sound/soc/intel/avs/control.h b/sound/soc/intel/avs/control.h
index d9fac3569e8d..08b2919e4629 100644
--- a/sound/soc/intel/avs/control.h
+++ b/sound/soc/intel/avs/control.h
@@ -10,14 +10,18 @@
#define __SOUND_SOC_INTEL_AVS_CTRL_H
#include <sound/control.h>
+#include <uapi/sound/asoc.h>
struct avs_control_data {
u32 id;
-
- long volume;
+ long values[SND_SOC_TPLG_MAX_CHAN];
};
-int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
+int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
+int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo);
+int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
+int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
+int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo);
#endif
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 0e750e9e01d9..8fbf33e30dfc 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -612,7 +612,7 @@ static int avs_suspend_standby(struct avs_dev *adev)
return 0;
}
-static int __maybe_unused avs_suspend_common(struct avs_dev *adev, bool low_power)
+static int avs_suspend_common(struct avs_dev *adev, bool low_power)
{
struct hdac_bus *bus = &adev->base.core;
int ret;
@@ -673,7 +673,7 @@ static int avs_resume_standby(struct avs_dev *adev)
return 0;
}
-static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power, bool purge)
+static int avs_resume_common(struct avs_dev *adev, bool low_power, bool purge)
{
struct hdac_bus *bus = &adev->base.core;
int ret;
@@ -696,41 +696,41 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power
return 0;
}
-static int __maybe_unused avs_suspend(struct device *dev)
+static int avs_suspend(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), true);
}
-static int __maybe_unused avs_resume(struct device *dev)
+static int avs_resume(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), true, true);
}
-static int __maybe_unused avs_runtime_suspend(struct device *dev)
+static int avs_runtime_suspend(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), true);
}
-static int __maybe_unused avs_runtime_resume(struct device *dev)
+static int avs_runtime_resume(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), true, false);
}
-static int __maybe_unused avs_freeze(struct device *dev)
+static int avs_freeze(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), false);
}
-static int __maybe_unused avs_thaw(struct device *dev)
+static int avs_thaw(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), false, true);
}
-static int __maybe_unused avs_poweroff(struct device *dev)
+static int avs_poweroff(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), false);
}
-static int __maybe_unused avs_restore(struct device *dev)
+static int avs_restore(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), false, true);
}
@@ -742,7 +742,7 @@ static const struct dev_pm_ops avs_dev_pm = {
.thaw = avs_thaw,
.poweroff = avs_poweroff,
.restore = avs_restore,
- SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
+ RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
};
static const struct avs_sram_spec skl_sram_spec = {
@@ -893,7 +893,7 @@ static struct pci_driver avs_pci_driver = {
.shutdown = avs_pci_shutdown,
.dev_groups = avs_attr_groups,
.driver = {
- .pm = &avs_dev_pm,
+ .pm = pm_ptr(&avs_dev_pm),
},
};
module_pci_driver(avs_pci_driver);
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
index 7b47e52c2b39..b9de691e9b9b 100644
--- a/sound/soc/intel/avs/dsp.c
+++ b/sound/soc/intel/avs/dsp.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/string_choices.h>
#include <sound/hdaudio_ext.h>
#include "avs.h"
#include "registers.h"
@@ -39,7 +40,7 @@ int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
AVS_ADSPCS_TIMEOUT_US);
if (ret)
dev_err(adev->dev, "core_mask %d power %s failed: %d\n",
- core_mask, power ? "on" : "off", ret);
+ core_mask, str_on_off(power), ret);
return ret;
}
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 9ff7818395cd..0b29941feb0e 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -603,7 +603,7 @@ release_fw:
return ret;
}
-int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
+static int avs_load_firmware(struct avs_dev *adev, bool purge)
{
struct avs_soc_component *acomp;
int ret, i;
@@ -657,28 +657,33 @@ reenable_gating:
return 0;
}
-int avs_dsp_first_boot_firmware(struct avs_dev *adev)
+static int avs_config_basefw(struct avs_dev *adev)
{
- int ret, i;
+ int ret;
- if (avs_platattr_test(adev, CLDMA)) {
- ret = hda_cldma_init(&code_loader, &adev->base.core,
- adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE);
- if (ret < 0) {
- dev_err(adev->dev, "cldma init failed: %d\n", ret);
+ if (adev->spec->dsp_ops->config_basefw) {
+ ret = avs_dsp_op(adev, config_basefw);
+ if (ret)
return ret;
- }
}
- ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
- if (ret < 0)
- return ret;
+ return 0;
+}
- ret = avs_dsp_boot_firmware(adev, true);
- if (ret < 0) {
- dev_err(adev->dev, "firmware boot failed: %d\n", ret);
+int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
+{
+ int ret;
+
+ ret = avs_load_firmware(adev, purge);
+ if (ret)
return ret;
- }
+
+ return avs_config_basefw(adev);
+}
+
+static int avs_dsp_alloc_resources(struct avs_dev *adev)
+{
+ int ret, i;
ret = avs_ipc_get_hw_config(adev, &adev->hw_cfg);
if (ret)
@@ -705,6 +710,31 @@ int avs_dsp_first_boot_firmware(struct avs_dev *adev)
strscpy(adev->lib_names[0], "BASEFW", AVS_LIB_NAME_SIZE);
ida_init(&adev->ppl_ida);
-
return 0;
}
+
+int avs_dsp_first_boot_firmware(struct avs_dev *adev)
+{
+ int ret;
+
+ if (avs_platattr_test(adev, CLDMA)) {
+ ret = hda_cldma_init(&code_loader, &adev->base.core,
+ adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE);
+ if (ret < 0) {
+ dev_err(adev->dev, "cldma init failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
+ if (ret < 0)
+ return ret;
+
+ ret = avs_dsp_boot_firmware(adev, true);
+ if (ret < 0) {
+ dev_err(adev->dev, "firmware boot failed: %d\n", ret);
+ return ret;
+ }
+
+ return avs_dsp_alloc_resources(adev);
+}
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index 30b666f8909b..a5ba27983091 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -510,6 +510,44 @@ err:
return ret;
}
+int avs_ipc_set_fw_config(struct avs_dev *adev, size_t num_tlvs, ...)
+{
+ struct avs_tlv *tlv;
+ void *payload;
+ size_t offset;
+ va_list args;
+ int ret, i;
+
+ payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ va_start(args, num_tlvs);
+ for (offset = i = 0; i < num_tlvs && offset < AVS_MAILBOX_SIZE - sizeof(*tlv); i++) {
+ tlv = (struct avs_tlv *)(payload + offset);
+ tlv->type = va_arg(args, u32);
+ tlv->length = va_arg(args, u32);
+
+ offset += sizeof(*tlv) + tlv->length;
+ if (offset > AVS_MAILBOX_SIZE)
+ break;
+
+ memcpy(tlv->value, va_arg(args, u8*), tlv->length);
+ }
+
+ if (i == num_tlvs)
+ ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+ AVS_BASEFW_FIRMWARE_CONFIG, payload, offset);
+ else
+ ret = -ERANGE;
+
+ va_end(args);
+ kfree(payload);
+ if (ret)
+ dev_err(adev->dev, "set fw cfg failed: %d\n", ret);
+ return ret;
+}
+
int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg)
{
struct avs_tlv *tlv;
@@ -639,13 +677,6 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
(u8 *)&cpr_fmt, sizeof(cpr_fmt));
}
-int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
- struct avs_volume_cfg *vol)
-{
- return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, (u8 *)vol,
- sizeof(*vol));
-}
-
int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
struct avs_volume_cfg **vols, size_t *num_vols)
{
@@ -668,6 +699,110 @@ int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_
return 0;
}
+int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_volume_cfg *vol)
+{
+ return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME,
+ (u8 *)vol, sizeof(*vol));
+}
+
+int avs_ipc_peakvol_set_volumes(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_volume_cfg *vols, size_t num_vols)
+{
+ struct avs_tlv *tlv;
+ size_t offset;
+ size_t size;
+ u8 *payload;
+ int ret, i;
+
+ size = num_vols * sizeof(*vols);
+ size += num_vols * sizeof(*tlv);
+ if (size > AVS_MAILBOX_SIZE)
+ return -EINVAL;
+
+ payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ for (offset = i = 0; i < num_vols; i++) {
+ tlv = (struct avs_tlv *)(payload + offset);
+
+ tlv->type = AVS_PEAKVOL_VOLUME;
+ tlv->length = sizeof(*vols);
+ memcpy(tlv->value, &vols[i], tlv->length);
+
+ offset += sizeof(*tlv) + tlv->length;
+ }
+
+ ret = avs_ipc_set_large_config(adev, module_id, instance_id, AVS_VENDOR_CONFIG, payload,
+ size);
+ kfree(payload);
+ return ret;
+}
+
+int avs_ipc_peakvol_get_mute(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg **mutes, size_t *num_mutes)
+{
+ size_t payload_size;
+ u8 *payload;
+ int ret;
+
+ ret = avs_ipc_get_large_config(adev, module_id, instance_id, AVS_PEAKVOL_MUTE, NULL, 0,
+ &payload, &payload_size);
+ if (ret)
+ return ret;
+
+ /* Non-zero payload expected for PEAKVOL_MUTE. */
+ if (!payload_size)
+ return -EREMOTEIO;
+
+ *mutes = (struct avs_mute_cfg *)payload;
+ *num_mutes = payload_size / sizeof(**mutes);
+
+ return 0;
+}
+
+int avs_ipc_peakvol_set_mute(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg *mute)
+{
+ return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_MUTE,
+ (u8 *)mute, sizeof(*mute));
+}
+
+int avs_ipc_peakvol_set_mutes(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg *mutes, size_t num_mutes)
+{
+ struct avs_tlv *tlv;
+ size_t offset;
+ size_t size;
+ u8 *payload;
+ int ret, i;
+
+ size = num_mutes * sizeof(*mutes);
+ size += num_mutes * sizeof(*tlv);
+ if (size > AVS_MAILBOX_SIZE)
+ return -EINVAL;
+
+ payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ for (offset = i = 0; i < num_mutes; i++) {
+ tlv = (struct avs_tlv *)(payload + offset);
+
+ tlv->type = AVS_PEAKVOL_MUTE;
+ tlv->length = sizeof(*mutes);
+ memcpy(tlv->value, &mutes[i], tlv->length);
+
+ offset += sizeof(*tlv) + tlv->length;
+ }
+
+ ret = avs_ipc_set_large_config(adev, module_id, instance_id, AVS_VENDOR_CONFIG, payload,
+ size);
+ kfree(payload);
+ return ret;
+}
+
#ifdef CONFIG_DEBUG_FS
int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
{
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index 0378633c7f96..2f243802ccc2 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -451,6 +451,8 @@ enum avs_fw_cfg_params {
AVS_FW_CFG_RESERVED,
AVS_FW_CFG_POWER_GATING_POLICY,
AVS_FW_CFG_ASSERT_MODE,
+ AVS_FW_CFG_RESERVED2,
+ AVS_FW_CFG_BUS_HARDWARE_ID,
};
struct avs_fw_cfg {
@@ -475,7 +477,14 @@ struct avs_fw_cfg {
u32 power_gating_policy;
};
+struct avs_bus_hwid {
+ u32 device;
+ u32 subsystem;
+ u8 revision;
+};
+
int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg);
+int avs_ipc_set_fw_config(struct avs_dev *adev, size_t num_tlvs, ...);
enum avs_hw_cfg_params {
AVS_HW_CFG_AVS_VER,
@@ -643,6 +652,9 @@ int avs_ipc_set_system_time(struct avs_dev *adev);
#define AVS_INTELWOV_MOD_UUID \
GUID_INIT(0xEC774FA9, 0x28D3, 0x424A, 0x90, 0xE4, 0x69, 0xF9, 0x84, 0xF1, 0xEE, 0xB7)
+#define AVS_WOVHOSTM_MOD_UUID \
+ GUID_INIT(0xF9ED62B7, 0x092E, 0x4A90, 0x8F, 0x4D, 0x82, 0xDA, 0xA8, 0xB3, 0x8F, 0x3B)
+
/* channel map */
enum avs_channel_index {
AVS_CHANNEL_LEFT = 0,
@@ -802,6 +814,15 @@ struct avs_volume_cfg {
} __packed;
static_assert(sizeof(struct avs_volume_cfg) == 24);
+struct avs_mute_cfg {
+ u32 channel_id;
+ u32 mute;
+ u32 curve_type;
+ u32 reserved; /* alignment */
+ u64 curve_duration;
+} __packed;
+static_assert(sizeof(struct avs_mute_cfg) == 24);
+
struct avs_peakvol_cfg {
struct avs_modcfg_base base;
struct avs_volume_cfg vols[];
@@ -872,8 +893,20 @@ struct avs_wov_cfg {
} __packed;
static_assert(sizeof(struct avs_wov_cfg) == 44);
+struct avs_whm_cfg {
+ struct avs_modcfg_base base;
+ /* Audio format for output pin 0 */
+ struct avs_audio_format ref_fmt;
+ struct avs_audio_format out_fmt;
+ u32 wake_tick_period;
+ struct avs_copier_gtw_cfg gtw_cfg;
+} __packed;
+static_assert(sizeof(struct avs_whm_cfg) == 108);
+
/* Module runtime parameters */
+#define AVS_VENDOR_CONFIG 0xFF
+
enum avs_copier_runtime_param {
AVS_COPIER_SET_SINK_FORMAT = 2,
};
@@ -892,6 +925,7 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
enum avs_peakvol_runtime_param {
AVS_PEAKVOL_VOLUME = 0,
+ AVS_PEAKVOL_MUTE = 3,
};
enum avs_audio_curve_type {
@@ -899,10 +933,18 @@ enum avs_audio_curve_type {
AVS_AUDIO_CURVE_WINDOWS_FADE = 1,
};
-int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
- struct avs_volume_cfg *vol);
int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
struct avs_volume_cfg **vols, size_t *num_vols);
+int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_volume_cfg *vol);
+int avs_ipc_peakvol_set_volumes(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_volume_cfg *vols, size_t num_vols);
+int avs_ipc_peakvol_get_mute(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg **mutes, size_t *num_mutes);
+int avs_ipc_peakvol_set_mute(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg *mute);
+int avs_ipc_peakvol_set_mutes(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg *mutes, size_t num_mutes);
#define AVS_PROBE_INST_ID 0
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index f31d5e2caa7b..cafb8c6198be 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -115,154 +115,265 @@ avs_path_find_variant(struct avs_dev *adev,
return NULL;
}
-__maybe_unused
-static bool avs_dma_type_is_host(u32 dma_type)
-{
- return dma_type == AVS_DMA_HDA_HOST_OUTPUT ||
- dma_type == AVS_DMA_HDA_HOST_INPUT;
-}
+static struct acpi_nhlt_config *
+avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t);
-__maybe_unused
-static bool avs_dma_type_is_link(u32 dma_type)
+int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template *template,
+ struct snd_pcm_hw_constraint_list *rate_list,
+ struct snd_pcm_hw_constraint_list *channels_list,
+ struct snd_pcm_hw_constraint_list *sample_bits_list)
{
- return !avs_dma_type_is_host(dma_type);
-}
+ struct avs_tplg_path *path_template;
+ unsigned int *rlist, *clist, *slist;
+ size_t i;
+
+ i = 0;
+ list_for_each_entry(path_template, &template->path_list, node)
+ i++;
+
+ rlist = kcalloc(i, sizeof(rlist), GFP_KERNEL);
+ clist = kcalloc(i, sizeof(clist), GFP_KERNEL);
+ slist = kcalloc(i, sizeof(slist), GFP_KERNEL);
+
+ i = 0;
+ list_for_each_entry(path_template, &template->path_list, node) {
+ struct avs_tplg_pipeline *pipeline_template;
+
+ list_for_each_entry(pipeline_template, &path_template->ppl_list, node) {
+ struct avs_tplg_module *module_template;
+
+ list_for_each_entry(module_template, &pipeline_template->mod_list, node) {
+ const guid_t *type = &module_template->cfg_ext->type;
+ struct acpi_nhlt_config *blob;
+
+ if (!guid_equal(type, &AVS_COPIER_MOD_UUID) &&
+ !guid_equal(type, &AVS_WOVHOSTM_MOD_UUID))
+ continue;
+
+ switch (module_template->cfg_ext->copier.dma_type) {
+ case AVS_DMA_DMIC_LINK_INPUT:
+ case AVS_DMA_I2S_LINK_OUTPUT:
+ case AVS_DMA_I2S_LINK_INPUT:
+ break;
+ default:
+ continue;
+ }
+
+ blob = avs_nhlt_config_or_default(adev, module_template);
+ if (IS_ERR(blob))
+ continue;
+
+ rlist[i] = path_template->fe_fmt->sampling_freq;
+ clist[i] = path_template->fe_fmt->num_channels;
+ slist[i] = path_template->fe_fmt->bit_depth;
+ i++;
+ }
+ }
+ }
-__maybe_unused
-static bool avs_dma_type_is_output(u32 dma_type)
-{
- return dma_type == AVS_DMA_HDA_HOST_OUTPUT ||
- dma_type == AVS_DMA_HDA_LINK_OUTPUT ||
- dma_type == AVS_DMA_I2S_LINK_OUTPUT;
-}
+ if (i) {
+ rate_list->count = i;
+ rate_list->list = rlist;
+ channels_list->count = i;
+ channels_list->list = clist;
+ sample_bits_list->count = i;
+ sample_bits_list->list = slist;
+ } else {
+ kfree(rlist);
+ kfree(clist);
+ kfree(slist);
+ }
-__maybe_unused
-static bool avs_dma_type_is_input(u32 dma_type)
-{
- return !avs_dma_type_is_output(dma_type);
+ return i;
}
-static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod)
+static void avs_init_node_id(union avs_connector_node_id *node_id,
+ struct avs_tplg_modcfg_ext *te, u32 dma_id)
{
- struct avs_tplg_module *t = mod->template;
- struct avs_copier_cfg *cfg;
- struct acpi_nhlt_format_config *ep_blob;
- struct acpi_nhlt_endpoint *ep;
- union avs_connector_node_id node_id = {0};
- size_t cfg_size, data_size;
- void *data = NULL;
- u32 dma_type;
- int ret;
-
- data_size = sizeof(cfg->gtw_cfg.config);
- dma_type = t->cfg_ext->copier.dma_type;
- node_id.dma_type = dma_type;
-
- switch (dma_type) {
- struct avs_audio_format *fmt;
- int direction;
+ node_id->val = 0;
+ node_id->dma_type = te->copier.dma_type;
+ switch (node_id->dma_type) {
+ case AVS_DMA_DMIC_LINK_INPUT:
case AVS_DMA_I2S_LINK_OUTPUT:
case AVS_DMA_I2S_LINK_INPUT:
- if (avs_dma_type_is_input(dma_type))
- direction = SNDRV_PCM_STREAM_CAPTURE;
- else
- direction = SNDRV_PCM_STREAM_PLAYBACK;
-
- if (t->cfg_ext->copier.blob_fmt)
- fmt = t->cfg_ext->copier.blob_fmt;
- else if (direction == SNDRV_PCM_STREAM_CAPTURE)
- fmt = t->in_fmt;
- else
- fmt = t->cfg_ext->copier.out_fmt;
-
- ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP,
- ACPI_NHLT_DEVICETYPE_CODEC, direction,
- t->cfg_ext->copier.vindex.i2s.instance);
- ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq,
- fmt->valid_bit_depth, fmt->bit_depth);
- if (!ep_blob) {
- dev_err(adev->dev, "no I2S ep_blob found\n");
- return -ENOENT;
- }
+ /* Gateway's virtual index is statically assigned in the topology. */
+ node_id->vindex = te->copier.vindex.val;
+ break;
- data = ep_blob->config.capabilities;
- data_size = ep_blob->config.capabilities_size;
- /* I2S gateway's vindex is statically assigned in topology */
- node_id.vindex = t->cfg_ext->copier.vindex.val;
+ case AVS_DMA_HDA_HOST_OUTPUT:
+ case AVS_DMA_HDA_HOST_INPUT:
+ /* Gateway's virtual index is dynamically assigned with DMA ID */
+ node_id->vindex = dma_id;
+ break;
+ case AVS_DMA_HDA_LINK_OUTPUT:
+ case AVS_DMA_HDA_LINK_INPUT:
+ node_id->vindex = te->copier.vindex.val | dma_id;
break;
- case AVS_DMA_DMIC_LINK_INPUT:
- direction = SNDRV_PCM_STREAM_CAPTURE;
-
- if (t->cfg_ext->copier.blob_fmt)
- fmt = t->cfg_ext->copier.blob_fmt;
- else
- fmt = t->in_fmt;
-
- ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, direction, 0);
- ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq,
- fmt->valid_bit_depth, fmt->bit_depth);
- if (!ep_blob) {
- dev_err(adev->dev, "no DMIC ep_blob found\n");
- return -ENOENT;
- }
+ default:
+ *node_id = INVALID_NODE_ID;
+ break;
+ }
+}
- data = ep_blob->config.capabilities;
- data_size = ep_blob->config.capabilities_size;
- /* DMIC gateway's vindex is statically assigned in topology */
- node_id.vindex = t->cfg_ext->copier.vindex.val;
+/* Every BLOB contains at least gateway attributes. */
+static struct acpi_nhlt_config *default_blob = (struct acpi_nhlt_config *)&(u32[2]) {4};
+static struct acpi_nhlt_config *
+avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t)
+{
+ struct acpi_nhlt_format_config *fmtcfg;
+ struct avs_tplg_modcfg_ext *te;
+ struct avs_audio_format *fmt;
+ int link_type, dev_type;
+ int bus_id, dir;
+
+ te = t->cfg_ext;
+
+ switch (te->copier.dma_type) {
+ case AVS_DMA_I2S_LINK_OUTPUT:
+ link_type = ACPI_NHLT_LINKTYPE_SSP;
+ dev_type = ACPI_NHLT_DEVICETYPE_CODEC;
+ bus_id = te->copier.vindex.i2s.instance;
+ dir = SNDRV_PCM_STREAM_PLAYBACK;
+ fmt = te->copier.out_fmt;
break;
- case AVS_DMA_HDA_HOST_OUTPUT:
- case AVS_DMA_HDA_HOST_INPUT:
- /* HOST gateway's vindex is dynamically assigned with DMA id */
- node_id.vindex = mod->owner->owner->dma_id;
+ case AVS_DMA_I2S_LINK_INPUT:
+ link_type = ACPI_NHLT_LINKTYPE_SSP;
+ dev_type = ACPI_NHLT_DEVICETYPE_CODEC;
+ bus_id = te->copier.vindex.i2s.instance;
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ fmt = t->in_fmt;
break;
- case AVS_DMA_HDA_LINK_OUTPUT:
- case AVS_DMA_HDA_LINK_INPUT:
- node_id.vindex = t->cfg_ext->copier.vindex.val |
- mod->owner->owner->dma_id;
+ case AVS_DMA_DMIC_LINK_INPUT:
+ link_type = ACPI_NHLT_LINKTYPE_PDM;
+ dev_type = -1; /* ignored */
+ bus_id = 0;
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ fmt = t->in_fmt;
break;
- case INVALID_OBJECT_ID:
default:
- node_id = INVALID_NODE_ID;
- break;
+ return default_blob;
}
- cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config) + data_size;
- if (cfg_size > AVS_MAILBOX_SIZE)
- return -EINVAL;
+ /* Override format selection if necessary. */
+ if (te->copier.blob_fmt)
+ fmt = te->copier.blob_fmt;
+
+ fmtcfg = acpi_nhlt_find_fmtcfg(link_type, dev_type, dir, bus_id,
+ fmt->num_channels, fmt->sampling_freq, fmt->valid_bit_depth,
+ fmt->bit_depth);
+ if (!fmtcfg) {
+ dev_warn(adev->dev, "Endpoint format configuration not found.\n");
+ return ERR_PTR(-ENOENT);
+ }
+
+ if (fmtcfg->config.capabilities_size < default_blob->capabilities_size)
+ return ERR_PTR(-ETOOSMALL);
+ /* The firmware expects the payload to be DWORD-aligned. */
+ if (fmtcfg->config.capabilities_size % sizeof(u32))
+ return ERR_PTR(-EINVAL);
+
+ return &fmtcfg->config;
+}
+
+static int avs_fill_gtw_config(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw,
+ struct avs_tplg_module *t, size_t *cfg_size)
+{
+ struct acpi_nhlt_config *blob;
+ size_t gtw_size;
+
+ blob = avs_nhlt_config_or_default(adev, t);
+ if (IS_ERR(blob))
+ return PTR_ERR(blob);
+
+ gtw_size = blob->capabilities_size;
+ if (*cfg_size + gtw_size > AVS_MAILBOX_SIZE)
+ return -E2BIG;
+
+ gtw->config_length = gtw_size / sizeof(u32);
+ memcpy(gtw->config.blob, blob->capabilities, blob->capabilities_size);
+ *cfg_size += gtw_size;
+
+ return 0;
+}
+
+static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod)
+{
+ struct avs_tplg_module *t = mod->template;
+ struct avs_tplg_modcfg_ext *te;
+ struct avs_copier_cfg *cfg;
+ size_t cfg_size;
+ u32 dma_id;
+ int ret;
+ te = t->cfg_ext;
cfg = adev->modcfg_buf;
- memset(cfg, 0, cfg_size);
+ dma_id = mod->owner->owner->dma_id;
+ cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config);
+
+ ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size);
+ if (ret)
+ return ret;
+
cfg->base.cpc = t->cfg_base->cpc;
cfg->base.ibs = t->cfg_base->ibs;
cfg->base.obs = t->cfg_base->obs;
cfg->base.is_pages = t->cfg_base->is_pages;
cfg->base.audio_fmt = *t->in_fmt;
- cfg->out_fmt = *t->cfg_ext->copier.out_fmt;
- cfg->feature_mask = t->cfg_ext->copier.feature_mask;
- cfg->gtw_cfg.node_id = node_id;
- cfg->gtw_cfg.dma_buffer_size = t->cfg_ext->copier.dma_buffer_size;
- /* config_length in DWORDs */
- cfg->gtw_cfg.config_length = DIV_ROUND_UP(data_size, 4);
- if (data)
- memcpy(&cfg->gtw_cfg.config.blob, data, data_size);
+ cfg->out_fmt = *te->copier.out_fmt;
+ cfg->feature_mask = te->copier.feature_mask;
+ avs_init_node_id(&cfg->gtw_cfg.node_id, te, dma_id);
+ cfg->gtw_cfg.dma_buffer_size = te->copier.dma_buffer_size;
+ mod->gtw_attrs = cfg->gtw_cfg.config.attrs;
+
+ ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id,
+ t->domain, cfg, cfg_size, &mod->instance_id);
+ return ret;
+}
+static int avs_whm_create(struct avs_dev *adev, struct avs_path_module *mod)
+{
+ struct avs_tplg_module *t = mod->template;
+ struct avs_tplg_modcfg_ext *te;
+ struct avs_whm_cfg *cfg;
+ size_t cfg_size;
+ u32 dma_id;
+ int ret;
+
+ te = t->cfg_ext;
+ cfg = adev->modcfg_buf;
+ dma_id = mod->owner->owner->dma_id;
+ cfg_size = offsetof(struct avs_whm_cfg, gtw_cfg.config);
+
+ ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size);
+ if (ret)
+ return ret;
+
+ cfg->base.cpc = t->cfg_base->cpc;
+ cfg->base.ibs = t->cfg_base->ibs;
+ cfg->base.obs = t->cfg_base->obs;
+ cfg->base.is_pages = t->cfg_base->is_pages;
+ cfg->base.audio_fmt = *t->in_fmt;
+ cfg->ref_fmt = *te->whm.ref_fmt;
+ cfg->out_fmt = *te->whm.out_fmt;
+ cfg->wake_tick_period = te->whm.wake_tick_period;
+ avs_init_node_id(&cfg->gtw_cfg.node_id, te, dma_id);
+ cfg->gtw_cfg.dma_buffer_size = te->whm.dma_buffer_size;
mod->gtw_attrs = cfg->gtw_cfg.config.attrs;
- ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,
- t->core_id, t->domain, cfg, cfg_size,
- &mod->instance_id);
+ ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id,
+ t->domain, cfg, cfg_size, &mod->instance_id);
return ret;
}
-static struct avs_control_data *avs_get_module_control(struct avs_path_module *mod)
+static struct soc_mixer_control *avs_get_module_control(struct avs_path_module *mod,
+ const char *name)
{
struct avs_tplg_module *t = mod->template;
struct avs_tplg_path_template *path_tmpl;
@@ -278,27 +389,93 @@ static struct avs_control_data *avs_get_module_control(struct avs_path_module *m
mc = (struct soc_mixer_control *)w->kcontrols[i]->private_value;
ctl_data = (struct avs_control_data *)mc->dobj.private;
- if (ctl_data->id == t->ctl_id)
- return ctl_data;
+ if (ctl_data->id == t->ctl_id && strstr(w->kcontrols[i]->id.name, name))
+ return mc;
}
return NULL;
}
+int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod,
+ struct soc_mixer_control *mc, long *input)
+{
+ struct avs_volume_cfg vols[SND_SOC_TPLG_MAX_CHAN] = {{0}};
+ struct avs_control_data *ctl_data;
+ struct avs_tplg_module *t;
+ int ret, i;
+
+ ctl_data = mc->dobj.private;
+ t = mod->template;
+ if (!input)
+ input = ctl_data->values;
+
+ if (mc->num_channels) {
+ for (i = 0; i < mc->num_channels; i++) {
+ vols[i].channel_id = i;
+ vols[i].target_volume = input[i];
+ vols[i].curve_type = t->cfg_ext->peakvol.curve_type;
+ vols[i].curve_duration = t->cfg_ext->peakvol.curve_duration;
+ }
+
+ ret = avs_ipc_peakvol_set_volumes(adev, mod->module_id, mod->instance_id, vols,
+ mc->num_channels);
+ return AVS_IPC_RET(ret);
+ }
+
+ /* Target all channels if no individual selected. */
+ vols[0].channel_id = AVS_ALL_CHANNELS_MASK;
+ vols[0].target_volume = input[0];
+ vols[0].curve_type = t->cfg_ext->peakvol.curve_type;
+ vols[0].curve_duration = t->cfg_ext->peakvol.curve_duration;
+
+ ret = avs_ipc_peakvol_set_volume(adev, mod->module_id, mod->instance_id, &vols[0]);
+ return AVS_IPC_RET(ret);
+}
+
+int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod,
+ struct soc_mixer_control *mc, long *input)
+{
+ struct avs_mute_cfg mutes[SND_SOC_TPLG_MAX_CHAN] = {{0}};
+ struct avs_control_data *ctl_data;
+ struct avs_tplg_module *t;
+ int ret, i;
+
+ ctl_data = mc->dobj.private;
+ t = mod->template;
+ if (!input)
+ input = ctl_data->values;
+
+ if (mc->num_channels) {
+ for (i = 0; i < mc->num_channels; i++) {
+ mutes[i].channel_id = i;
+ mutes[i].mute = !input[i];
+ mutes[i].curve_type = t->cfg_ext->peakvol.curve_type;
+ mutes[i].curve_duration = t->cfg_ext->peakvol.curve_duration;
+ }
+
+ ret = avs_ipc_peakvol_set_mutes(adev, mod->module_id, mod->instance_id, mutes,
+ mc->num_channels);
+ return AVS_IPC_RET(ret);
+ }
+
+ /* Target all channels if no individual selected. */
+ mutes[0].channel_id = AVS_ALL_CHANNELS_MASK;
+ mutes[0].mute = !input[0];
+ mutes[0].curve_type = t->cfg_ext->peakvol.curve_type;
+ mutes[0].curve_duration = t->cfg_ext->peakvol.curve_duration;
+
+ ret = avs_ipc_peakvol_set_mute(adev, mod->module_id, mod->instance_id, &mutes[0]);
+ return AVS_IPC_RET(ret);
+}
+
static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod)
{
struct avs_tplg_module *t = mod->template;
- struct avs_control_data *ctl_data;
+ struct soc_mixer_control *mc;
struct avs_peakvol_cfg *cfg;
- int volume = S32_MAX;
size_t cfg_size;
int ret;
- ctl_data = avs_get_module_control(mod);
- if (ctl_data)
- volume = ctl_data->volume;
-
- /* As 2+ channels controls are unsupported, have a single block for all channels. */
cfg_size = struct_size(cfg, vols, 1);
if (cfg_size > AVS_MAILBOX_SIZE)
return -EINVAL;
@@ -310,15 +487,28 @@ static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod)
cfg->base.obs = t->cfg_base->obs;
cfg->base.is_pages = t->cfg_base->is_pages;
cfg->base.audio_fmt = *t->in_fmt;
- cfg->vols[0].target_volume = volume;
cfg->vols[0].channel_id = AVS_ALL_CHANNELS_MASK;
- cfg->vols[0].curve_type = AVS_AUDIO_CURVE_NONE;
- cfg->vols[0].curve_duration = 0;
+ cfg->vols[0].target_volume = S32_MAX;
+ cfg->vols[0].curve_type = t->cfg_ext->peakvol.curve_type;
+ cfg->vols[0].curve_duration = t->cfg_ext->peakvol.curve_duration;
ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id,
t->domain, cfg, cfg_size, &mod->instance_id);
+ if (ret)
+ return ret;
- return ret;
+ /* Now configure both VOLUME and MUTE parameters. */
+ mc = avs_get_module_control(mod, "Volume");
+ if (mc) {
+ ret = avs_peakvol_set_volume(adev, mod, mc, NULL);
+ if (ret)
+ return ret;
+ }
+
+ mc = avs_get_module_control(mod, "Switch");
+ if (mc)
+ return avs_peakvol_set_mute(adev, mod, mc, NULL);
+ return 0;
}
static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *mod)
@@ -533,6 +723,7 @@ static struct avs_module_create avs_module_create[] = {
{ &AVS_ASRC_MOD_UUID, avs_asrc_create },
{ &AVS_INTELWOV_MOD_UUID, avs_wov_create },
{ &AVS_PROBE_MOD_UUID, avs_probe_create },
+ { &AVS_WOVHOSTM_MOD_UUID, avs_whm_create },
};
static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_module *mod)
diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h
index bfd253c9fa95..c65ed84aa853 100644
--- a/sound/soc/intel/avs/path.h
+++ b/sound/soc/intel/avs/path.h
@@ -69,4 +69,14 @@ int avs_path_reset(struct avs_path *path);
int avs_path_pause(struct avs_path *path);
int avs_path_run(struct avs_path *path, int trigger);
+int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template *template,
+ struct snd_pcm_hw_constraint_list *rate_list,
+ struct snd_pcm_hw_constraint_list *channels_list,
+ struct snd_pcm_hw_constraint_list *sample_bits_list);
+
+int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod,
+ struct soc_mixer_control *mc, long *input);
+int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod,
+ struct soc_mixer_control *mc, long *input);
+
#endif
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 4bfbcb5a5ae8..d83ef504643b 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -31,6 +31,10 @@ struct avs_dma_data {
struct hdac_ext_stream *host_stream;
};
+ struct snd_pcm_hw_constraint_list rate_list;
+ struct snd_pcm_hw_constraint_list channels_list;
+ struct snd_pcm_hw_constraint_list sample_bits_list;
+
struct work_struct period_elapsed_work;
struct snd_pcm_substream *substream;
};
@@ -74,6 +78,45 @@ void avs_period_elapsed(struct snd_pcm_substream *substream)
schedule_work(&data->period_elapsed_work);
}
+static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule);
+static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hw_constraint_list *r, *c, *s;
+ struct avs_tplg_path_template *template;
+ struct avs_dma_data *data;
+ int ret;
+
+ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ return ret;
+
+ data = snd_soc_dai_get_dma_data(dai, substream);
+ r = &(data->rate_list);
+ c = &(data->channels_list);
+ s = &(data->sample_bits_list);
+
+ template = avs_dai_find_path_template(dai, !rtd->dai_link->no_pcm, substream->stream);
+ ret = avs_path_set_constraint(data->adev, template, r, c, s);
+ if (ret <= 0)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, r);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, c);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, s);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
@@ -101,7 +144,7 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d
if (rtd->dai_link->ignore_suspend)
adev->num_lp_paths++;
- return 0;
+ return avs_hw_constraints_init(substream, dai);
}
static void avs_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
@@ -114,6 +157,10 @@ static void avs_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc
if (rtd->dai_link->ignore_suspend)
data->adev->num_lp_paths--;
+ kfree(data->rate_list.list);
+ kfree(data->channels_list.list);
+ kfree(data->sample_bits_list.list);
+
snd_soc_dai_set_dma_data(dai, substream, NULL);
kfree(data);
}
@@ -927,7 +974,8 @@ static int avs_component_probe(struct snd_soc_component *component)
else
mach->tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,
"hda-generic-tplg.bin");
-
+ if (!mach->tplg_filename)
+ return -ENOMEM;
filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
mach->tplg_filename);
if (!filename)
@@ -1380,7 +1428,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l
for_each_set_bit(i, &port_mask, ssp_count)
cpu_count += hweight_long(tdms[i]);
- cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL);
+ cpus = devm_kcalloc(adev->dev, cpu_count, sizeof(*cpus), GFP_KERNEL);
if (!cpus)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c
index a9019ff5e3af..56905f2b9eb2 100644
--- a/sound/soc/intel/avs/tgl.c
+++ b/sound/soc/intel/avs/tgl.c
@@ -6,7 +6,11 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/pci.h>
#include "avs.h"
+#include "messages.h"
+
+#define CPUID_TSC_LEAF 0x15
static int avs_tgl_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
{
@@ -35,6 +39,34 @@ static int avs_tgl_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stal
return avs_dsp_core_stall(adev, core_mask, stall);
}
+static int avs_tgl_config_basefw(struct avs_dev *adev)
+{
+ struct pci_dev *pci = adev->base.pci;
+ struct avs_bus_hwid hwid;
+ int ret;
+#ifdef CONFIG_X86
+ unsigned int ecx;
+
+#include <asm/cpuid.h>
+ ecx = cpuid_ecx(CPUID_TSC_LEAF);
+ if (ecx) {
+ ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx);
+ if (ret)
+ return AVS_IPC_RET(ret);
+ }
+#endif
+
+ hwid.device = pci->device;
+ hwid.subsystem = pci->subsystem_vendor | (pci->subsystem_device << 16);
+ hwid.revision = pci->revision;
+
+ ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_BUS_HARDWARE_ID, sizeof(hwid), &hwid);
+ if (ret)
+ return AVS_IPC_RET(ret);
+
+ return 0;
+}
+
const struct avs_dsp_ops avs_tgl_dsp_ops = {
.power = avs_tgl_dsp_core_power,
.reset = avs_tgl_dsp_core_reset,
@@ -44,6 +76,7 @@ const struct avs_dsp_ops avs_tgl_dsp_ops = {
.load_basefw = avs_icl_load_basefw,
.load_lib = avs_hda_load_library,
.transfer_mods = avs_hda_transfer_modules,
+ .config_basefw = avs_tgl_config_basefw,
.log_buffer_offset = avs_icl_log_buffer_offset,
.log_buffer_status = avs_apl_log_buffer_status,
.coredump = avs_apl_coredump,
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index d612f20ed989..3c222c352701 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -815,6 +815,66 @@ static const struct avs_tplg_token_parser modcfg_ext_parsers[] = {
.offset = offsetof(struct avs_tplg_modcfg_ext, generic.num_output_pins),
.parse = avs_parse_short_token,
},
+ {
+ .token = AVS_TKN_MODCFG_WHM_REF_AFMT_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.ref_fmt),
+ .parse = avs_parse_audio_format_ptr,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_OUT_AFMT_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.out_fmt),
+ .parse = avs_parse_audio_format_ptr,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_WAKE_TICK_PERIOD_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.wake_tick_period),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_VINDEX_U8,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.vindex),
+ .parse = avs_parse_byte_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_DMA_TYPE_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.dma_type),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_DMABUFF_SIZE_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.dma_buffer_size),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_BLOB_AFMT_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.blob_fmt),
+ .parse = avs_parse_audio_format_ptr,
+ },
+ {
+ .token = AVS_TKN_MODCFG_PEAKVOL_VOLUME_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.target_volume),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_PEAKVOL_CURVE_TYPE_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.curve_type),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_PEAKVOL_CURVE_DURATION_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.curve_duration),
+ .parse = avs_parse_word_token,
+ },
};
static const struct avs_tplg_token_parser pin_format_parsers[] = {
@@ -1845,13 +1905,23 @@ static int avs_manifest(struct snd_soc_component *comp, int index,
return 0;
}
-#define AVS_CONTROL_OPS_VOLUME 257
+enum {
+ AVS_CONTROL_OPS_VOLUME = 257,
+ AVS_CONTROL_OPS_MUTE,
+};
static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = {
{
.id = AVS_CONTROL_OPS_VOLUME,
.get = avs_control_volume_get,
.put = avs_control_volume_put,
+ .info = avs_control_volume_info,
+ },
+ {
+ .id = AVS_CONTROL_OPS_MUTE,
+ .get = avs_control_mute_get,
+ .put = avs_control_mute_put,
+ .info = avs_control_mute_info,
},
};
@@ -1873,18 +1943,20 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_
struct avs_control_data *ctl_data;
struct soc_mixer_control *mc;
size_t block_size;
- int ret;
+ int ret, i;
switch (le32_to_cpu(hdr->type)) {
case SND_SOC_TPLG_TYPE_MIXER:
- tmc = container_of(hdr, typeof(*tmc), hdr);
- tuples = tmc->priv.array;
- block_size = le32_to_cpu(tmc->priv.size);
break;
default:
return -EINVAL;
}
+ mc = (struct soc_mixer_control *)ctmpl->private_value;
+ tmc = container_of(hdr, typeof(*tmc), hdr);
+ tuples = tmc->priv.array;
+ block_size = le32_to_cpu(tmc->priv.size);
+
ctl_data = devm_kzalloc(comp->card->dev, sizeof(*ctl_data), GFP_KERNEL);
if (!ctl_data)
return -ENOMEM;
@@ -1895,8 +1967,13 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_
if (ret)
return ret;
- mc = (struct soc_mixer_control *)ctmpl->private_value;
mc->dobj.private = ctl_data;
+ if (tmc->invert) {
+ ctl_data->values[0] = mc->max;
+ for (i = 1; i < mc->num_channels; i++)
+ ctl_data->values[i] = mc->max;
+ }
+
return 0;
}
diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h
index 7892e3797f63..304880997717 100644
--- a/sound/soc/intel/avs/topology.h
+++ b/sound/soc/intel/avs/topology.h
@@ -74,10 +74,17 @@ struct avs_tplg_modcfg_ext {
union avs_virtual_index vindex;
u32 dma_type;
u32 dma_buffer_size;
- u32 config_length;
- /* config_data part of priv data */
} copier;
struct {
+ struct avs_audio_format *ref_fmt;
+ struct avs_audio_format *out_fmt;
+ u32 wake_tick_period;
+ union avs_virtual_index vindex;
+ u32 dma_type;
+ u32 dma_buffer_size;
+ struct avs_audio_format *blob_fmt; /* optional override */
+ } whm;
+ struct {
u32 out_channel_config;
u32 coefficients_select;
s32 coefficients[AVS_CHANNELS_MAX];
@@ -106,6 +113,11 @@ struct avs_tplg_modcfg_ext {
struct {
struct avs_audio_format *out_fmt;
} micsel;
+ struct {
+ u32 target_volume;
+ u32 curve_type;
+ u32 curve_duration;
+ } peakvol;
};
};