Skip to content

Commit

Permalink
ASoC: Allow DAI links to be specified using device tree nodes
Browse files Browse the repository at this point in the history
DAI link endpoints and platform (DMA) devices are currently specified
by name. When instantiating sound cards from device tree, it may be more
convenient to refer to these devices by phandle in the device tree, and
for code to describe DAI links using the "struct device_node *"
("of_node") those phandles map to.

This change adds new fields to snd_soc_dai_link which can "name" devices
using of_node, enhances soc_bind_dai_link() to allow binding based on
of_node, and enhances snd_soc_register_card() to ensure that illegal
combinations of name and of_node are not used.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
  • Loading branch information
Stephen Warren authored and Mark Brown committed Dec 22, 2011
1 parent 8215010 commit 5a50496
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 7 deletions.
4 changes: 4 additions & 0 deletions include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ enum snd_soc_bias_level {
SND_SOC_BIAS_ON = 3,
};

struct device_node;
struct snd_jack;
struct snd_soc_card;
struct snd_soc_pcm_stream;
Expand Down Expand Up @@ -703,8 +704,11 @@ struct snd_soc_dai_link {
const char *name; /* Codec name */
const char *stream_name; /* Stream name */
const char *codec_name; /* for multi-codec */
const struct device_node *codec_of_node;
const char *platform_name; /* for multi-platform */
const struct device_node *platform_of_node;
const char *cpu_dai_name;
const struct device_node *cpu_dai_of_node;
const char *codec_dai_name;

unsigned int dai_fmt; /* format to set on init */
Expand Down
64 changes: 57 additions & 7 deletions sound/soc/soc-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,8 +764,13 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
}
/* no, then find CPU DAI from registered DAIs*/
list_for_each_entry(cpu_dai, &dai_list, list) {
if (strcmp(cpu_dai->name, dai_link->cpu_dai_name))
continue;
if (dai_link->cpu_dai_of_node) {
if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
continue;
} else {
if (strcmp(cpu_dai->name, dai_link->cpu_dai_name))
continue;
}

rtd->cpu_dai = cpu_dai;
goto find_codec;
Expand All @@ -781,8 +786,13 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)

/* no, then find CODEC from registered CODECs*/
list_for_each_entry(codec, &codec_list, list) {
if (strcmp(codec->name, dai_link->codec_name))
continue;
if (dai_link->codec_of_node) {
if (codec->dev->of_node != dai_link->codec_of_node)
continue;
} else {
if (strcmp(codec->name, dai_link->codec_name))
continue;
}

rtd->codec = codec;

Expand Down Expand Up @@ -814,13 +824,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)

/* if there's no platform we match on the empty platform */
platform_name = dai_link->platform_name;
if (!platform_name)
if (!platform_name && !dai_link->platform_of_node)
platform_name = "snd-soc-dummy";

/* no, then find one from the set of registered platforms */
list_for_each_entry(platform, &platform_list, list) {
if (strcmp(platform->name, platform_name))
continue;
if (dai_link->platform_of_node) {
if (platform->dev->of_node !=
dai_link->platform_of_node)
continue;
} else {
if (strcmp(platform->name, platform_name))
continue;
}

rtd->platform = platform;
goto out;
Expand Down Expand Up @@ -2831,6 +2847,40 @@ int snd_soc_register_card(struct snd_soc_card *card)
if (!card->name || !card->dev)
return -EINVAL;

for (i = 0; i < card->num_links; i++) {
struct snd_soc_dai_link *link = &card->dai_link[i];

/*
* Codec must be specified by 1 of name or OF node,
* not both or neither.
*/
if (!!link->codec_name == !!link->codec_of_node) {
dev_err(card->dev,
"Neither/both codec name/of_node are set\n");
return -EINVAL;
}

/*
* Platform may be specified by either name or OF node, but
* can be left unspecified, and a dummy platform will be used.
*/
if (link->platform_name && link->platform_of_node) {
dev_err(card->dev,
"Both platform name/of_node are set\n");
return -EINVAL;
}

/*
* CPU DAI must be specified by 1 of name or OF node,
* not both or neither.
*/
if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) {
dev_err(card->dev,
"Neither/both cpu_dai name/of_node are set\n");
return -EINVAL;
}
}

dev_set_drvdata(card->dev, card);

snd_soc_initialize_card_lists(card);
Expand Down

0 comments on commit 5a50496

Please sign in to comment.