aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt27
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.yaml67
-rw-r--r--sound/soc/intel/boards/Kconfig1
-rw-r--r--sound/soc/intel/boards/Makefile1
-rw-r--r--sound/soc/intel/boards/bridge_cs35l56.c137
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.h1
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c50
-rw-r--r--sound/soc/intel/boards/sof_sdw.c106
-rw-r--r--sound/soc/intel/boards/sof_sdw_common.h27
-rw-r--r--sound/soc/intel/boards/sof_sdw_cs42l43.c14
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-lnl-match.c52
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c83
-rw-r--r--sound/soc/sof/debug.c23
-rw-r--r--sound/soc/sof/intel/hda.c158
-rw-r--r--sound/soc/sof/ipc4-topology.c50
-rw-r--r--sound/soc/sof/topology.c7
-rw-r--r--sound/soc/sunxi/sun50i-dmic.c34
17 files changed, 660 insertions, 178 deletions
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt
deleted file mode 100644
index 38caa936f6f8..000000000000
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-NVIDIA Tegra30 I2S controller
-
-Required properties:
-- compatible : For Tegra30, must contain "nvidia,tegra30-i2s". For Tegra124,
- must contain "nvidia,tegra124-i2s". Otherwise, must contain
- "nvidia,<chip>-i2s" plus at least one of the above, where <chip> is
- tegra114 or tegra132.
-- reg : Should contain I2S registers location and length
-- clocks : Must contain one entry, for the module clock.
- See ../clocks/clock-bindings.txt for details.
-- resets : Must contain an entry for each entry in reset-names.
- See ../reset/reset.txt for details.
-- reset-names : Must include the following entries:
- - i2s
-- nvidia,ahub-cif-ids : The list of AHUB CIF IDs for this port, rx (playback)
- first, tx (capture) second. See nvidia,tegra30-ahub.txt for values.
-
-Example:
-
-i2s@70080300 {
- compatible = "nvidia,tegra30-i2s";
- reg = <0x70080300 0x100>;
- nvidia,ahub-cif-ids = <4 4>;
- clocks = <&tegra_car 11>;
- resets = <&tegra_car 11>;
- reset-names = "i2s";
-};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.yaml
new file mode 100644
index 000000000000..89c3c6414ab1
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra30-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra30 I2S controller
+
+maintainers:
+ - Thierry Reding <[email protected]>
+ - Jon Hunter <[email protected]>
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - nvidia,tegra124-i2s
+ - nvidia,tegra30-i2s
+ - items:
+ - const: nvidia,tegra114-i2s
+ - const: nvidia,tegra30-i2s
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: i2s
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ const: i2s
+
+ nvidia,ahub-cif-ids:
+ description: list of AHUB CIF IDs
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ items:
+ - description: rx (playback)
+ - description: tx (capture)
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+ - reset-names
+ - nvidia,ahub-cif-ids
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/tegra30-car.h>
+
+ i2s@70080300 {
+ compatible = "nvidia,tegra30-i2s";
+ reg = <0x70080300 0x100>;
+ nvidia,ahub-cif-ids = <4 4>;
+ clocks = <&tegra_car TEGRA30_CLK_I2S0>;
+ resets = <&tegra_car 30>;
+ reset-names = "i2s";
+ };
+...
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index 0ad7b0a1e237..b122b8aedd9a 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -690,6 +690,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
select SND_SOC_CS42L43_SDW
select MFD_CS42L43
select MFD_CS42L43_SDW
+ select SND_SOC_CS35L56_SPI
select SND_SOC_CS35L56_SDW
select SND_SOC_DMIC
select SND_SOC_INTEL_HDA_DSP_COMMON
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 119413c262de..1c099e717eca 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -37,6 +37,7 @@ snd-soc-ehl-rt5660-objs := ehl_rt5660.o
snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
snd-soc-sof-sdw-objs += sof_sdw.o \
sof_sdw_maxim.o sof_sdw_rt_amp.o \
+ bridge_cs35l56.o \
sof_sdw_rt5682.o sof_sdw_rt700.o \
sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \
sof_sdw_rt712_sdca.o sof_sdw_rt722_sdca.o \
diff --git a/sound/soc/intel/boards/bridge_cs35l56.c b/sound/soc/intel/boards/bridge_cs35l56.c
new file mode 100644
index 000000000000..c3995e724aed
--- /dev/null
+++ b/sound/soc/intel/boards/bridge_cs35l56.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Intel SOF Machine Driver with Cirrus Logic CS35L56 Smart Amp
+
+#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>
+#include <sound/soc-acpi.h>
+#include "sof_sdw_common.h"
+
+static const struct snd_soc_dapm_widget bridge_widgets[] = {
+ SND_SOC_DAPM_SPK("Bridge Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route bridge_map[] = {
+ {"Bridge Speaker", NULL, "AMPL SPK"},
+ {"Bridge Speaker", NULL, "AMPR SPK"},
+};
+
+static const char * const bridge_cs35l56_name_prefixes[] = {
+ "AMPL",
+ "AMPR",
+};
+
+static int bridge_cs35l56_asp_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ int i, ret;
+ unsigned int rx_mask = 3; // ASP RX1, RX2
+ unsigned int tx_mask = 3; // ASP TX1, TX2
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai *cpu_dai;
+
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s spk:cs35l56-bridge",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+
+ ret = snd_soc_dapm_new_controls(&card->dapm, bridge_widgets,
+ ARRAY_SIZE(bridge_widgets));
+ if (ret) {
+ dev_err(card->dev, "widgets addition failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dapm_add_routes(&card->dapm, bridge_map, ARRAY_SIZE(bridge_map));
+ if (ret) {
+ dev_err(card->dev, "map addition failed: %d\n", ret);
+ return ret;
+ }
+
+ /* 4 x 16-bit sample slots and FSYNC=48000, BCLK=3.072 MHz */
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, rx_mask, 4, 16);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 3072000, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+ }
+
+ for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, 4, 16);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_pcm_stream bridge_params = {
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+SND_SOC_DAILINK_DEFS(bridge_dai,
+ DAILINK_COMP_ARRAY(COMP_CODEC("cs42l43-codec", "cs42l43-asp")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("spi-cs35l56-left", "cs35l56-asp1"),
+ COMP_CODEC("spi-cs35l56-right", "cs35l56-asp1")),
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("cs42l43-codec")));
+
+static const struct snd_soc_dai_link bridge_dai_template = {
+ .name = "cs42l43-cs35l56",
+ .init = bridge_cs35l56_asp_init,
+ .c2c_params = &bridge_params,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBC_CFC,
+ SND_SOC_DAILINK_REG(bridge_dai),
+};
+
+int bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
+ int *num_dais, int *num_devs)
+{
+ if (sof_sdw_quirk & SOF_SIDECAR_AMPS) {
+ (*num_dais)++;
+ (*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
+ }
+
+ return 0;
+}
+
+int bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links,
+ struct snd_soc_codec_conf **codec_conf)
+{
+ if (sof_sdw_quirk & SOF_SIDECAR_AMPS) {
+ **dai_links = bridge_dai_template;
+
+ for (int i = 0; i < ARRAY_SIZE(bridge_cs35l56_name_prefixes); i++) {
+ (*codec_conf)->dlc.name = (*dai_links)->codecs[i].name;
+ (*codec_conf)->name_prefix = bridge_cs35l56_name_prefixes[i];
+ (*codec_conf)++;
+ }
+
+ (*dai_links)++;
+ }
+
+ return 0;
+}
+
+int bridge_cs35l56_spk_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct sof_sdw_codec_info *info,
+ bool playback)
+{
+ if (sof_sdw_quirk & SOF_SIDECAR_AMPS)
+ info->amp_num += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
+
+ return 0;
+}
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h
index 4b0b3959182e..19b814dee4ad 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_common.h
+++ b/sound/soc/intel/boards/skl_hda_dsp_common.h
@@ -28,6 +28,7 @@ struct skl_hda_hdmi_pcm {
};
struct skl_hda_private {
+ struct snd_soc_card card;
struct list_head hdmi_pcm_list;
int pcm_count;
int dai_index;
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index 4aa7fd2a05e4..88d91c0280bb 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -92,19 +92,6 @@ skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link)
return ret;
}
-static struct snd_soc_card hda_soc_card = {
- .name = "hda-dsp",
- .owner = THIS_MODULE,
- .dai_link = skl_hda_be_dai_links,
- .dapm_widgets = skl_hda_widgets,
- .dapm_routes = skl_hda_map,
- .add_dai_link = skl_hda_add_dai_link,
- .fully_routed = true,
- .late_probe = skl_hda_card_late_probe,
-};
-
-static char hda_soc_components[30];
-
#define IDISP_DAI_COUNT 3
#define HDAC_DAI_COUNT 2
#define DMIC_DAI_COUNT 2
@@ -115,9 +102,9 @@ static char hda_soc_components[30];
#define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000
-static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
+static int skl_hda_fill_card_info(struct snd_soc_card *card,
+ struct snd_soc_acpi_mach_params *mach_params)
{
- struct snd_soc_card *card = &hda_soc_card;
struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_dai_link *dai_link;
u32 codec_count, codec_mask;
@@ -199,6 +186,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
{
struct snd_soc_acpi_mach *mach;
struct skl_hda_private *ctx;
+ struct snd_soc_card *card;
int ret;
dev_dbg(&pdev->dev, "entry\n");
@@ -213,32 +201,44 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
if (!mach)
return -EINVAL;
- snd_soc_card_set_drvdata(&hda_soc_card, ctx);
+ card = &ctx->card;
+ card->name = "hda-dsp",
+ card->owner = THIS_MODULE,
+ card->dai_link = skl_hda_be_dai_links,
+ card->dapm_widgets = skl_hda_widgets,
+ card->dapm_routes = skl_hda_map,
+ card->add_dai_link = skl_hda_add_dai_link,
+ card->fully_routed = true,
+ card->late_probe = skl_hda_card_late_probe,
+
+ snd_soc_card_set_drvdata(card, ctx);
- ret = skl_hda_fill_card_info(&mach->mach_params);
+ ret = skl_hda_fill_card_info(card, &mach->mach_params);
if (ret < 0) {
dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n");
return ret;
}
- ctx->pcm_count = hda_soc_card.num_links;
+ ctx->pcm_count = card->num_links;
ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */
ctx->platform_name = mach->mach_params.platform;
ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
- hda_soc_card.dev = &pdev->dev;
+ card->dev = &pdev->dev;
if (!snd_soc_acpi_sof_parent(&pdev->dev))
- hda_soc_card.disable_route_checks = true;
+ card->disable_route_checks = true;
if (mach->mach_params.dmic_num > 0) {
- snprintf(hda_soc_components, sizeof(hda_soc_components),
- "cfg-dmics:%d", mach->mach_params.dmic_num);
- hda_soc_card.components = hda_soc_components;
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "cfg-dmics:%d",
+ mach->mach_params.dmic_num);
+ if (!card->components)
+ return -ENOMEM;
}
- ret = devm_snd_soc_register_card(&pdev->dev, &hda_soc_card);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
if (!ret)
- skl_set_hda_codec_autosuspend_delay(&hda_soc_card);
+ skl_set_hda_codec_autosuspend_delay(card);
return ret;
}
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index d65c5da49000..b1595fdb500d 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -39,6 +39,8 @@ static void log_quirks(struct device *dev)
dev_err(dev, "quirk SOF_SDW_NO_AGGREGATION enabled but no longer supported\n");
if (sof_sdw_quirk & SOF_CODEC_SPKR)
dev_dbg(dev, "quirk SOF_CODEC_SPKR enabled\n");
+ if (sof_sdw_quirk & SOF_SIDECAR_AMPS)
+ dev_dbg(dev, "quirk SOF_SIDECAR_AMPS enabled\n");
}
static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
@@ -421,8 +423,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
- RT711_JD2 |
- SOF_SDW_FOUR_SPK),
+ RT711_JD2),
},
{
.callback = sof_sdw_quirk_cb,
@@ -996,6 +997,8 @@ static struct sof_sdw_codec_info codec_info_list[] = {
{
.part_id = 0x4243,
.codec_name = "cs42l43-codec",
+ .count_sidecar = bridge_cs35l56_count_sidecar,
+ .add_sidecar = bridge_cs35l56_add_sidecar,
.dais = {
{
.direction = {true, false},
@@ -1024,7 +1027,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
.init = sof_sdw_cs42l43_spk_init,
.rtd_init = cs42l43_spk_rtd_init,
- .quirk = SOF_CODEC_SPKR,
+ .quirk = SOF_CODEC_SPKR | SOF_SIDECAR_AMPS,
},
},
.dai_num = 4,
@@ -1280,6 +1283,8 @@ struct sof_sdw_endpoint {
u32 link_mask;
const char *codec_name;
+ const char *name_prefix;
+ bool include_sidecar;
struct sof_sdw_codec_info *codec_info;
const struct sof_sdw_dai_info *dai_info;
@@ -1335,17 +1340,18 @@ static struct sof_sdw_dailink *find_dailink(struct sof_sdw_dailink *dailinks,
static int parse_sdw_endpoints(struct snd_soc_card *card,
struct sof_sdw_dailink *sof_dais,
- struct sof_sdw_endpoint *sof_ends)
+ struct sof_sdw_endpoint *sof_ends,
+ int *num_devs)
{
struct device *dev = card->dev;
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
- struct snd_soc_codec_conf *codec_conf = card->codec_conf;
const struct snd_soc_acpi_link_adr *adr_link;
struct sof_sdw_endpoint *sof_end = sof_ends;
int num_dais = 0;
int i, j;
+ int ret;
for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
int num_link_dailinks = 0;
@@ -1377,13 +1383,19 @@ static int parse_sdw_endpoints(struct snd_soc_card *card,
if (!codec_name)
return -ENOMEM;
- codec_conf->dlc.name = codec_name;
- codec_conf->name_prefix = adr_dev->name_prefix;
- codec_conf++;
-
dev_dbg(dev, "Adding prefix %s for %s\n",
adr_dev->name_prefix, codec_name);
+ sof_end->name_prefix = adr_dev->name_prefix;
+
+ if (codec_info->count_sidecar && codec_info->add_sidecar) {
+ ret = codec_info->count_sidecar(card, &num_dais, num_devs);
+ if (ret)
+ return ret;
+
+ sof_end->include_sidecar = true;
+ }
+
for (j = 0; j < adr_dev->num_endpoints; j++) {
const struct snd_soc_acpi_endpoint *adr_end;
const struct sof_sdw_dai_info *dai_info;
@@ -1444,20 +1456,33 @@ static int parse_sdw_endpoints(struct snd_soc_card *card,
ctx->append_dai_type |= (num_link_dailinks > 1);
}
- WARN_ON(codec_conf != card->codec_conf + card->num_configs);
-
return num_dais;
}
static int create_sdw_dailink(struct snd_soc_card *card,
struct sof_sdw_dailink *sof_dai,
struct snd_soc_dai_link **dai_links,
- int *be_id)
+ int *be_id, struct snd_soc_codec_conf **codec_conf)
{
struct device *dev = card->dev;
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
struct sof_sdw_endpoint *sof_end;
int stream;
+ int ret;
+
+ list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
+ if (sof_end->name_prefix) {
+ (*codec_conf)->dlc.name = sof_end->codec_name;
+ (*codec_conf)->name_prefix = sof_end->name_prefix;
+ (*codec_conf)++;
+ }
+
+ if (sof_end->include_sidecar) {
+ ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf);
+ if (ret)
+ return ret;
+ }
+ }
for_each_pcm_streams(stream) {
static const char * const sdw_stream_name[] = {
@@ -1570,7 +1595,8 @@ static int create_sdw_dailink(struct snd_soc_card *card,
static int create_sdw_dailinks(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links, int *be_id,
- struct sof_sdw_dailink *sof_dais)
+ struct sof_sdw_dailink *sof_dais,
+ struct snd_soc_codec_conf **codec_conf)
{
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
int ret, i;
@@ -1582,7 +1608,8 @@ static int create_sdw_dailinks(struct snd_soc_card *card,
while (sof_dais->initialised) {
int current_be_id;
- ret = create_sdw_dailink(card, sof_dais, dai_links, &current_be_id);
+ ret = create_sdw_dailink(card, sof_dais, dai_links,
+ &current_be_id, codec_conf);
if (ret)
return ret;
@@ -1752,17 +1779,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
goto err_dai;
}
- /* will be populated when acpi endpoints are parsed */
- codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
- if (!codec_conf) {
- ret = -ENOMEM;
- goto err_end;
- }
-
- card->codec_conf = codec_conf;
- card->num_configs = num_devs;
-
- ret = parse_sdw_endpoints(card, sof_dais, sof_ends);
+ ret = parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs);
if (ret < 0)
goto err_end;
@@ -1799,6 +1816,12 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
sdw_be_num, ssp_num, dmic_num,
ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num);
+ codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
+ if (!codec_conf) {
+ ret = -ENOMEM;
+ goto err_end;
+ }
+
/* allocate BE dailinks */
num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
@@ -1807,12 +1830,15 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
goto err_end;
}
+ card->codec_conf = codec_conf;
+ card->num_configs = num_devs;
card->dai_link = dai_links;
card->num_links = num_links;
/* SDW */
if (sdw_be_num) {
- ret = create_sdw_dailinks(card, &dai_links, &be_id, sof_dais);
+ ret = create_sdw_dailinks(card, &dai_links, &be_id,
+ sof_dais, &codec_conf);
if (ret)
goto err_end;
}
@@ -1848,6 +1874,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
goto err_end;
}
+ WARN_ON(codec_conf != card->codec_conf + card->num_configs);
WARN_ON(dai_links != card->dai_link + card->num_links);
err_end:
@@ -1879,15 +1906,6 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *card)
return ret;
}
-/* SoC card */
-static const char sdw_card_long_name[] = "Intel Soundwire SOF";
-
-static struct snd_soc_card card_sof_sdw = {
- .name = "soundwire",
- .owner = THIS_MODULE,
- .late_probe = sof_sdw_card_late_probe,
-};
-
/* helper to get the link that the codec DAI is used */
static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card,
const char *dai_name)
@@ -1939,20 +1957,24 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card)
static int mc_probe(struct platform_device *pdev)
{
- struct snd_soc_card *card = &card_sof_sdw;
struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
+ struct snd_soc_card *card;
struct mc_private *ctx;
int amp_num = 0, i;
int ret;
- card->dev = &pdev->dev;
-
- dev_dbg(card->dev, "Entry\n");
+ dev_dbg(&pdev->dev, "Entry\n");
- ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
+ card = &ctx->card;
+ card->dev = &pdev->dev;
+ card->name = "soundwire",
+ card->owner = THIS_MODULE,
+ card->late_probe = sof_sdw_card_late_probe,
+
snd_soc_card_set_drvdata(card, ctx);
dmi_check_system(sof_sdw_quirk_table);
@@ -1988,7 +2010,7 @@ static int mc_probe(struct platform_device *pdev)
amp_num += codec_info_list[i].amp_num;
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "cfg-amp:%d", amp_num);
+ " cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
@@ -2001,8 +2023,6 @@ static int mc_probe(struct platform_device *pdev)
return -ENOMEM;
}
- card->long_name = sdw_card_long_name;
-
/* Register the card */
ret = devm_snd_soc_register_card(card->dev, card);
if (ret) {
diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h
index 89253938ebaa..94657dd210f5 100644
--- a/sound/soc/intel/boards/sof_sdw_common.h
+++ b/sound/soc/intel/boards/sof_sdw_common.h
@@ -55,6 +55,16 @@ enum {
#define SOF_SDW_NO_AGGREGATION BIT(14)
/* If a CODEC has an optional speaker output, this quirk will enable it */
#define SOF_CODEC_SPKR BIT(15)
+/*
+ * If the CODEC has additional devices attached directly to it.
+ *
+ * For the cs42l43:
+ * - 0 - No speaker output
+ * - SOF_CODEC_SPKR - CODEC internal speaker
+ * - SOF_SIDECAR_AMPS - 2x Sidecar amplifiers + CODEC internal speaker
+ * - SOF_CODEC_SPKR | SOF_SIDECAR_AMPS - Not currently supported
+ */
+#define SOF_SIDECAR_AMPS BIT(16)
/* BT audio offload: reserve 3 bits for future */
#define SOF_BT_OFFLOAD_SSP_SHIFT 15
@@ -98,9 +108,16 @@ struct sof_sdw_codec_info {
const int dai_num;
int (*codec_card_late_probe)(struct snd_soc_card *card);
+
+ int (*count_sidecar)(struct snd_soc_card *card,
+ int *num_dais, int *num_devs);
+ int (*add_sidecar)(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links,
+ struct snd_soc_codec_conf **codec_conf);
};
struct mc_private {
+ struct snd_soc_card card;
struct snd_soc_jack sdw_headset;
struct sof_hdmi_private hdmi;
struct device *headset_codec_dev; /* only one headset per card */
@@ -170,6 +187,16 @@ int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card,
bool playback);
/* CS AMP support */
+int bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
+ int *num_dais, int *num_devs);
+int bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
+ struct snd_soc_dai_link **dai_links,
+ struct snd_soc_codec_conf **codec_conf);
+int bridge_cs35l56_spk_init(struct snd_soc_card *card,
+ struct snd_soc_dai_link *dai_links,
+ struct sof_sdw_codec_info *info,
+ bool playback);
+
int sof_sdw_cs_amp_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct sof_sdw_codec_info *info,
diff --git a/sound/soc/intel/boards/sof_sdw_cs42l43.c b/sound/soc/intel/boards/sof_sdw_cs42l43.c
index 5361249f0f53..0fd5e099bb1a 100644
--- a/sound/soc/intel/boards/sof_sdw_cs42l43.c
+++ b/sound/soc/intel/boards/sof_sdw_cs42l43.c
@@ -124,10 +124,14 @@ int cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_card *card = rtd->card;
int ret;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:cs42l43-spk",
- card->components);
- if (!card->components)
- return -ENOMEM;
+ if (!(sof_sdw_quirk & SOF_SIDECAR_AMPS)) {
+ /* Will be set by the bridge code in this case */
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s spk:cs42l43-spk",
+ card->components);
+ if (!card->components)
+ return -ENOMEM;
+ }
ret = snd_soc_dapm_new_controls(&card->dapm, cs42l43_spk_widgets,
ARRAY_SIZE(cs42l43_spk_widgets));
@@ -155,7 +159,7 @@ int sof_sdw_cs42l43_spk_init(struct snd_soc_card *card,
info->amp_num++;
- return 0;
+ return bridge_cs35l56_spk_init(card, dai_links, info, playback);
}
int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd)
diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
index 74d6dcd7471f..0318c1a46f3c 100644
--- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
@@ -130,6 +130,33 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
+ {
+ .adr = 0x000130025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1318-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = {
+ {
+ .adr = 0x000232025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1318-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
+ {
+ .adr = 0x000030025D071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt714_1_adr[] = {
{
.adr = 0x000130025D071401ull,
@@ -195,6 +222,25 @@ static const struct snd_soc_acpi_link_adr lnl_3_in_1_sdca[] = {
{}
};
+static const struct snd_soc_acpi_link_adr lnl_sdw_rt1318_l12_rt714_l0[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+ .adr_d = rt1318_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+ .adr_d = rt1318_2_group1_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt714_0_adr),
+ .adr_d = rt714_0_adr,
+ },
+ {}
+};
+
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
/* mockup tests need to be first */
@@ -240,6 +286,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-rt722-l0.tplg",
},
+ {
+ .link_mask = GENMASK(2, 0),
+ .links = lnl_sdw_rt1318_l12_rt714_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg"
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_sdw_machines);
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 f95490a16b55..4eeec0bc92dc 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -312,6 +312,15 @@ static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1318_1_single_adr[] = {
+ {
+ .adr = 0x000130025D131801,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt1318"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
{
.adr = 0x000130025D131801ull,
@@ -348,7 +357,7 @@ static const struct snd_soc_acpi_adr_device rt714_1_adr[] = {
}
};
-static const struct snd_soc_acpi_link_adr mtl_712_only[] = {
+static const struct snd_soc_acpi_link_adr mtl_712_l0_1712_l3[] = {
{
.mask = BIT(0),
.num_adr = ARRAY_SIZE(rt712_0_single_adr),
@@ -362,6 +371,15 @@ static const struct snd_soc_acpi_link_adr mtl_712_only[] = {
{}
};
+static const struct snd_soc_acpi_link_adr mtl_712_l0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt712_0_single_adr),
+ .adr_d = rt712_0_single_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
{ /* Jack Playback Endpoint */
.num = 0,
@@ -559,6 +577,49 @@ static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12_rt1713_l3[] =
{}
};
+static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1318_l1_rt1713_l3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt713_0_single_adr),
+ .adr_d = rt713_0_single_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_single_adr),
+ .adr_d = rt1318_1_single_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1713_3_single_adr),
+ .adr_d = rt1713_3_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1318_l12_rt1713_l3[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt713_0_single_adr),
+ .adr_d = rt713_0_single_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+ .adr_d = rt1318_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+ .adr_d = rt1318_2_group1_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1713_3_single_adr),
+ .adr_d = rt1713_3_single_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12[] = {
{
.mask = BIT(0),
@@ -698,6 +759,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12-rt1713-l3.tplg",
},
{
+ .link_mask = GENMASK(3, 0),
+ .links = mtl_rt713_l0_rt1318_l12_rt1713_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l12-rt1713-l3.tplg",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1) | BIT(3),
+ .links = mtl_rt713_l0_rt1318_l1_rt1713_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l1-rt1713-l3.tplg",
+ },
+ {
.link_mask = GENMASK(2, 0),
.links = mtl_rt713_l0_rt1316_l12,
.drv_name = "sof_sdw",
@@ -705,11 +778,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
},
{
.link_mask = BIT(3) | BIT(0),
- .links = mtl_712_only,
+ .links = mtl_712_l0_1712_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg",
},
{
+ .link_mask = BIT(0),
+ .links = mtl_712_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt712-l0.tplg",
+ },
+ {
.link_mask = GENMASK(2, 0),
.links = mtl_sdw_rt1318_l12_rt714_l0,
.drv_name = "sof_sdw",
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index 884d85770426..a620d1bcd49d 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -326,8 +326,27 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
debugfs_create_str("fw_path", 0444, fw_profile,
(char **)&plat_data->fw_filename_prefix);
- debugfs_create_str("fw_lib_path", 0444, fw_profile,
- (char **)&plat_data->fw_lib_prefix);
+ /* library path is not valid for IPC3 */
+ if (plat_data->ipc_type != SOF_IPC_TYPE_3) {
+ /*
+ * fw_lib_prefix can be NULL if the vendor/platform does not
+ * support loadable libraries
+ */
+ if (plat_data->fw_lib_prefix) {
+ debugfs_create_str("fw_lib_path", 0444, fw_profile,
+ (char **)&plat_data->fw_lib_prefix);
+ } else {
+ static char *fw_lib_path;
+
+ fw_lib_path = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "Not supported");
+ if (!fw_lib_path)
+ return -ENOMEM;
+
+ debugfs_create_str("fw_lib_path", 0444, fw_profile,
+ (char **)&fw_lib_path);
+ }
+ }
debugfs_create_str("tplg_path", 0444, fw_profile,
(char **)&plat_data->tplg_filename_prefix);
debugfs_create_str("fw_name", 0444, fw_profile,
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 2fc10bec7331..d509cfa38a64 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1645,6 +1645,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 snd_soc_acpi_mach *mach;
struct sof_intel_hda_dev *hdev;
u32 link_mask;
@@ -1653,92 +1654,109 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
hdev = pdata->hw_pdata;
link_mask = hdev->info.link_mask;
+ if (!link_mask) {
+ dev_info(sdev->dev, "SoundWire links not enabled\n");
+ return NULL;
+ }
+
+ if (!hdev->sdw) {
+ dev_dbg(sdev->dev, "SoundWire context not allocated\n");
+ return NULL;
+ }
+
+ if (!hdev->sdw->num_slaves) {
+ dev_warn(sdev->dev, "No SoundWire peripheral detected in ACPI tables\n");
+ return NULL;
+ }
+
/*
* Select SoundWire machine driver if needed using the
* alternate tables. This case deals with SoundWire-only
* machines, for mixed cases with I2C/I2S the detection relies
* on the HID list.
*/
- if (link_mask) {
- for (mach = pdata->desc->alt_machines;
- mach && mach->link_mask; mach++) {
- /*
- * On some platforms such as Up Extreme all links
- * are enabled but only one link can be used by
- * external codec. Instead of exact match of two masks,
- * first check whether link_mask of mach is subset of
- * link_mask supported by hw and then go on searching
- * link_adr
- */
- if (~link_mask & mach->link_mask)
- continue;
-
- /* No need to match adr if there is no links defined */
- if (!mach->links)
- break;
-
- link = mach->links;
- for (i = 0; i < hdev->info.count && link->num_adr;
- i++, link++) {
- /*
- * Try next machine if any expected Slaves
- * are not found on this link.
- */
- if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
- hdev->sdw->ids,
- hdev->sdw->num_slaves))
- break;
- }
- /* Found if all Slaves are checked */
- if (i == hdev->info.count || !link->num_adr)
- break;
- }
- if (mach && mach->link_mask) {
- int dmic_num = 0;
- bool tplg_fixup;
- const char *tplg_filename;
-
- mach->mach_params.links = mach->links;
- mach->mach_params.link_mask = mach->link_mask;
- mach->mach_params.platform = dev_name(sdev->dev);
+ for (mach = pdata->desc->alt_machines;
+ mach && mach->link_mask; mach++) {
+ /*
+ * On some platforms such as Up Extreme all links
+ * are enabled but only one link can be used by
+ * external codec. Instead of exact match of two masks,
+ * first check whether link_mask of mach is subset of
+ * link_mask supported by hw and then go on searching
+ * link_adr
+ */
+ if (~link_mask & mach->link_mask)
+ continue;
- if (pdata->tplg_filename) {
- tplg_fixup = false;
- } else {
- tplg_fixup = true;
- tplg_filename = mach->sof_tplg_filename;
- }
+ /* No need to match adr if there is no links defined */
+ if (!mach->links)
+ break;
+ link = mach->links;
+ for (i = 0; i < hdev->info.count && link->num_adr;
+ i++, link++) {
/*
- * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
- * link 2 and 3, or link 1 and 2, thus we only try to enable dmics
- * if all conditions are true:
- * a) 2 or fewer links are used by SoundWire
- * b) the NHLT table reports the presence of microphones
+ * Try next machine if any expected Slaves
+ * are not found on this link.
*/
- if (hweight_long(mach->link_mask) <= 2) {
- int ret;
-
- ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "",
- &dmic_num, tplg_fixup);
- if (ret < 0)
- return NULL;
- }
- if (tplg_fixup)
- pdata->tplg_filename = tplg_filename;
- mach->mach_params.dmic_num = dmic_num;
+ if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
+ hdev->sdw->ids,
+ hdev->sdw->num_slaves))
+ break;
+ }
+ /* Found if all Slaves are checked */
+ if (i == hdev->info.count || !link->num_adr)
+ break;
+ }
+ if (mach && mach->link_mask) {
+ int dmic_num = 0;
+ bool tplg_fixup;
+ const char *tplg_filename;
+
+ mach->mach_params.links = mach->links;
+ mach->mach_params.link_mask = mach->link_mask;
+ mach->mach_params.platform = dev_name(sdev->dev);
+
+ if (pdata->tplg_filename) {
+ tplg_fixup = false;
+ } else {
+ tplg_fixup = true;
+ tplg_filename = mach->sof_tplg_filename;
+ }
- dev_dbg(sdev->dev,
- "SoundWire machine driver %s topology %s\n",
- mach->drv_name,
- pdata->tplg_filename);
+ /*
+ * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
+ * link 2 and 3, or link 1 and 2, thus we only try to enable dmics
+ * if all conditions are true:
+ * a) 2 or fewer links are used by SoundWire
+ * b) the NHLT table reports the presence of microphones
+ */
+ if (hweight_long(mach->link_mask) <= 2) {
+ int ret;
- return mach;
+ ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "",
+ &dmic_num, tplg_fixup);
+ if (ret < 0)
+ return NULL;
}
+ if (tplg_fixup)
+ pdata->tplg_filename = tplg_filename;
+ mach->mach_params.dmic_num = dmic_num;
- dev_info(sdev->dev, "No SoundWire machine driver found\n");
+ dev_dbg(sdev->dev,
+ "SoundWire machine driver %s topology %s\n",
+ mach->drv_name,
+ pdata->tplg_filename);
+
+ return mach;
}
+ 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++)
+ 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);
+
return NULL;
}
#else
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index c29c1de4e925..a972b2b5122a 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -407,6 +407,52 @@ static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swi
}
}
+static int
+sof_ipc4_update_card_components_string(struct snd_sof_widget *swidget,
+ struct snd_sof_pcm *spcm, int dir)
+{
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+ struct snd_soc_component *scomp = spcm->scomp;
+ struct snd_soc_card *card = scomp->card;
+ const char *pt_marker = "iec61937-pcm";
+
+ /*
+ * Update the card's components list with iec61937-pcm and a list of PCM
+ * ids where ChainDMA is enabled.
+ * These PCMs can be used for bytestream passthrough.
+ */
+ if (!pipeline->use_chain_dma)
+ return 0;
+
+ if (card->components) {
+ const char *tmp = card->components;
+
+ if (strstr(card->components, pt_marker))
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s,%d",
+ card->components,
+ spcm->pcm.pcm_id);
+ else
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s %s:%d",
+ card->components,
+ pt_marker,
+ spcm->pcm.pcm_id);
+
+ devm_kfree(card->dev, tmp);
+ } else {
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s:%d", pt_marker,
+ spcm->pcm.pcm_id);
+ }
+
+ if (!card->components)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
{
struct sof_ipc4_available_audio_format *available_fmt;
@@ -452,6 +498,10 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
if (!spcm)
goto skip_gtw_cfg;
+ ret = sof_ipc4_update_card_components_string(swidget, spcm, dir);
+ if (ret)
+ goto free_available_fmt;
+
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
struct snd_sof_pcm_stream *sps = &spcm->stream[dir];
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index bcdb499c96a0..ec931a26b54f 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1531,10 +1531,9 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
/* check token parsing reply */
if (ret < 0) {
dev_err(scomp->dev,
- "error: failed to add widget id %d type %d name : %s stream %s\n",
- tw->shift, swidget->id, tw->name,
- strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
- ? tw->sname : "none");
+ "failed to add widget type %d name : %s stream %s\n",
+ swidget->id, tw->name, strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
+ ? tw->sname : "none");
goto widget_free;
}
diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c
index c76628bc86c6..dd32780fb6a4 100644
--- a/sound/soc/sunxi/sun50i-dmic.c
+++ b/sound/soc/sunxi/sun50i-dmic.c
@@ -14,6 +14,7 @@
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/tlv.h>
#define SUN50I_DMIC_EN_CTL (0x00)
#define SUN50I_DMIC_EN_CTL_GLOBE BIT(8)
@@ -43,6 +44,17 @@
#define SUN50I_DMIC_CH_NUM_N_MASK GENMASK(2, 0)
#define SUN50I_DMIC_CNT (0x2c)
#define SUN50I_DMIC_CNT_N (1 << 0)
+#define SUN50I_DMIC_D0D1_VOL_CTR (0x30)
+ #define SUN50I_DMIC_D0D1_VOL_CTR_0R (0)
+ #define SUN50I_DMIC_D0D1_VOL_CTR_0L (8)
+ #define SUN50I_DMIC_D0D1_VOL_CTR_1R (16)
+ #define SUN50I_DMIC_D0D1_VOL_CTR_1L (24)
+#define SUN50I_DMIC_D2D3_VOL_CTR (0x34)
+ #define SUN50I_DMIC_D2D3_VOL_CTR_2R (0)
+ #define SUN50I_DMIC_D2D3_VOL_CTR_2L (8)
+ #define SUN50I_DMIC_D2D3_VOL_CTR_3R (16)
+ #define SUN50I_DMIC_D2D3_VOL_CTR_3L (24)
+
#define SUN50I_DMIC_HPF_CTRL (0x38)
#define SUN50I_DMIC_VERSION (0x50)
@@ -273,8 +285,30 @@ static const struct of_device_id sun50i_dmic_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sun50i_dmic_of_match);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(sun50i_dmic_vol_scale, -12000, 75, 1);
+
+static const struct snd_kcontrol_new sun50i_dmic_controls[] = {
+
+ SOC_DOUBLE_TLV("DMIC Channel 0 Capture Volume", SUN50I_DMIC_D0D1_VOL_CTR,
+ SUN50I_DMIC_D0D1_VOL_CTR_0L, SUN50I_DMIC_D0D1_VOL_CTR_0R,
+ 0xFF, 0, sun50i_dmic_vol_scale),
+ SOC_DOUBLE_TLV("DMIC Channel 1 Capture Volume", SUN50I_DMIC_D0D1_VOL_CTR,
+ SUN50I_DMIC_D0D1_VOL_CTR_1L, SUN50I_DMIC_D0D1_VOL_CTR_1R,
+ 0xFF, 0, sun50i_dmic_vol_scale),
+ SOC_DOUBLE_TLV("DMIC Channel 2 Capture Volume", SUN50I_DMIC_D2D3_VOL_CTR,
+ SUN50I_DMIC_D2D3_VOL_CTR_2L, SUN50I_DMIC_D2D3_VOL_CTR_2R,
+ 0xFF, 0, sun50i_dmic_vol_scale),
+ SOC_DOUBLE_TLV("DMIC Channel 3 Capture Volume", SUN50I_DMIC_D2D3_VOL_CTR,
+ SUN50I_DMIC_D2D3_VOL_CTR_3L, SUN50I_DMIC_D2D3_VOL_CTR_3R,
+ 0xFF, 0, sun50i_dmic_vol_scale),
+
+
+};
+
static const struct snd_soc_component_driver sun50i_dmic_component = {
.name = "sun50i-dmic",
+ .controls = sun50i_dmic_controls,
+ .num_controls = ARRAY_SIZE(sun50i_dmic_controls),
};
static int sun50i_dmic_runtime_suspend(struct device *dev)