Skip to content
Permalink
Browse files
simple-card-utils: prepare for Multi-CPU/Codec support
simple-card / audio-graph are used fixed number (= 1) for
dai_link's num_cpus/num_codecs/num_platforms.
But audio-graph-card2 will support Multi-CPU/Codec.
This patch prepare Multi-CPU/Codec support.

To be simple code, it assumes SNDRV_MINOR_DEVICES is the MAX dai_link size.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  • Loading branch information
morimoto committed Nov 10, 2020
1 parent 6ce70a7 commit 22ad805d527057b9972b3e64dc7fd15674edc0a9
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 80 deletions.
@@ -41,11 +41,9 @@ struct asoc_simple_jack {
struct asoc_simple_priv {
struct snd_soc_card snd_card;
struct simple_dai_props {
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component cpus; /* single cpu */
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platforms;
struct asoc_simple_dai *cpus;
struct asoc_simple_dai *codecs;
struct snd_soc_dai_link_component *link_component; /* cpus / codecs / platforms */
struct asoc_simple_data adata;
struct snd_soc_codec_conf *codec_conf;
unsigned int mclk_fs;
@@ -70,6 +68,11 @@ struct link_info {
int link; /* number of link */
int conf; /* number of codec_conf */
int cpu; /* turn for CPU / Codec */
struct dai_link_nums {
int cpus;
int codecs;
int platforms;
} link_nums[SNDRV_MINOR_DEVICES];
};

int asoc_simple_parse_daifmt(struct device *dev,
@@ -84,10 +87,10 @@ int asoc_simple_set_dailink_name(struct device *dev,
int asoc_simple_parse_card_name(struct snd_soc_card *card,
char *prefix);

#define asoc_simple_parse_clk_cpu(dev, node, dai_link, simple_dai) \
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->cpus)
#define asoc_simple_parse_clk_codec(dev, node, dai_link, simple_dai) \
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->codecs)
#define asoc_simple_parse_clk_cpu(dev, node, dai_link, dai_props, idx) \
asoc_simple_parse_clk(dev, node, dai_props->cpus + idx, dai_link->cpus + idx)
#define asoc_simple_parse_clk_codec(dev, node, dai_link, dai_props, idx) \
asoc_simple_parse_clk(dev, node, dai_props->codecs + idx, dai_link->codecs + idx)
int asoc_simple_parse_clk(struct device *dev,
struct device_node *node,
struct asoc_simple_dai *simple_dai,
@@ -268,7 +268,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
if (ret)
goto out_put_node;

ret = asoc_simple_parse_clk_cpu(dev, ep, dai_link, dai);
ret = asoc_simple_parse_clk_cpu(dev, ep, dai_link, dai_props, 0);
if (ret < 0)
goto out_put_node;

@@ -316,7 +316,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
if (ret < 0)
goto out_put_node;

ret = asoc_simple_parse_clk_codec(dev, ep, dai_link, dai);
ret = asoc_simple_parse_clk_codec(dev, ep, dai_link, dai_props, 0);
if (ret < 0)
goto out_put_node;

@@ -420,11 +420,11 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv,
if (ret < 0)
return ret;

ret = asoc_simple_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
ret = asoc_simple_parse_clk_cpu(dev, cpu_ep, dai_link, dai_props, 0);
if (ret < 0)
return ret;

ret = asoc_simple_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
ret = asoc_simple_parse_clk_codec(dev, codec_ep, dai_link, dai_props, 0);
if (ret < 0)
return ret;

@@ -610,12 +610,33 @@ int graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
}
EXPORT_SYMBOL_GPL(graph_parse_of);

static int graph_link_nums_inc(struct asoc_simple_priv *priv, struct link_info *li)
{
if (li->link >= SNDRV_MINOR_DEVICES) {
struct device *dev = simple_priv_to_dev(priv);

dev_err(dev, "too many DAI Links. Do nothing\n");
return -EINVAL;
}

/* audio-graph doesn't support Multi CPU/Codec */
li->link_nums[li->link].cpus = 1;
li->link_nums[li->link].codecs = 1;
li->link_nums[li->link].platforms = 1;

return 0;
}

static int graph_count_noml(struct asoc_simple_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct link_info *li)
{
struct device *dev = simple_priv_to_dev(priv);
int ret = graph_link_nums_inc(priv, li);

if (ret < 0)
return ret;

li->link += 1; /* 1xCPU-Codec */
li->dais += 2; /* 1xCPU + 1xCodec */
@@ -632,11 +653,20 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv,
int dup_codec)
{
struct device *dev = simple_priv_to_dev(priv);
int ret;

ret = graph_link_nums_inc(priv, li);
if (ret < 0)
return ret;

li->link++; /* 1xCPU-dummy */
li->dais++; /* 1xCPU */

if (!dup_codec && codec_ep) {
ret = graph_link_nums_inc(priv, li);
if (ret < 0)
return ret;

li->link++; /* 1xdummy-Codec */
li->conf++; /* 1xdummy-Codec */
li->dais++; /* 1xCodec */
@@ -196,15 +196,27 @@ int asoc_simple_startup(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
int ret;
int cpu, codec, ret;

ret = asoc_simple_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
for(cpu = 0; cpu < rtd->num_cpus; cpu++) {
ret = asoc_simple_clk_enable(dai_props->cpus + cpu);
if (ret)
goto cpu_err;
}

ret = asoc_simple_clk_enable(dai_props->codec_dai);
if (ret)
asoc_simple_clk_disable(dai_props->cpu_dai);
for(codec = 0; codec < rtd->num_codecs; codec++) {
ret = asoc_simple_clk_enable(dai_props->codecs + codec);
if (ret)
goto codec_err;
}
codec_err:
if (ret < 0)
for (; codec >= 0; codec--)
asoc_simple_clk_disable(dai_props->codecs + codec);
cpu_err:
if (ret < 0)
for (; cpu >= 0; cpu--)
asoc_simple_clk_disable(dai_props->cpus + cpu);

return ret;
}
@@ -213,20 +225,23 @@ EXPORT_SYMBOL_GPL(asoc_simple_startup);
void asoc_simple_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai;
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
int i;

if (dai_props->mclk_fs) {
snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN);
snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT);
for_each_rtd_cpu_dais(rtd, i, dai) {
if (dai_props->mclk_fs)
snd_soc_dai_set_sysclk(dai, 0, 0, SND_SOC_CLOCK_OUT);
asoc_simple_clk_disable(dai_props->cpus + i);
}

asoc_simple_clk_disable(dai_props->cpu_dai);

asoc_simple_clk_disable(dai_props->codec_dai);
for_each_rtd_codec_dais(rtd, i, dai) {
if (dai_props->mclk_fs)
snd_soc_dai_set_sysclk(dai, 0, 0, SND_SOC_CLOCK_IN);
asoc_simple_clk_disable(dai_props->codecs + i);
}
}
EXPORT_SYMBOL_GPL(asoc_simple_shutdown);

@@ -249,41 +264,40 @@ int asoc_simple_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *dai;
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
unsigned int mclk, mclk_fs = 0;
int ret = 0;
int i, ret = 0;

if (dai_props->mclk_fs)
mclk_fs = dai_props->mclk_fs;

if (mclk_fs) {
mclk = params_rate(params) * mclk_fs;

ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
if (ret < 0)
return ret;
for_each_rtd_codec_dais(rtd, i, dai) {
ret = asoc_simple_set_clk_rate(dai_props->codecs + i, mclk);
if (ret < 0)
return ret;

ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_sysclk(dai, 0, mclk, SND_SOC_CLOCK_IN);
if (ret && ret != -ENOTSUPP)
return ret;
}

ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
SND_SOC_CLOCK_IN);
if (ret && ret != -ENOTSUPP)
goto err;
for_each_rtd_cpu_dais(rtd, i, dai) {
ret = asoc_simple_set_clk_rate(dai_props->cpus + i, mclk);
if (ret < 0)
return ret;

ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
SND_SOC_CLOCK_OUT);
if (ret && ret != -ENOTSUPP)
goto err;
ret = snd_soc_dai_set_sysclk(dai, 0, mclk, SND_SOC_CLOCK_OUT);
if (ret && ret != -ENOTSUPP)
return ret;
}
}
return 0;
err:
return ret;
}
EXPORT_SYMBOL_GPL(asoc_simple_hw_params);

@@ -379,17 +393,20 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
int ret;
struct snd_soc_dai *dai;
int i, ret;

ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, 0),
dai_props->codec_dai);
if (ret < 0)
return ret;
for_each_rtd_codec_dais(rtd, i, dai) {
ret = asoc_simple_init_dai(dai, dai_props->codecs + i);
if (ret < 0)
return ret;
}

ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, 0),
dai_props->cpu_dai);
if (ret < 0)
return ret;
for_each_rtd_cpu_dais(rtd, i, dai) {
ret = asoc_simple_init_dai(dai, dai_props->cpus + i);
if (ret < 0)
return ret;
}

ret = asoc_simple_init_dai_link_params(rtd, dai_props);
if (ret < 0)
@@ -402,6 +419,11 @@ EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link)
{
/* Assumes platform == cpu */
/*
* FIXME:
* Does this works for Multi-CPU case, too ?
* How about Multi-Platform case ?
*/
if (!dai_link->platforms->of_node)
dai_link->platforms->of_node = dai_link->cpus->of_node;

@@ -426,6 +448,9 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
* fmt_single_name()
* fmt_multiple_name()
*/
/*
* FIXME: Is this works on Multi-CPU case, too ?
*/
if (is_single_links)
dai_link->cpus->dai_name = NULL;
}
@@ -434,11 +459,14 @@ EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
int asoc_simple_clean_reference(struct snd_soc_card *card)
{
struct snd_soc_dai_link *dai_link;
int i;
struct snd_soc_dai_link_component *data;
int i, t;

for_each_card_prelinks(card, i, dai_link) {
of_node_put(dai_link->cpus->of_node);
of_node_put(dai_link->codecs->of_node);
for_each_link_cpus(dai_link, t, data)
of_node_put(data->of_node);
for_each_link_codecs(dai_link, t, data)
of_node_put(data->of_node);
}
return 0;
}
@@ -603,6 +631,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
struct simple_dai_props *dai_props;
struct asoc_simple_dai *dais;
struct snd_soc_codec_conf *cconf = NULL;
struct snd_soc_dai_link_component *link_component;
int i;

dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
@@ -623,12 +652,23 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
* simple-card-utils.c :: asoc_simple_canonicalize_platform()
*/
for (i = 0; i < li->link; i++) {
dai_link[i].cpus = &dai_props[i].cpus;
dai_link[i].num_cpus = 1;
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platforms = &dai_props[i].platforms;
dai_link[i].num_platforms = 1;
link_component = devm_kcalloc(dev,
li->link_nums[i].cpus +
li->link_nums[i].codecs +
li->link_nums[i].platforms,
sizeof(*link_component), GFP_KERNEL);
if (!link_component)
return -ENOMEM;

dai_props[i].link_component = link_component;

dai_link[i].cpus = link_component;
dai_link[i].num_cpus = li->link_nums[i].cpus;
dai_link[i].codecs = link_component + li->link_nums[i].cpus;
dai_link[i].num_codecs = li->link_nums[i].codecs;
dai_link[i].platforms = link_component + li->link_nums[i].cpus +
li->link_nums[i].codecs;
dai_link[i].num_platforms = li->link_nums[i].platforms;
}

priv->dai_props = dai_props;

0 comments on commit 22ad805

Please sign in to comment.