#define for_each_component(component) \
list_for_each_entry(component, &component_list, list)
+/*
+ * This is used if driver don't need to have CPU/Codec/Platform
+ * dai_link. see soc.h
+ */
+struct snd_soc_dai_link_component null_dailink_component[0];
+EXPORT_SYMBOL_GPL(null_dailink_component);
+
/*
* This is a timeout to do a DAPM powerdown after a stream is closed().
* It can be used to eliminate pops between different playback streams, e.g.
static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
{
+ if (!card->debugfs_card_root)
+ return;
debugfs_remove_recursive(card->debugfs_card_root);
+ card->debugfs_card_root = NULL;
}
static void snd_soc_debugfs_init(void)
{
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dai_link_component *codecs;
- struct snd_soc_dai_link_component cpu_dai_component;
struct snd_soc_component *component;
int i;
if (!rtd)
return -ENOMEM;
- cpu_dai_component.name = dai_link->cpu_name;
- cpu_dai_component.of_node = dai_link->cpu_of_node;
- cpu_dai_component.dai_name = dai_link->cpu_dai_name;
- rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);
+ /* FIXME: we need multi CPU support in the future */
+ rtd->cpu_dai = snd_soc_find_dai(dai_link->cpus);
if (!rtd->cpu_dai) {
dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
- dai_link->cpu_dai_name);
+ dai_link->cpus->dai_name);
goto _err_defer;
}
snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component);
static void soc_cleanup_component(struct snd_soc_component *component)
{
+ snd_soc_component_set_jack(component, NULL, NULL);
list_del(&component->card_list);
snd_soc_dapm_free(snd_soc_component_get_dapm(component));
soc_cleanup_component_debugfs(component);
struct snd_soc_component *component;
struct snd_soc_rtdcom_list *rtdcom;
+ mutex_lock(&client_mutex);
for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component;
if (component->driver->remove_order == order)
soc_remove_component(component);
}
+ mutex_unlock(&client_mutex);
}
static void soc_remove_dai_links(struct snd_soc_card *card)
}
}
-static int snd_soc_init_platform(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link)
-{
- struct snd_soc_dai_link_component *platform = dai_link->platforms;
-
- /*
- * REMOVE ME
- *
- * This is glue code for Legacy vs Modern dai_link.
- * This function will be removed if all derivers are switched to
- * modern style dai_link.
- * Driver shouldn't use both legacy and modern style in the same time.
- * see
- * soc.h :: struct snd_soc_dai_link
- */
- /* convert Legacy platform link */
- if (!platform) {
- platform = devm_kzalloc(card->dev,
- sizeof(struct snd_soc_dai_link_component),
- GFP_KERNEL);
- if (!platform)
- return -ENOMEM;
-
- dai_link->platforms = platform;
- dai_link->num_platforms = 1;
- dai_link->legacy_platform = 1;
- platform->name = dai_link->platform_name;
- platform->of_node = dai_link->platform_of_node;
- platform->dai_name = NULL;
- }
-
- /* if there's no platform we match on the empty platform */
- if (!platform->name &&
- !platform->of_node)
- platform->name = "snd-soc-dummy";
-
- return 0;
-}
-
-static void soc_cleanup_platform(struct snd_soc_card *card)
-{
- struct snd_soc_dai_link *link;
- int i;
- /*
- * FIXME
- *
- * this function should be removed with snd_soc_init_platform
- */
-
- for_each_card_prelinks(card, i, link) {
- if (link->legacy_platform) {
- link->legacy_platform = 0;
- link->platforms = NULL;
- }
- }
-}
-
-static int snd_soc_init_multicodec(struct snd_soc_card *card,
- struct snd_soc_dai_link *dai_link)
-{
- /*
- * REMOVE ME
- *
- * This is glue code for Legacy vs Modern dai_link.
- * This function will be removed if all derivers are switched to
- * modern style dai_link.
- * Driver shouldn't use both legacy and modern style in the same time.
- * see
- * soc.h :: struct snd_soc_dai_link
- */
-
- /* Legacy codec/codec_dai link is a single entry in multicodec */
- if (dai_link->codec_name || dai_link->codec_of_node ||
- dai_link->codec_dai_name) {
- dai_link->num_codecs = 1;
-
- dai_link->codecs = devm_kzalloc(card->dev,
- sizeof(struct snd_soc_dai_link_component),
- GFP_KERNEL);
- if (!dai_link->codecs)
- return -ENOMEM;
-
- dai_link->codecs[0].name = dai_link->codec_name;
- dai_link->codecs[0].of_node = dai_link->codec_of_node;
- dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
- }
-
- if (!dai_link->codecs) {
- dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
- return -EINVAL;
- }
-
- return 0;
-}
+static struct snd_soc_dai_link_component dummy_link = COMP_DUMMY();
static int soc_init_dai_link(struct snd_soc_card *card,
struct snd_soc_dai_link *link)
{
- int i, ret;
+ int i;
struct snd_soc_dai_link_component *codec;
- ret = snd_soc_init_platform(card, link);
- if (ret) {
- dev_err(card->dev, "ASoC: failed to init multiplatform\n");
- return ret;
- }
-
- ret = snd_soc_init_multicodec(card, link);
- if (ret) {
- dev_err(card->dev, "ASoC: failed to init multicodec\n");
- return ret;
+ /* default Platform */
+ if (!link->platforms || !link->num_platforms) {
+ link->platforms = &dummy_link;
+ link->num_platforms = 1;
}
for_each_link_codecs(link, i, codec) {
!soc_find_component(link->platforms->of_node, link->platforms->name))
return -EPROBE_DEFER;
+ /* FIXME */
+ if (link->num_cpus > 1) {
+ dev_err(card->dev,
+ "ASoC: multi cpu is not yet supported %s\n",
+ link->name);
+ return -EINVAL;
+ }
+
/*
* CPU device may be specified by either name or OF node, but
* can be left unspecified, and will be matched based on DAI
* name alone..
*/
- if (link->cpu_name && link->cpu_of_node) {
+ if (link->cpus->name && link->cpus->of_node) {
dev_err(card->dev,
"ASoC: Neither/both cpu name/of_node are set for %s\n",
link->name);
* Defer card registartion if cpu dai component is not added to
* component list.
*/
- if ((link->cpu_of_node || link->cpu_name) &&
- !soc_find_component(link->cpu_of_node, link->cpu_name))
+ if ((link->cpus->of_node || link->cpus->name) &&
+ !soc_find_component(link->cpus->of_node, link->cpus->name))
return -EPROBE_DEFER;
/*
* At least one of CPU DAI name or CPU device name/node must be
* specified
*/
- if (!link->cpu_dai_name &&
- !(link->cpu_name || link->cpu_of_node)) {
+ if (!link->cpus->dai_name &&
+ !(link->cpus->name || link->cpus->of_node)) {
dev_err(card->dev,
"ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
link->name);
card->dai_link[i].name);
/* override platform component */
- if (snd_soc_init_platform(card, dai_link) < 0) {
+ if (!dai_link->platforms) {
dev_err(card->dev, "init platform error");
continue;
}
static int soc_cleanup_card_resources(struct snd_soc_card *card)
{
/* free the ALSA card at first; this syncs with pending operations */
- if (card->snd_card)
+ if (card->snd_card) {
snd_card_free(card->snd_card);
+ card->snd_card = NULL;
+ }
/* remove and free each DAI */
soc_remove_dai_links(card);
soc_remove_pcm_runtimes(card);
- soc_cleanup_platform(card);
/* remove auxiliary devices */
soc_remove_aux_devices(card);
int ret, i, order;
mutex_lock(&client_mutex);
+ for_each_card_prelinks(card, i, dai_link) {
+ ret = soc_init_dai_link(card, dai_link);
+ if (ret) {
+ soc_cleanup_card_resources(card);
+ dev_err(card->dev, "ASoC: failed to init link %s: %d\n",
+ dai_link->name, ret);
+ mutex_unlock(&client_mutex);
+ return ret;
+ }
+ }
mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
card->dapm.bias_level = SND_SOC_BIAS_OFF;
*/
int snd_soc_register_card(struct snd_soc_card *card)
{
- int i, ret;
- struct snd_soc_dai_link *link;
-
if (!card->name || !card->dev)
return -EINVAL;
- mutex_lock(&client_mutex);
- for_each_card_prelinks(card, i, link) {
-
- ret = soc_init_dai_link(card, link);
- if (ret) {
- soc_cleanup_platform(card);
- dev_err(card->dev, "ASoC: failed to init link %s\n",
- link->name);
- mutex_unlock(&client_mutex);
- return ret;
- }
- }
- mutex_unlock(&client_mutex);
-
dev_set_drvdata(card->dev, card);
snd_soc_initialize_card_lists(card);