NVIDIA: SAUCE: ASoC: tegra: codec2codec mode for AHUB DAI links

BugLink: https://bugs.launchpad.net/bugs/2072591

Add support to use AHUB internal modules with codec2codec DAI links.
This can be enabled by using DT property "nvidia,ahub-c2c-links" in
the sound node. The FE DAI links use normal PCM interfaces and thus
are normal DAI links. Rest of the AHUB modules are connected via
codec2codec DAI links. This is enabled with graph card driver now.

http://nvbugs/4451662

Signed-off-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-by: Sharad Gupta <sharadg@nvidia.com>
Reviewed-by: Mohan kumar <mkumard@nvidia.com>
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Acked-by: Noah Wager <noah.wager@canonical.com>
Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
Sameer Pujar
2024-03-13 18:08:57 +00:00
committed by Noah Wager
parent bf92861fb7
commit b5d22f0cd4
16 changed files with 131 additions and 9 deletions
+1
View File
@@ -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;
+7 -1
View File
@@ -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);
+3
View File
@@ -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)
+1
View File
@@ -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)
{
+1
View File
@@ -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)
+1
View File
@@ -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)
+1
View File
@@ -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,
+4 -2
View File
@@ -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 <linux/clk.h>
#include <linux/device.h>
@@ -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 = {
+1
View File
@@ -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)
+1
View File
@@ -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)
+1
View File
@@ -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)
+1
View File
@@ -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,
+1
View File
@@ -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)
+1
View File
@@ -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)
+1
View File
@@ -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)
+105 -6
View File
@@ -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 <linux/math64.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <sound/graph_card.h>
#include <sound/pcm_params.h>
#include <sound/soc-dai.h>
#include <sound/soc-link.h>
#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 = {