Commit da215354 authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mark Brown

ASoC: simple-card: merge simple-scu-card

simple-card and simple-scu-card are very similar driver,
but the former is supporting normal sound card,
the latter is supporting DPCM sound card.

We couldn't use normal sound and DPCM sound in same time by
one sound card. This patch merges both sound card into
simple-card. Now we can use both feature on same driver.

simple-card is now supporting .compatible = "simple-scu-audio-card".
Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent c4e8ebb9
...@@ -6,6 +6,7 @@ config SND_SIMPLE_CARD ...@@ -6,6 +6,7 @@ config SND_SIMPLE_CARD
select SND_SIMPLE_CARD_UTILS select SND_SIMPLE_CARD_UTILS
help help
This option enables generic simple sound card support This option enables generic simple sound card support
It also support DPCM of multi CPU single Codec ststem.
config SND_SIMPLE_SCU_CARD config SND_SIMPLE_SCU_CARD
tristate "ASoC Simple SCU sound card support" tristate "ASoC Simple SCU sound card support"
......
...@@ -22,6 +22,8 @@ struct simple_card_data { ...@@ -22,6 +22,8 @@ struct simple_card_data {
struct asoc_simple_dai *codec_dai; struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs; /* single codec */ struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platform; struct snd_soc_dai_link_component platform;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
unsigned int mclk_fs; unsigned int mclk_fs;
} *dai_props; } *dai_props;
unsigned int mclk_fs; unsigned int mclk_fs;
...@@ -29,6 +31,8 @@ struct simple_card_data { ...@@ -29,6 +31,8 @@ struct simple_card_data {
struct asoc_simple_jack mic_jack; struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link; struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais; struct asoc_simple_dai *dais;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
}; };
#define simple_priv_to_card(priv) (&(priv)->snd_card) #define simple_priv_to_card(priv) (&(priv)->snd_card)
...@@ -74,6 +78,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) ...@@ -74,6 +78,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
unsigned long rate) unsigned long rate)
{ {
if (!simple_dai)
return 0;
if (!simple_dai->clk) if (!simple_dai->clk)
return 0; return 0;
...@@ -151,6 +158,141 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) ...@@ -151,6 +158,141 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
return 0; return 0;
} }
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
asoc_simple_card_convert_fixup(&dai_props->adata, params);
/* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup(&priv->adata, params);
return 0;
}
static int asoc_simple_card_dai_link_of_dpcm(struct device_node *node,
struct device_node *np,
struct device_node *codec,
struct simple_card_data *priv,
int *dai_idx, int link_idx,
int *conf_idx, int is_fe,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
struct snd_soc_card *card = simple_priv_to_card(priv);
struct asoc_simple_dai *dai;
char *prefix = "";
int ret;
/* For single DAI link & old style of DT node */
if (is_top_level_node)
prefix = PREFIX;
if (is_fe) {
int is_single_links = 0;
struct snd_soc_dai_link_component *codecs;
/* BE is dummy */
codecs = dai_link->codecs;
codecs->of_node = NULL;
codecs->dai_name = "snd-soc-dummy-dai";
codecs->name = "snd-soc-dummy";
/* FE settings */
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
&is_single_links);
if (ret)
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"fe.%s",
dai_link->cpu_dai_name);
if (ret < 0)
return ret;
asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
} else {
struct snd_soc_codec_conf *cconf;
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
dai_link->cpu_name = "snd-soc-dummy";
/* BE settings */
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
cconf =
dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"be.%s",
dai_link->codecs->dai_name);
if (ret < 0)
return ret;
/* check "prefix" from top node */
snd_soc_of_parse_audio_prefix(card, cconf,
dai_link->codecs->of_node,
PREFIX "prefix");
/* check "prefix" from each node if top doesn't have */
if (!cconf->of_node)
snd_soc_of_parse_node_prefix(np, cconf,
dai_link->codecs->of_node,
"prefix");
}
asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata);
ret = asoc_simple_card_of_parse_tdm(np, dai);
if (ret)
return ret;
ret = asoc_simple_card_canonicalize_dailink(dai_link);
if (ret < 0)
return ret;
of_property_read_u32(np, "mclk-fs", &dai_props->mclk_fs);
ret = asoc_simple_card_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
return ret;
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_simple_card_ops;
dai_link->init = asoc_simple_card_dai_init;
return 0;
}
static int asoc_simple_card_dai_link_of(struct device_node *node, static int asoc_simple_card_dai_link_of(struct device_node *node,
struct simple_card_data *priv, struct simple_card_data *priv,
int *dai_idx, int link_idx, int *dai_idx, int link_idx,
...@@ -291,63 +433,153 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, ...@@ -291,63 +433,153 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
static int asoc_simple_card_parse_of(struct simple_card_data *priv) static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{ {
struct device *dev = simple_priv_to_dev(priv); struct device *dev = simple_priv_to_dev(priv);
struct device_node *top = dev->of_node;
struct snd_soc_card *card = simple_priv_to_card(priv); struct snd_soc_card *card = simple_priv_to_card(priv);
struct device_node *dai_link; struct device_node *node;
struct device_node *node = dev->of_node; struct device_node *np;
int ret; struct device_node *codec;
int link_idx, dai_idx; bool is_fe;
int ret, loop;
if (!node) int dai_idx, link_idx, conf_idx;
if (!top)
return -EINVAL; return -EINVAL;
dai_link = of_get_child_by_name(node, PREFIX "dai-link");
ret = asoc_simple_card_of_parse_widgets(card, PREFIX); ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (ret < 0) if (ret < 0)
goto card_parse_end; return ret;
ret = asoc_simple_card_of_parse_routing(card, PREFIX); ret = asoc_simple_card_of_parse_routing(card, PREFIX);
if (ret < 0) if (ret < 0)
goto card_parse_end; return ret;
/* Factor to mclk, used in hw_params() */ /* Factor to mclk, used in hw_params() */
of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); of_property_read_u32(top, PREFIX "mclk-fs", &priv->mclk_fs);
asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
/* Single/Muti DAI link(s) & New style of DT node */ /* Single/Muti DAI link(s) & New style of DT node */
link_idx = 0; loop = 1;
dai_idx = 0; link_idx = 0;
if (dai_link) { dai_idx = 0;
struct device_node *np = NULL; conf_idx = 0;
node = of_get_child_by_name(top, PREFIX "dai-link");
for_each_child_of_node(node, np) { if (!node) {
dev_dbg(dev, "\tlink %d:\n", link_idx); node = dev->of_node;
ret = asoc_simple_card_dai_link_of(np, priv, loop = 0;
&dai_idx, link_idx++, false); }
if (ret < 0) {
of_node_put(np); do {
goto card_parse_end; /* DPCM */
if (of_get_child_count(node) > 2) {
for_each_child_of_node(node, np) {
codec = of_get_child_by_name(node,
loop ? "codec" :
PREFIX "codec");
if (!codec)
return -ENODEV;
is_fe = (np != codec);
ret = asoc_simple_card_dai_link_of_dpcm(
node, np, codec, priv,
&dai_idx, link_idx++, &conf_idx,
is_fe, !loop);
} }
} else {
ret = asoc_simple_card_dai_link_of(
node, priv,
&dai_idx, link_idx++, !loop);
} }
} else {
/* For single DAI link & old style of DT node */
ret = asoc_simple_card_dai_link_of(node, priv,
&dai_idx, link_idx++, true);
if (ret < 0) if (ret < 0)
goto card_parse_end; return ret;
}
node = of_get_next_child(top, node);
} while (loop && node);
ret = asoc_simple_card_parse_card_name(card, PREFIX); ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0) if (ret < 0)
goto card_parse_end; return ret;
ret = asoc_simple_card_parse_aux_devs(node, priv);
card_parse_end: ret = asoc_simple_card_parse_aux_devs(top, priv);
of_node_put(dai_link);
return ret; return ret;
} }
static void asoc_simple_card_get_dais_count(struct device *dev,
int *link_num,
int *dais_num,
int *ccnf_num)
{
struct device_node *top = dev->of_node;
struct device_node *node;
int loop;
int num;
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for "dummy-Codec"
*
* ex1)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 7
* CPU2 -/ ccnf : 1
* CPU3 --- Codec2
*
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
* => 7 DAIs = 4xCPU + 3xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex2)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 6
* CPU2 -/ ccnf : 1
* CPU3 -/
*
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex3)
* CPU0 --- Codec0 link : 6
* CPU1 -/ dais : 6
* CPU2 --- Codec1 ccnf : 2
* CPU3 -/
*
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 2 ccnf = 2xdummy-Codec
*/
if (!top) {
(*link_num) = 1;
(*dais_num) = 2;
(*ccnf_num) = 0;
return;
}
loop = 1;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = top;
loop = 0;
}
do {
num = of_get_child_count(node);
(*dais_num) += num;
if (num > 2) {
(*link_num) += num;
(*ccnf_num)++;
} else {
(*link_num)++;
}
node = of_get_next_child(top, node);
} while (loop && node);
}
static int asoc_simple_soc_card_probe(struct snd_soc_card *card) static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
{ {
struct simple_card_data *priv = snd_soc_card_get_drvdata(card); struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
...@@ -373,22 +605,23 @@ static int asoc_simple_card_probe(struct platform_device *pdev) ...@@ -373,22 +605,23 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct snd_soc_card *card; struct snd_soc_card *card;
int num, ret, i; struct snd_soc_codec_conf *cconf;
int lnum = 0, dnum = 0, cnum = 0;
/* Get the number of DAI links */ int ret, i;
if (np && of_get_child_by_name(np, PREFIX "dai-link"))
num = of_get_child_count(np);
else
num = 1;
/* Allocate the private data and the DAI link array */ /* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); if (!lnum || !dnum)
dais = devm_kcalloc(dev, num * 2, sizeof(*dais), GFP_KERNEL); return -EINVAL;
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
if (!dai_props || !dai_link || !dais) if (!dai_props || !dai_link || !dais)
return -ENOMEM; return -ENOMEM;
...@@ -398,7 +631,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) ...@@ -398,7 +631,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
* see * see
* soc-core.c :: snd_soc_init_multicodec() * soc-core.c :: snd_soc_init_multicodec()
*/ */
for (i = 0; i < num; i++) { for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1; dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform; dai_link[i].platform = &dai_props[i].platform;
...@@ -407,13 +640,16 @@ static int asoc_simple_card_probe(struct platform_device *pdev) ...@@ -407,13 +640,16 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props; priv->dai_props = dai_props;
priv->dai_link = dai_link; priv->dai_link = dai_link;
priv->dais = dais; priv->dais = dais;
priv->codec_conf = cconf;
/* Init snd_soc_card */ /* Init snd_soc_card */
card = simple_priv_to_card(priv); card = simple_priv_to_card(priv);
card->owner = THIS_MODULE; card->owner = THIS_MODULE;
card->dev = dev; card->dev = dev;
card->dai_link = priv->dai_link; card->dai_link = priv->dai_link;
card->num_links = num; card->num_links = lnum;
card->codec_conf = cconf;
card->num_configs = cnum;
card->probe = asoc_simple_soc_card_probe; card->probe = asoc_simple_soc_card_probe;
if (np && of_device_is_available(np)) { if (np && of_device_is_available(np)) {
...@@ -490,6 +726,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev) ...@@ -490,6 +726,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
static const struct of_device_id asoc_simple_of_match[] = { static const struct of_device_id asoc_simple_of_match[] = {
{ .compatible = "simple-audio-card", }, { .compatible = "simple-audio-card", },
{ .compatible = "simple-scu-audio-card", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, asoc_simple_of_match); MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment