ASoC: tegra: Single cpu multi codec dai support

Add driver support for single cpu dai connected to multiple
codec dai.

Tested on Concord board with one DSPK cpu dai connected to
two TAS2552 codec dai present on Super-io module connected
to 40 pin header.

Bug 3772918

Change-Id: I6cf33c2a4736dc27a44b5db136ebabe88f55ab65
Signed-off-by: Mohan Kumar <mkumard@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.10/+/2795021
(cherry picked from commit 8e2485e8ff53581acb4aa6fae739114490c77238)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2815755
Reviewed-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-by: Sharad Gupta <sharadg@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Mohan Kumar
2022-10-19 22:43:02 +05:30
committed by mobile promotions
parent 1cd9efe47d
commit dc9fe67430
3 changed files with 133 additions and 160 deletions

View File

@@ -446,38 +446,6 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
.ops = &tegra186_dspk_dai_ops,
.symmetric_rate = 1,
},
/* The second DAI is used when the output of the DSPK is connected
* to two mono codecs. When the output of the DSPK is connected to
* a single stereo codec, then only the first DAI should be used.
*/
{
.name = "CIF2",
.playback = {
.stream_name = "CIF2-Playback",
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
},
{
.name = "DAP2",
#if IS_ENABLED(CONFIG_TEGRA_DPCM)
.playback = {
.stream_name = "DAP2-Playback",
#else
.capture = {
.stream_name = "DAP2-Capture",
#endif
.channels_min = 1,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
.symmetric_rate = 1,
},
{
.name = "DUMMY_SINK",
.playback = {
@@ -493,7 +461,6 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
static const struct snd_soc_dapm_widget tegra186_dspk_widgets[] = {
SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA186_DSPK_ENABLE, 0, 0),
SND_SOC_DAPM_AIF_OUT("DAP2 TX", NULL, 0, 0, 0, 0),
SND_SOC_DAPM_SPK("SPK", NULL),
};
@@ -507,8 +474,6 @@ static const struct snd_soc_dapm_route tegra186_dspk_routes[] = {
#else
{ "RX", NULL, "CIF-Playback" },
{ "DAP-Capture", NULL, "RX" },
{ "DAP2 TX", NULL, "CIF2-Playback" },
{ "DAP2-Capture", NULL, "DAP2 TX" },
{ "SPK", NULL, "Dummy-Playback" },
#endif
};

View File

@@ -97,7 +97,35 @@ static int get_num_dai_links(struct platform_device *pdev,
unsigned int *num_links)
{
struct device_node *top = pdev->dev.of_node;
struct device_node *link_node, *codec;
struct device_node *link_node;
unsigned int link_count = 0;
link_node = of_get_child_by_name(top, PREFIX "dai-link");
if (!link_node) {
dev_err(&pdev->dev, "no dai links found\n");
return -ENOENT;
}
do {
if (!of_dai_link_is_available(link_node)) {
link_node = of_get_next_child(top, link_node);
continue;
}
link_count++;
link_node = of_get_next_child(top, link_node);
} while (link_node);
*num_links = link_count;
return 0;
}
static int allocate_link_dais(struct platform_device *pdev,
struct snd_soc_dai_link *dai_links)
{
struct device_node *top = pdev->dev.of_node;
struct device_node *link_node;
unsigned int link_count = 0, num_codecs;
link_node = of_get_child_by_name(top, PREFIX "dai-link");
@@ -112,14 +140,14 @@ static int get_num_dai_links(struct platform_device *pdev,
continue;
}
/*
* depending on the number of codec subnodes, DAI link
* count is incremented. DT can have one DAI link entry
* with multiple codec nodes(for ex: DSPK), driver can
* create multiple links out of it.
*/
dai_links[link_count].cpus = devm_kzalloc(&pdev->dev,
sizeof(*dai_links[link_count].cpus),
GFP_KERNEL);
if (!dai_links[link_count].cpus)
return -ENOMEM;
num_codecs = of_get_child_count_with_name(link_node,
"codec");
"codec");
if (!num_codecs) {
of_node_put(link_node);
dev_err(&pdev->dev,
@@ -127,19 +155,28 @@ static int get_num_dai_links(struct platform_device *pdev,
return -EINVAL;
}
for_each_child_of_node(link_node, codec) {
if (of_node_cmp(codec->name, "codec"))
continue;
dai_links[link_count].codecs =
devm_kzalloc(&pdev->dev,
sizeof(*dai_links[link_count].codecs) * num_codecs,
GFP_KERNEL);
if (!dai_links[link_count].codecs)
return -ENOMEM;
if (of_property_read_bool(codec, DAI))
link_count++;
}
dai_links[link_count].platforms = devm_kzalloc(&pdev->dev,
sizeof(*dai_links[link_count].platforms),
GFP_KERNEL);
if (!dai_links[link_count].platforms)
return -ENOMEM;
dai_links[link_count].num_cpus = 1;
dai_links[link_count].num_codecs = num_codecs;
dai_links[link_count].num_platforms = 1;
link_count++;
link_node = of_get_next_child(top, link_node);
} while (link_node);
*num_links = link_count;
return 0;
}
@@ -372,7 +409,7 @@ static int parse_dt_dai_links(struct snd_soc_card *card,
struct device_node *top = pdev->dev.of_node;
struct device_node *link_node;
struct snd_soc_dai_link *dai_links;
unsigned int num_links, link_count = 0, i;
unsigned int num_links, link_count = 0;
int ret;
ret = get_num_dai_links(pdev, &machine->asoc->num_links);
@@ -388,29 +425,9 @@ static int parse_dt_dai_links(struct snd_soc_card *card,
if (!dai_links)
return -ENOMEM;
for (i = 0; i < num_links; i++) {
dai_links[i].cpus = devm_kzalloc(&pdev->dev,
sizeof(*dai_links[i].cpus),
GFP_KERNEL);
if (!dai_links[i].cpus)
return -ENOMEM;
dai_links[i].codecs = devm_kzalloc(&pdev->dev,
sizeof(*dai_links[i].codecs),
GFP_KERNEL);
if (!dai_links[i].codecs)
return -ENOMEM;
dai_links[i].platforms = devm_kzalloc(&pdev->dev,
sizeof(*dai_links[i].platforms),
GFP_KERNEL);
if (!dai_links[i].platforms)
return -ENOMEM;
dai_links[i].num_cpus = 1;
dai_links[i].num_codecs = 1;
dai_links[i].num_platforms = 1;
}
ret = allocate_link_dais(pdev, dai_links);
if (ret < 0)
return ret;
machine->asoc->dai_links = dai_links;
@@ -433,6 +450,7 @@ static int parse_dt_dai_links(struct snd_soc_card *card,
dev_dbg(&pdev->dev, "parsing (%pOF)\n", link_node);
dai_link = &dai_links[link_count];
cpu = of_get_child_by_name(link_node, "cpu");
if (!cpu) {
dev_err(&pdev->dev, "cpu subnode is missing");
@@ -440,6 +458,11 @@ static int parse_dt_dai_links(struct snd_soc_card *card,
goto cleanup;
}
/* parse CPU DAI */
ret = parse_dai(cpu, dai_link->cpus);
if (ret < 0)
goto cleanup;
for_each_child_of_node(link_node, codec) {
/* loop over codecs only */
if (of_node_cmp(codec->name, "codec"))
@@ -453,48 +476,43 @@ static int parse_dt_dai_links(struct snd_soc_card *card,
continue;
}
dai_link = &dai_links[link_count];
/* parse CPU DAI */
ret = parse_dai(cpu, dai_link->cpus);
if (ret < 0)
goto cleanup;
/* parse CODEC DAI */
ret = parse_dai(codec, dai_link->codecs);
ret = parse_dai(codec, &dai_link->codecs[codec_count]);
if (ret < 0)
goto cleanup;
/* set DAI link name */
if (of_property_read_string_index(link_node,
"link-name",
codec_count,
&dai_link->name)) {
ret = asoc_simple_set_dailink_name(
&pdev->dev, dai_link, "%s-%d",
"tegra-dlink", link_count);
if (ret < 0)
goto cleanup;
}
codec_count++;
}
asoc_simple_parse_daifmt(&pdev->dev, link_node, codec,
NULL, &dai_link->dai_fmt);
/* set DAI link name */
if (of_property_read_string(link_node,
"link-name",
&dai_link->name)) {
ret = asoc_simple_set_dailink_name(
&pdev->dev, dai_link, "%s-%d",
"tegra-dlink", link_count);
if (ret < 0)
goto cleanup;
}
asoc_simple_canonicalize_platform(dai_link->platforms,
dai_link->cpus);
asoc_simple_parse_daifmt(&pdev->dev, link_node, codec,
NULL, &dai_link->dai_fmt);
of_property_read_u32(link_node, "link-type",
&link_type);
switch (link_type) {
case PCM_LINK:
dai_link->ops = pcm_ops;
break;
case COMPR_LINK:
dai_link->compr_ops = compr_ops;
break;
case C2C_LINK:
/* Parse DT provided link params */
ret = parse_dai_link_params(pdev, link_node,
asoc_simple_canonicalize_platform(dai_link->platforms,
dai_link->cpus);
of_property_read_u32(link_node, "link-type",
&link_type);
switch (link_type) {
case PCM_LINK:
dai_link->ops = pcm_ops;
break;
case COMPR_LINK:
dai_link->compr_ops = compr_ops;
break;
case C2C_LINK:
/* Parse DT provided link params */
ret = parse_dai_link_params(pdev, link_node,
dai_link);
if (ret < 0)
goto cleanup;
@@ -504,33 +522,32 @@ static int parse_dt_dai_links(struct snd_soc_card *card,
dev_err(&pdev->dev, "DAI link type invalid\n");
ret = -EINVAL;
goto cleanup;
}
/*
* Assign DAI link ID based on DT link address.
* This is done to use consistent PCM/Compress device
* IDs irrespective of parsing order of DT DAI links.
*/
link_addr = strrchr(link_node->full_name, '@');
if (!link_addr) {
dev_err(&pdev->dev,
"Invalid link node (%pOF)\n",
link_node);
ret = -EINVAL;
goto cleanup;
}
ret = kstrtos32(++link_addr, 10, &dai_link->id);
if (ret < 0) {
dev_err(&pdev->dev,
"Failed to get link node (%pOF) ID\n",
link_node);
goto cleanup;
}
link_count++;
codec_count++;
}
/*
* Assign DAI link ID based on DT link address.
* This is done to use consistent PCM/Compress device
* IDs irrespective of parsing order of DT DAI links.
*/
link_addr = strrchr(link_node->full_name, '@');
if (!link_addr) {
dev_err(&pdev->dev,
"Invalid link node (%pOF)\n",
link_node);
ret = -EINVAL;
goto cleanup;
}
ret = kstrtos32(++link_addr, 10, &dai_link->id);
if (ret < 0) {
dev_err(&pdev->dev,
"Failed to get link node (%pOF) ID\n",
link_node);
goto cleanup;
}
link_count++;
cleanup:
of_node_put(cpu);
if (ret < 0) {

View File

@@ -185,7 +185,7 @@ int tegra_codecs_runtime_setup(struct snd_soc_card *card,
unsigned int aud_mclk)
{
struct snd_soc_pcm_runtime *rtd;
int err;
int i, err;
rtd = get_pcm_runtime(card, "rt565x-playback");
if (rtd) {
@@ -231,30 +231,21 @@ int tegra_codecs_runtime_setup(struct snd_soc_card *card,
}
}
rtd = get_pcm_runtime(card, "dspk-playback-r");
rtd = get_pcm_runtime(card, "dspk-playback-dual-tas2552");
if (rtd) {
if (!strcmp(rtd->dais[rtd->dai_link->num_cpus]->name, "tas2552-amplifier")) {
err = snd_soc_dai_set_sysclk(rtd->dais[rtd->dai_link->num_cpus],
TAS2552_PDM_CLK_IVCLKIN, aud_mclk,
SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "dais[%d] clock not set\n",
rtd->dai_link->num_cpus);
return err;
}
}
}
rtd = get_pcm_runtime(card, "dspk-playback-l");
if (rtd) {
if (!strcmp(rtd->dais[rtd->dai_link->num_cpus]->name, "tas2552-amplifier")) {
err = snd_soc_dai_set_sysclk(rtd->dais[rtd->dai_link->num_cpus],
TAS2552_PDM_CLK_IVCLKIN, aud_mclk,
SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "dais[%d] clock not set\n",
rtd->dai_link->num_cpus);
return err;
for (i = 0; i < rtd->num_codecs; i++) {
if (!strcmp(rtd->dais[rtd->num_cpus + i]->name,
"tas2552-amplifier")) {
err = snd_soc_dai_set_sysclk(
rtd->dais[rtd->num_cpus + i],
TAS2552_PDM_CLK_IVCLKIN, aud_mclk,
SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev,
"dais[%d] clock not set\n",
rtd->num_cpus + i);
return err;
}
}
}
}