diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ad67957b7b48..bd7842096b69 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -70,6 +70,7 @@ struct simple_util_priv { struct snd_soc_dai_link *dai_link; struct simple_util_dai *dais; struct snd_soc_dai_link_component *dlcs; + struct snd_soc_dai_link_component *dummy_dlc; struct snd_soc_codec_conf *codec_conf; struct gpio_desc *pa_gpio; const struct snd_soc_ops *ops; diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 83e3ba773fbd..04dd82f67096 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -274,12 +274,18 @@ static int graph_dai_link_of(struct simple_util_priv *priv, if (ret < 0) return ret; + if (!codec_ep) { + codecs = priv->dummy_dlc; + dai_link->codecs = priv->dummy_dlc; + } + ret = graph_parse_node(priv, codec_ep, li, NULL); if (ret < 0) return ret; snprintf(dai_name, sizeof(dai_name), - "%s-%s", cpus->dai_name, codecs->dai_name); + "%pOFP.%s-%pOFP.%s", dai_link->cpus->of_node, cpus->dai_name, + dai_link->codecs->of_node, codecs->dai_name); simple_util_canonicalize_cpu(cpus, is_single_links); simple_util_canonicalize_platform(platforms, cpus); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 81077d16d22f..66300ab39264 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -230,6 +230,9 @@ int simple_util_parse_clk(struct device *dev, struct clk *clk; u32 val; + if (!node) + return 0; + /* * Parse dai->sysclk come from "clocks = <&xxx>" * (if system has common clock) diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index fee4022708bc..ce110890b64c 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -64,6 +64,7 @@ int snd_soc_link_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return soc_link_ret(rtd, ret); } +EXPORT_SYMBOL_GPL(snd_soc_link_be_hw_params_fixup); int snd_soc_link_startup(struct snd_pcm_substream *substream) { diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c index 66cdaef6fa66..a8c4af84355c 100644 --- a/sound/soc/tegra/tegra186_asrc.c +++ b/sound/soc/tegra/tegra186_asrc.c @@ -927,6 +927,7 @@ static const struct snd_soc_component_driver tegra186_asrc_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra186_asrc_widgets), .controls = tegra186_asrc_controls, .num_controls = ARRAY_SIZE(tegra186_asrc_controls), + .endianness = 1, }; static bool tegra186_asrc_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c index 88e6e530eea8..99ad0f1efee8 100644 --- a/sound/soc/tegra/tegra186_dspk.c +++ b/sound/soc/tegra/tegra186_dspk.c @@ -446,6 +446,7 @@ static const struct snd_soc_component_driver tegra186_dspk_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra186_dspk_widgets), .controls = tegrat186_dspk_controls, .num_controls = ARRAY_SIZE(tegrat186_dspk_controls), + .endianness = 1, }; static bool tegra186_dspk_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index 45b4f420270b..a2853d12726f 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -440,6 +440,7 @@ static const struct snd_soc_component_driver tegra210_adx_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_adx_widgets), .controls = tegra210_adx_controls, .num_controls = ARRAY_SIZE(tegra210_adx_controls), + .endianness = 1, }; static bool tegra210_adx_wr_reg(struct device *dev, diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index ab3c6b2544d2..80df2fcf774a 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // tegra210_ahub.c - Tegra210 AHUB driver -// -// Copyright (c) 2020-2024, NVIDIA CORPORATION. All rights reserved. #include #include @@ -1243,6 +1242,7 @@ static const struct snd_soc_component_driver tegra210_ahub_component = { .num_dapm_widgets = ARRAY_SIZE(tegra210_ahub_widgets), .dapm_routes = tegra210_ahub_routes, .num_dapm_routes = ARRAY_SIZE(tegra210_ahub_routes), + .endianness = 1, }; static const struct snd_soc_component_driver tegra186_ahub_component = { @@ -1250,6 +1250,7 @@ static const struct snd_soc_component_driver tegra186_ahub_component = { .num_dapm_widgets = ARRAY_SIZE(tegra186_ahub_widgets), .dapm_routes = tegra186_ahub_routes, .num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes), + .endianness = 1, }; static const struct snd_soc_component_driver tegra234_ahub_component = { @@ -1257,6 +1258,7 @@ static const struct snd_soc_component_driver tegra234_ahub_component = { .num_dapm_widgets = ARRAY_SIZE(tegra234_ahub_widgets), .dapm_routes = tegra186_ahub_routes, .num_dapm_routes = ARRAY_SIZE(tegra186_ahub_routes), + .endianness = 1, }; static const struct regmap_config tegra210_ahub_regmap_config = { diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c index b9d338d6a848..a17fe653f099 100644 --- a/sound/soc/tegra/tegra210_amx.c +++ b/sound/soc/tegra/tegra210_amx.c @@ -456,6 +456,7 @@ static const struct snd_soc_component_driver tegra210_amx_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_amx_widgets), .controls = tegra210_amx_controls, .num_controls = ARRAY_SIZE(tegra210_amx_controls), + .endianness = 1, }; static bool tegra210_amx_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c index 3102d06ff410..f869c0e8949b 100644 --- a/sound/soc/tegra/tegra210_dmic.c +++ b/sound/soc/tegra/tegra210_dmic.c @@ -457,6 +457,7 @@ static const struct snd_soc_component_driver tegra210_dmic_compnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_dmic_widgets), .controls = tegra210_dmic_controls, .num_controls = ARRAY_SIZE(tegra210_dmic_controls), + .endianness = 1, }; static bool tegra210_dmic_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index cc6d789ca51c..da16f5e5d717 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -836,6 +836,7 @@ static const struct snd_soc_component_driver tegra210_i2s_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_i2s_widgets), .controls = tegra210_i2s_controls, .num_controls = ARRAY_SIZE(tegra210_i2s_controls), + .endianness = 1, }; static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c index 9d290e36d246..a8188b47cfe4 100644 --- a/sound/soc/tegra/tegra210_mixer.c +++ b/sound/soc/tegra/tegra210_mixer.c @@ -577,6 +577,7 @@ static const struct snd_soc_component_driver tegra210_mixer_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_mixer_widgets), .controls = tegra210_mixer_gain_ctls, .num_controls = ARRAY_SIZE(tegra210_mixer_gain_ctls), + .endianness = 1, }; static bool tegra210_mixer_wr_reg(struct device *dev, diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c index 72fef04fc067..7eaaed957983 100644 --- a/sound/soc/tegra/tegra210_mvc.c +++ b/sound/soc/tegra/tegra210_mvc.c @@ -662,6 +662,7 @@ static const struct snd_soc_component_driver tegra210_mvc_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_mvc_widgets), .controls = tegra210_mvc_vol_ctrl, .num_controls = ARRAY_SIZE(tegra210_mvc_vol_ctrl), + .endianness = 1, }; static bool tegra210_mvc_rd_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c index 91275dc90663..d4caf6b1e71b 100644 --- a/sound/soc/tegra/tegra210_ope.c +++ b/sound/soc/tegra/tegra210_ope.c @@ -253,6 +253,7 @@ static const struct snd_soc_component_driver tegra210_ope_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_ope_widgets), .controls = tegra210_ope_controls, .num_controls = ARRAY_SIZE(tegra210_ope_controls), + .endianness = 1, }; static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c index 7ba824fa210d..febf95b94635 100644 --- a/sound/soc/tegra/tegra210_sfc.c +++ b/sound/soc/tegra/tegra210_sfc.c @@ -3520,6 +3520,7 @@ static const struct snd_soc_component_driver tegra210_sfc_cmpnt = { .num_dapm_widgets = ARRAY_SIZE(tegra210_sfc_widgets), .controls = tegra210_sfc_controls, .num_controls = ARRAY_SIZE(tegra210_sfc_controls), + .endianness = 1, }; static bool tegra210_sfc_wr_reg(struct device *dev, unsigned int reg) diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c index feba9d42bbc5..bc594766a07d 100644 --- a/sound/soc/tegra/tegra_audio_graph_card.c +++ b/sound/soc/tegra/tegra_audio_graph_card.c @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // // tegra_audio_graph_card.c - Audio Graph based Tegra Machine Driver -// -// Copyright (c) 2020-2021 NVIDIA CORPORATION. All rights reserved. #include #include #include +#include #include #include #include #include +#include #define MAX_PLLA_OUT0_DIV 128 @@ -154,6 +155,9 @@ static int tegra_audio_graph_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_pcm_stream *dai_params; + struct snd_soc_pcm_runtime *vrtd; + struct snd_pcm_hw_params codec_params; int err; if (need_clk_update(cpu_dai)) { @@ -162,6 +166,34 @@ static int tegra_audio_graph_hw_params(struct snd_pcm_substream *substream, return err; } + /* + * For AHUB in c2c mode, hw_params() call here happens only for + * FE links. The PLL update is required to take care of I/O + * configuration. + * + */ + if (cpu_dai->driver->ops && !rtd->card->component_chaining) { + for_each_card_rtds(rtd->card, vrtd) { + if (!vrtd->dai_link->c2c_params) + continue; + + codec_params = *params; + snd_soc_link_be_hw_params_fixup(vrtd, &codec_params); + + dai_params = (struct snd_soc_pcm_stream *)vrtd->dai_link->c2c_params; + dai_params->rate_min = params_rate(&codec_params); + dai_params->channels_min = params_channels(&codec_params); + dai_params->formats = 1 << params_format(&codec_params); + + cpu_dai = snd_soc_rtd_to_cpu(vrtd, 0); + if (need_clk_update(cpu_dai)) { + err = tegra_audio_graph_update_pll(substream, &codec_params); + if (err) + return err; + } + } + } + return simple_util_hw_params(substream, params); } @@ -191,11 +223,58 @@ static int tegra_audio_graph_card_probe(struct snd_soc_card *card) return graph_util_card_probe(card); } +static struct snd_soc_dai_driver tegra_dummy_dai = { + .name = "tegra-snd-dummy-dai", + .playback = { + .stream_name = "Dummy Playback", + .channels_min = 1, + .channels_max = 32, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Dummy Capture", + .channels_min = 1, + .channels_max = 32, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}; + +static const struct snd_soc_dapm_widget tegra_dummy_widgets[] = { + SND_SOC_DAPM_MIC("Dummy MIC", NULL), + SND_SOC_DAPM_SPK("Dummy SPK", NULL), +}; + +static const struct snd_soc_dapm_route tegra_dummy_routes[] = { + {"Dummy SPK", NULL, "Dummy Playback"}, + {"Dummy Capture", NULL, "Dummy MIC"}, +}; + +static const struct snd_soc_component_driver tegra_dummy_component = { + .dapm_widgets = tegra_dummy_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra_dummy_widgets), + .dapm_routes = tegra_dummy_routes, + .num_dapm_routes = ARRAY_SIZE(tegra_dummy_routes), + .endianness = 1, +}; + +static struct snd_soc_dai_link_component tegra_dummy_dlc = { + .of_node = NULL, + .dai_name = "tegra-snd-dummy-dai", + .name = "sound", +}; + static int tegra_audio_graph_probe(struct platform_device *pdev) { struct tegra_audio_priv *priv; struct device *dev = &pdev->dev; struct snd_soc_card *card; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -207,11 +286,31 @@ static int tegra_audio_graph_probe(struct platform_device *pdev) card->probe = tegra_audio_graph_card_probe; /* audio_graph_parse_of() depends on below */ - card->component_chaining = 1; - priv->simple.ops = &tegra_audio_graph_ops; - priv->simple.force_dpcm = 1; + if (!of_property_read_bool(dev->of_node, "nvidia,ahub-c2c-links")) { + card->component_chaining = 1; + priv->simple.force_dpcm = 1; + } - return audio_graph_parse_of(&priv->simple, dev); + ret = devm_snd_soc_register_component(dev, &tegra_dummy_component, + &tegra_dummy_dai, 1); + if (ret < 0) { + dev_err(dev, "Tegra dummy component registration fails\n"); + return ret; + } + + priv->simple.dummy_dlc = &tegra_dummy_dlc; + priv->simple.ops = &tegra_audio_graph_ops; + + ret = audio_graph_parse_of(&priv->simple, dev); + if (ret < 0) + return ret; + + of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + + dev_info(&pdev->dev, "Registered APE graph sound card with %s links for AHUB\n", + card->component_chaining ? "DPCM" : "codec2codec"); + + return 0; } static const struct tegra_audio_cdata tegra210_data = {