mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 09:11:26 +03:00
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:
committed by
mobile promotions
parent
1cd9efe47d
commit
dc9fe67430
@@ -446,38 +446,6 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
|
|||||||
.ops = &tegra186_dspk_dai_ops,
|
.ops = &tegra186_dspk_dai_ops,
|
||||||
.symmetric_rate = 1,
|
.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",
|
.name = "DUMMY_SINK",
|
||||||
.playback = {
|
.playback = {
|
||||||
@@ -493,7 +461,6 @@ static struct snd_soc_dai_driver tegra186_dspk_dais[] = {
|
|||||||
|
|
||||||
static const struct snd_soc_dapm_widget tegra186_dspk_widgets[] = {
|
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_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),
|
SND_SOC_DAPM_SPK("SPK", NULL),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -507,8 +474,6 @@ static const struct snd_soc_dapm_route tegra186_dspk_routes[] = {
|
|||||||
#else
|
#else
|
||||||
{ "RX", NULL, "CIF-Playback" },
|
{ "RX", NULL, "CIF-Playback" },
|
||||||
{ "DAP-Capture", NULL, "RX" },
|
{ "DAP-Capture", NULL, "RX" },
|
||||||
{ "DAP2 TX", NULL, "CIF2-Playback" },
|
|
||||||
{ "DAP2-Capture", NULL, "DAP2 TX" },
|
|
||||||
{ "SPK", NULL, "Dummy-Playback" },
|
{ "SPK", NULL, "Dummy-Playback" },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -97,7 +97,35 @@ static int get_num_dai_links(struct platform_device *pdev,
|
|||||||
unsigned int *num_links)
|
unsigned int *num_links)
|
||||||
{
|
{
|
||||||
struct device_node *top = pdev->dev.of_node;
|
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;
|
unsigned int link_count = 0, num_codecs;
|
||||||
|
|
||||||
link_node = of_get_child_by_name(top, PREFIX "dai-link");
|
link_node = of_get_child_by_name(top, PREFIX "dai-link");
|
||||||
@@ -112,12 +140,12 @@ static int get_num_dai_links(struct platform_device *pdev,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
dai_links[link_count].cpus = devm_kzalloc(&pdev->dev,
|
||||||
* depending on the number of codec subnodes, DAI link
|
sizeof(*dai_links[link_count].cpus),
|
||||||
* count is incremented. DT can have one DAI link entry
|
GFP_KERNEL);
|
||||||
* with multiple codec nodes(for ex: DSPK), driver can
|
if (!dai_links[link_count].cpus)
|
||||||
* create multiple links out of it.
|
return -ENOMEM;
|
||||||
*/
|
|
||||||
num_codecs = of_get_child_count_with_name(link_node,
|
num_codecs = of_get_child_count_with_name(link_node,
|
||||||
"codec");
|
"codec");
|
||||||
if (!num_codecs) {
|
if (!num_codecs) {
|
||||||
@@ -127,19 +155,28 @@ static int get_num_dai_links(struct platform_device *pdev,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_child_of_node(link_node, codec) {
|
dai_links[link_count].codecs =
|
||||||
if (of_node_cmp(codec->name, "codec"))
|
devm_kzalloc(&pdev->dev,
|
||||||
continue;
|
sizeof(*dai_links[link_count].codecs) * num_codecs,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!dai_links[link_count].codecs)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
if (of_property_read_bool(codec, DAI))
|
|
||||||
link_count++;
|
link_count++;
|
||||||
}
|
|
||||||
|
|
||||||
link_node = of_get_next_child(top, link_node);
|
link_node = of_get_next_child(top, link_node);
|
||||||
} while (link_node);
|
} while (link_node);
|
||||||
|
|
||||||
*num_links = link_count;
|
|
||||||
|
|
||||||
return 0;
|
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 *top = pdev->dev.of_node;
|
||||||
struct device_node *link_node;
|
struct device_node *link_node;
|
||||||
struct snd_soc_dai_link *dai_links;
|
struct snd_soc_dai_link *dai_links;
|
||||||
unsigned int num_links, link_count = 0, i;
|
unsigned int num_links, link_count = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = get_num_dai_links(pdev, &machine->asoc->num_links);
|
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)
|
if (!dai_links)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i = 0; i < num_links; i++) {
|
ret = allocate_link_dais(pdev, dai_links);
|
||||||
dai_links[i].cpus = devm_kzalloc(&pdev->dev,
|
if (ret < 0)
|
||||||
sizeof(*dai_links[i].cpus),
|
return ret;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
machine->asoc->dai_links = dai_links;
|
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);
|
dev_dbg(&pdev->dev, "parsing (%pOF)\n", link_node);
|
||||||
|
|
||||||
|
dai_link = &dai_links[link_count];
|
||||||
cpu = of_get_child_by_name(link_node, "cpu");
|
cpu = of_get_child_by_name(link_node, "cpu");
|
||||||
if (!cpu) {
|
if (!cpu) {
|
||||||
dev_err(&pdev->dev, "cpu subnode is missing");
|
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;
|
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) {
|
for_each_child_of_node(link_node, codec) {
|
||||||
/* loop over codecs only */
|
/* loop over codecs only */
|
||||||
if (of_node_cmp(codec->name, "codec"))
|
if (of_node_cmp(codec->name, "codec"))
|
||||||
@@ -453,22 +476,17 @@ static int parse_dt_dai_links(struct snd_soc_card *card,
|
|||||||
continue;
|
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 */
|
/* parse CODEC DAI */
|
||||||
ret = parse_dai(codec, dai_link->codecs);
|
ret = parse_dai(codec, &dai_link->codecs[codec_count]);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
codec_count++;
|
||||||
|
}
|
||||||
|
|
||||||
/* set DAI link name */
|
/* set DAI link name */
|
||||||
if (of_property_read_string_index(link_node,
|
if (of_property_read_string(link_node,
|
||||||
"link-name",
|
"link-name",
|
||||||
codec_count,
|
|
||||||
&dai_link->name)) {
|
&dai_link->name)) {
|
||||||
ret = asoc_simple_set_dailink_name(
|
ret = asoc_simple_set_dailink_name(
|
||||||
&pdev->dev, dai_link, "%s-%d",
|
&pdev->dev, dai_link, "%s-%d",
|
||||||
@@ -529,8 +547,7 @@ static int parse_dt_dai_links(struct snd_soc_card *card,
|
|||||||
}
|
}
|
||||||
|
|
||||||
link_count++;
|
link_count++;
|
||||||
codec_count++;
|
|
||||||
}
|
|
||||||
cleanup:
|
cleanup:
|
||||||
of_node_put(cpu);
|
of_node_put(cpu);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ int tegra_codecs_runtime_setup(struct snd_soc_card *card,
|
|||||||
unsigned int aud_mclk)
|
unsigned int aud_mclk)
|
||||||
{
|
{
|
||||||
struct snd_soc_pcm_runtime *rtd;
|
struct snd_soc_pcm_runtime *rtd;
|
||||||
int err;
|
int i, err;
|
||||||
|
|
||||||
rtd = get_pcm_runtime(card, "rt565x-playback");
|
rtd = get_pcm_runtime(card, "rt565x-playback");
|
||||||
if (rtd) {
|
if (rtd) {
|
||||||
@@ -231,32 +231,23 @@ 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 (rtd) {
|
||||||
if (!strcmp(rtd->dais[rtd->dai_link->num_cpus]->name, "tas2552-amplifier")) {
|
for (i = 0; i < rtd->num_codecs; i++) {
|
||||||
err = snd_soc_dai_set_sysclk(rtd->dais[rtd->dai_link->num_cpus],
|
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,
|
TAS2552_PDM_CLK_IVCLKIN, aud_mclk,
|
||||||
SND_SOC_CLOCK_IN);
|
SND_SOC_CLOCK_IN);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(card->dev, "dais[%d] clock not set\n",
|
dev_err(card->dev,
|
||||||
rtd->dai_link->num_cpus);
|
"dais[%d] clock not set\n",
|
||||||
|
rtd->num_cpus + i);
|
||||||
return err;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user