[alsa-devel] [PATCH v2 0/2] ASoC: simple-card: Add multi-CODEC support
This patch set adds multi-CODEC support to the simple card.
v2: accept list of CODECs in 'sound-dais' (Benoit Cousson)
Jean-Francois Moine (2): ASoC: core: add multi-codec support in DT ASoC: simple-card: add multi-CODECs in DT
.../devicetree/bindings/sound/simple-card.txt | 28 +++-- include/sound/soc.h | 3 + sound/soc/generic/simple-card.c | 114 +++++++++++++-------- sound/soc/soc-core.c | 75 +++++++++++--- 4 files changed, 149 insertions(+), 71 deletions(-)
SoC audio cards may have many CODECs per audio link. This patch exports a core function to handle such links when they are described in the DT.
Signed-off-by: Jean-Francois Moine moinejf@free.fr --- include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 75 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 63 insertions(+), 15 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 7ba7130..a255f8b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1451,6 +1451,9 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, struct device_node **framemaster); int snd_soc_of_get_dai_name(struct device_node *of_node, const char **dai_name); +int snd_soc_of_get_dai_link_codecs(struct device_node *of_node, + const char *list_name, + struct snd_soc_dai_link *dai_link);
#include <sound/soc-dai.h>
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4c8f8a2..a605de5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4750,36 +4750,30 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
-int snd_soc_of_get_dai_name(struct device_node *of_node, - const char **dai_name) +static int snd_soc_get_dai_name(struct of_phandle_args *args, + const char **dai_name) { struct snd_soc_component *pos; - struct of_phandle_args args; - int ret; - - ret = of_parse_phandle_with_args(of_node, "sound-dai", - "#sound-dai-cells", 0, &args); - if (ret) - return ret; - - ret = -EPROBE_DEFER; + int ret = -EPROBE_DEFER;
mutex_lock(&client_mutex); list_for_each_entry(pos, &component_list, list) { - if (pos->dev->of_node != args.np) + if (pos->dev->of_node != args->np) continue;
if (pos->driver->of_xlate_dai_name) { - ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); + ret = pos->driver->of_xlate_dai_name(pos, + args, + dai_name); } else { int id = -1;
- switch (args.args_count) { + switch (args->args_count) { case 0: id = 0; /* same as dai_drv[0] */ break; case 1: - id = args.args[0]; + id = args->args[0]; break; default: /* not supported */ @@ -4801,6 +4795,21 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, break; } mutex_unlock(&client_mutex); + return ret; +} + +int snd_soc_of_get_dai_name(struct device_node *of_node, + const char **dai_name) +{ + struct of_phandle_args args; + int ret; + + ret = of_parse_phandle_with_args(of_node, "sound-dai", + "#sound-dai-cells", 0, &args); + if (ret) + return ret; + + ret = snd_soc_get_dai_name(&args, dai_name);
of_node_put(args.np);
@@ -4808,6 +4817,42 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, } EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
+int snd_soc_of_get_dai_link_codecs(struct device_node *of_node, + const char *list_name, + struct snd_soc_dai_link *dai_link) +{ + struct of_phandle_args args; + struct snd_soc_dai_link_component *component; + int index, ret; + + for (index = 0, component = dai_link->codecs; + index < dai_link->num_codecs; + index++, component++) { + ret = of_parse_phandle_with_args(of_node, list_name, + "#sound-dai-cells", + index, &args); + if (ret) + goto err; + component->of_node = args.np; + ret = snd_soc_get_dai_name(&args, &component->dai_name); + if (ret < 0) + goto err; + } + return 0; + +err: + for (index = 0, component = dai_link->codecs; + index < dai_link->num_codecs; + index++, component++) { + if (!component->of_node) + break; + of_node_put((struct device_node *) component->of_node); + component->of_node = NULL; + } + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS
This patch allows many CODECs per link to be defined in the device tree.
Signed-off-by: Jean-Francois Moine moinejf@free.fr --- .../devicetree/bindings/sound/simple-card.txt | 28 +++-- sound/soc/generic/simple-card.c | 114 +++++++++++++-------- 2 files changed, 86 insertions(+), 56 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index c3cba60..6cb1816 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -65,7 +65,11 @@ properties should also be placed in the codec node if needed.
Required CPU/CODEC subnodes properties:
-- sound-dai : phandle and port of CPU/CODEC +either + - sound-dai : phandle and port of CPU/CODEC +or + - sound-dais : list of phandle and port of CODECs +
Optional CPU/CODEC subnodes properties:
@@ -119,37 +123,29 @@ sh_fsi2: sh_fsi2@ec230000 { interrupts = <0 146 0x4>; };
-Example 2 - many DAI links: +Example 2 - many DAI links and multi-CODECs:
sound { compatible = "simple-audio-card"; simple-audio-card,name = "Cubox Audio";
- simple-audio-card,dai-link@0 { /* I2S - HDMI */ + simple-audio-card,dai-link@0 { /* S/PDIF - HDMI & S/PDIF */ format = "i2s"; cpu { - sound-dai = <&audio1 0>; - }; - codec { - sound-dai = <&tda998x 0>; - }; - }; - - simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */ - cpu { sound-dai = <&audio1 1>; }; codec { - sound-dai = <&tda998x 1>; + sound-dais = <&hdmi 0>, <&spdif_codec>; }; };
- simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */ + simple-audio-card,dai-link@1 { /* I2S - HDMI */ + format = "i2s"; cpu { - sound-dai = <&audio1 1>; + sound-dai = <&audio1 0>; }; codec { - sound-dai = <&spdif_codec>; + sound-dai = <&hdmi 1>; }; }; }; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 4f192ee..ff45f4d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -168,34 +168,12 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) static int asoc_simple_card_sub_parse_of(struct device_node *np, struct asoc_simple_dai *dai, - struct device_node **p_node, - const char **name, - int *args_count) + const struct device_node *dai_np) { - struct of_phandle_args args; struct clk *clk; u32 val; int ret;
- /* - * Get node via "sound-dai = <&phandle port>" - * it will be used as xxx_of_node on soc_bind_dai_link() - */ - ret = of_parse_phandle_with_args(np, "sound-dai", - "#sound-dai-cells", 0, &args); - if (ret) - return ret; - - *p_node = args.np; - - if (args_count) - *args_count = args.args_count; - - /* Get dai->name */ - ret = snd_soc_of_get_dai_name(np, name); - if (ret < 0) - return ret; - /* Parse TDM slot */ ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width); if (ret) @@ -218,7 +196,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np, } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { dai->sysclk = val; } else { - clk = of_clk_get(args.np, 0); + clk = of_clk_get((struct device_node *) dai_np, 0); if (!IS_ERR(clk)) dai->sysclk = clk_get_rate(clk); } @@ -237,11 +215,13 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, struct device_node *np = NULL; struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; + struct snd_soc_dai_link_component *component; + struct of_phandle_args args; unsigned int daifmt; char *name; char prop[128]; char *prefix = ""; - int ret, cpu_args; + int ret, cpu_args, i, num_codecs;
/* For single DAI link & old style of DT node */ if (is_top_level_node) @@ -259,10 +239,21 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, goto dai_link_of_err; }
+ + /* Get the CPU node and name */ + ret = of_parse_phandle_with_args(np, "sound-dai", + "#sound-dai-cells", 0, &args); + if (ret) + goto dai_link_of_err; + dai_link->cpu_of_node = args.np; + cpu_args = args.args_count; + + ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); + if (ret < 0) + goto dai_link_of_err; + ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai, - &dai_link->cpu_of_node, - &dai_link->cpu_dai_name, - &cpu_args); + dai_link->cpu_of_node); if (ret < 0) goto dai_link_of_err;
@@ -291,9 +282,35 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, goto dai_link_of_err; }
+ /* Get the node and name of the CODEC(s) */ + name = "sound-dai"; + num_codecs = of_count_phandle_with_args(np, name, + "#sound-dai-cells"); + if (num_codecs <= 0) { + name = "sound-dais"; + num_codecs = of_count_phandle_with_args(np, name, + "#sound-dai-cells"); + if (num_codecs <= 0) { + ret = -EINVAL; + dev_err(dev, "No CODEC DAI phandle\n"); + goto dai_link_of_err; + } + } + component = devm_kzalloc(dev, + sizeof *component * num_codecs, + GFP_KERNEL); + if (!component) { + ret = -ENOMEM; + goto dai_link_of_err; + } + dai_link->codecs = component; + dai_link->num_codecs = num_codecs; + ret = snd_soc_of_get_dai_link_codecs(np, name, dai_link); + if (ret < 0) + goto dai_link_of_err; + ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai, - &dai_link->codec_of_node, - &dai_link->codec_dai_name, NULL); + dai_link->codecs[0].of_node); if (ret < 0) goto dai_link_of_err;
@@ -337,10 +354,10 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, /* DAI link name is created from CPU/CODEC dai name */ name = devm_kzalloc(dev, strlen(dai_link->cpu_dai_name) + - strlen(dai_link->codec_dai_name) + 2, + strlen(dai_link->codecs[0].dai_name) + 2, GFP_KERNEL); sprintf(name, "%s-%s", dai_link->cpu_dai_name, - dai_link->codec_dai_name); + dai_link->codecs[0].dai_name); dai_link->name = dai_link->stream_name = name; dai_link->ops = &asoc_simple_card_ops; dai_link->init = asoc_simple_card_dai_init; @@ -351,7 +368,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, dai_props->cpu_dai.fmt, dai_props->cpu_dai.sysclk); dev_dbg(dev, "\tcodec : %s / %04x / %d\n", - dai_link->codec_dai_name, + dai_link->codecs[0].dai_name, dai_props->codec_dai.fmt, dai_props->codec_dai.sysclk);
@@ -366,8 +383,19 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, */ if (!cpu_args) dai_link->cpu_dai_name = NULL; + goto out;
dai_link_of_err: + for (i = 0, component = dai_link->codecs; + i < dai_link->num_codecs; + i++, component++) { + if (!component->of_node) + break; + of_node_put((struct device_node *) component->of_node); + component->of_node = NULL; + } + +out: of_node_put(np); of_node_put(bitclkmaster); of_node_put(framemaster); @@ -454,16 +482,22 @@ static int asoc_simple_card_unref(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct snd_soc_dai_link *dai_link; + struct snd_soc_dai_link_component *component; struct device_node *np; - int num_links; + int num_links, i;
for (num_links = 0, dai_link = card->dai_link; num_links < card->num_links; num_links++, dai_link++) { np = (struct device_node *) dai_link->cpu_of_node; of_node_put(np); - np = (struct device_node *) dai_link->codec_of_node; - of_node_put(np); + for (i = 0, component = dai_link->codecs; + i < dai_link->num_codecs; + i++, component++) { + if (!component->of_node) + break; + of_node_put((struct device_node *) component->of_node); + } } return 0; }
participants (1)
-
Jean-Francois Moine