diff options
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r-- | sound/soc/soc-core.c | 641 |
1 files changed, 238 insertions, 403 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8ef0efeed0a7..068d809c349a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -45,11 +45,6 @@ #define NAME_SIZE 32 -#ifdef CONFIG_DEBUG_FS -struct dentry *snd_soc_debugfs_root; -EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); -#endif - static DEFINE_MUTEX(client_mutex); static LIST_HEAD(component_list); static LIST_HEAD(unbind_card_list); @@ -73,23 +68,6 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); -#ifdef CONFIG_DMI -/* - * If a DMI filed contain strings in this blacklist (e.g. - * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken - * as invalid and dropped when setting the card long name from DMI info. - */ -static const char * const dmi_blacklist[] = { - "To be filled by OEM", - "TBD by OEM", - "Default String", - "Board Manufacturer", - "Board Vendor Name", - "Board Product Name", - NULL, /* terminator */ -}; -#endif - static ssize_t pmdown_time_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -150,6 +128,9 @@ static const struct attribute_group *soc_dev_attr_groups[] = { }; #ifdef CONFIG_DEBUG_FS +struct dentry *snd_soc_debugfs_root; +EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); + static void soc_init_component_debugfs(struct snd_soc_component *component) { if (!component->card->debugfs_card_root) @@ -277,49 +258,21 @@ static inline void snd_soc_debugfs_exit(void) #endif -/* - * This is glue code between snd_pcm_lib_ioctl() and - * snd_soc_component_driver :: ioctl - */ -int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - return snd_pcm_lib_ioctl(substream, cmd, arg); -} -EXPORT_SYMBOL_GPL(snd_soc_pcm_lib_ioctl); - -static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_component *component) +static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_component *component) { - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *comp; + int i; - for_each_rtd_components(rtd, rtdcom, comp) { + for_each_rtd_components(rtd, i, comp) { /* already connected */ if (comp == component) return 0; } - /* - * created rtdcom here will be freed when rtd->dev was freed. - * see - * soc_free_pcm_runtime() :: device_unregister(rtd->dev) - */ - rtdcom = devm_kzalloc(rtd->dev, sizeof(*rtdcom), GFP_KERNEL); - if (!rtdcom) - return -ENOMEM; - - rtdcom->component = component; - INIT_LIST_HEAD(&rtdcom->list); - - /* - * When rtd was freed, created rtdcom here will be - * also freed. - * And we don't need to call list_del(&rtdcom->list) - * when freed, because rtd is also freed. - */ - list_add_tail(&rtdcom->list, &rtd->component_list); + /* see for_each_rtd_components */ + rtd->components[rtd->num_components] = component; + rtd->num_components++; return 0; } @@ -327,8 +280,8 @@ static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, const char *driver_name) { - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; + int i; if (!driver_name) return NULL; @@ -341,7 +294,7 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, * But, if many components which have same driver name are connected * to 1 rtd, this function will return 1st found component. */ - for_each_rtd_components(rtd, rtdcom, component) { + for_each_rtd_components(rtd, i, component) { const char *component_name = component->driver->name; if (!component_name) @@ -349,7 +302,7 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, if ((component_name == driver_name) || strcmp(component_name, driver_name) == 0) - return rtdcom->component; + return component; } return NULL; @@ -389,22 +342,48 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev, } EXPORT_SYMBOL_GPL(snd_soc_lookup_component); -struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, - const char *dai_link, int stream) +struct snd_soc_pcm_runtime +*snd_soc_get_pcm_runtime(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; for_each_card_rtds(card, rtd) { - if (rtd->dai_link->no_pcm && - !strcmp(rtd->dai_link->name, dai_link)) - return rtd->pcm->streams[stream].substream; + if (rtd->dai_link == dai_link) + return rtd; } - dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link); + dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link->name); return NULL; } -EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); +EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); -static const struct snd_soc_ops null_snd_soc_ops; +/* + * Power down the audio subsystem pmdown_time msecs after close is called. + * This is to ensure there are no pops or clicks in between any music tracks + * due to DAPM power cycling. + */ +void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); + + dev_dbg(rtd->dev, + "ASoC: pop wq checking: %s status: %s waiting: %s\n", + codec_dai->driver->playback.stream_name, + codec_dai->playback_active ? "active" : "inactive", + rtd->pop_wait ? "yes" : "no"); + + /* are we waiting on this codec DAI stream */ + if (rtd->pop_wait == 1) { + rtd->pop_wait = 0; + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, + SND_SOC_DAPM_STREAM_STOP); + } + + mutex_unlock(&rtd->card->pcm_mutex); +} +EXPORT_SYMBOL_GPL(snd_soc_close_delayed_work); static void soc_release_rtd_dev(struct device *dev) { @@ -449,6 +428,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; + struct snd_soc_component *component; struct device *dev; int ret; @@ -474,13 +454,17 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( /* * for rtd */ - rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL); + rtd = devm_kzalloc(dev, + sizeof(*rtd) + + sizeof(*component) * (dai_link->num_cpus + + dai_link->num_codecs + + dai_link->num_platforms), + GFP_KERNEL); if (!rtd) goto free_rtd; rtd->dev = dev; INIT_LIST_HEAD(&rtd->list); - INIT_LIST_HEAD(&rtd->component_list); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients); INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients); @@ -502,8 +486,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( */ rtd->card = card; rtd->dai_link = dai_link; - if (!rtd->dai_link->ops) - rtd->dai_link->ops = &null_snd_soc_ops; /* see for_each_card_rtds */ list_add_tail(&rtd->list, &card->rtd_list); @@ -517,20 +499,6 @@ free_rtd: return NULL; } -struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, - const char *dai_link) -{ - struct snd_soc_pcm_runtime *rtd; - - for_each_card_rtds(card, rtd) { - if (!strcmp(rtd->dai_link->name, dai_link)) - return rtd; - } - dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link); - return NULL; -} -EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); - static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -586,16 +554,6 @@ int snd_soc_suspend(struct device *dev) if (card->suspend_pre) card->suspend_pre(card); - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - if (rtd->dai_link->ignore_suspend) - continue; - - if (!cpu_dai->driver->bus_control) - snd_soc_dai_suspend(cpu_dai); - } - /* close any waiting streams */ snd_soc_flush_all_delayed_work(card); @@ -618,15 +576,25 @@ int snd_soc_suspend(struct device *dev) snd_soc_dapm_sync(&card->dapm); /* suspend all COMPONENTs */ - for_each_card_components(card, component) { - struct snd_soc_dapm_context *dapm = + for_each_card_rtds(card, rtd) { + + if (rtd->dai_link->ignore_suspend) + continue; + + for_each_rtd_components(rtd, i, component) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - /* - * If there are paths active then the COMPONENT will be held - * with bias _ON and should not be suspended. - */ - if (!snd_soc_component_is_suspended(component)) { + /* + * ignore if component was already suspended + */ + if (snd_soc_component_is_suspended(component)) + continue; + + /* + * If there are paths active then the COMPONENT will be + * held with bias _ON and should not be suspended. + */ switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_STANDBY: /* @@ -657,19 +625,6 @@ int snd_soc_suspend(struct device *dev) } } - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - if (rtd->dai_link->ignore_suspend) - continue; - - if (cpu_dai->driver->bus_control) - snd_soc_dai_suspend(cpu_dai); - - /* deactivate pins to sleep state */ - pinctrl_pm_select_sleep_state(cpu_dai->dev); - } - if (card->suspend_post) card->suspend_post(card); @@ -703,17 +658,6 @@ static void soc_resume_deferred(struct work_struct *work) if (card->resume_pre) card->resume_pre(card); - /* resume control bus DAIs */ - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - if (rtd->dai_link->ignore_suspend) - continue; - - if (cpu_dai->driver->bus_control) - snd_soc_dai_resume(cpu_dai); - } - for_each_card_components(card, component) { if (snd_soc_component_is_suspended(component)) snd_soc_component_resume(component); @@ -747,16 +691,6 @@ static void soc_resume_deferred(struct work_struct *work) } } - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - if (rtd->dai_link->ignore_suspend) - continue; - - if (!cpu_dai->driver->bus_control) - snd_soc_dai_resume(cpu_dai); - } - if (card->resume_post) card->resume_post(card); @@ -774,47 +708,20 @@ static void soc_resume_deferred(struct work_struct *work) int snd_soc_resume(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); - bool bus_control = false; - struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai *codec_dai; - int i; + struct snd_soc_component *component; /* If the card is not initialized yet there is nothing to do */ if (!card->instantiated) return 0; /* activate pins from sleep state */ - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - if (cpu_dai->active) - pinctrl_pm_select_default_state(cpu_dai->dev); + for_each_card_components(card, component) + if (component->active) + pinctrl_pm_select_default_state(component->dev); - for_each_rtd_codec_dai(rtd, i, codec_dai) { - if (codec_dai->active) - pinctrl_pm_select_default_state(codec_dai->dev); - } - } - - /* - * DAIs that also act as the control bus master might have other drivers - * hanging off them so need to resume immediately. Other drivers don't - * have that problem and may take a substantial amount of time to resume - * due to I/O costs and anti-pop so handle them out of line. - */ - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - - bus_control |= cpu_dai->driver->bus_control; - } - if (bus_control) { - dev_dbg(dev, "ASoC: Resuming control bus master immediately\n"); - soc_resume_deferred(&card->deferred_resume_work); - } else { - dev_dbg(dev, "ASoC: Scheduling resume work\n"); - if (!schedule_work(&card->deferred_resume_work)) - dev_err(dev, "ASoC: resume work item may be lost\n"); - } + dev_dbg(dev, "ASoC: Scheduling resume work\n"); + if (!schedule_work(&card->deferred_resume_work)) + dev_err(dev, "ASoC: resume work item may be lost\n"); return 0; } @@ -926,47 +833,6 @@ struct snd_soc_dai *snd_soc_find_dai( } EXPORT_SYMBOL_GPL(snd_soc_find_dai); -/** - * snd_soc_find_dai_link - Find a DAI link - * - * @card: soc card - * @id: DAI link ID to match - * @name: DAI link name to match, optional - * @stream_name: DAI link stream name to match, optional - * - * This function will search all existing DAI links of the soc card to - * find the link of the same ID. Since DAI links may not have their - * unique ID, so name and stream name should also match if being - * specified. - * - * Return: pointer of DAI link, or NULL if not found. - */ -struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, - int id, const char *name, - const char *stream_name) -{ - struct snd_soc_dai_link *link; - - lockdep_assert_held(&client_mutex); - - for_each_card_links(card, link) { - if (link->id != id) - continue; - - if (name && (!link->name || strcmp(name, link->name))) - continue; - - if (stream_name && (!link->stream_name - || strcmp(stream_name, link->stream_name))) - continue; - - return link; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(snd_soc_find_dai_link); - static int soc_dai_link_sanity_check(struct snd_soc_card *card, struct snd_soc_dai_link *link) { @@ -1064,49 +930,40 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card, } /** - * snd_soc_remove_dai_link - Remove a DAI link from the list - * @card: The ASoC card that owns the link - * @dai_link: The DAI link to remove + * snd_soc_remove_pcm_runtime - Remove a pcm_runtime from card + * @card: The ASoC card to which the pcm_runtime has + * @rtd: The pcm_runtime to remove * - * This function removes a DAI link from the ASoC card's link list. - * - * For DAI links previously added by topology, topology should - * remove them by using the dobj embedded in the link. + * This function removes a pcm_runtime from the ASoC card. */ -void snd_soc_remove_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link) +void snd_soc_remove_pcm_runtime(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_pcm_runtime *rtd; - lockdep_assert_held(&client_mutex); /* * Notify the machine driver for extra destruction */ if (card->remove_dai_link) - card->remove_dai_link(card, dai_link); - - list_del(&dai_link->list); + card->remove_dai_link(card, rtd->dai_link); - rtd = snd_soc_get_pcm_runtime(card, dai_link->name); - if (rtd) - soc_free_pcm_runtime(rtd); + soc_free_pcm_runtime(rtd); } -EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); +EXPORT_SYMBOL_GPL(snd_soc_remove_pcm_runtime); /** - * snd_soc_add_dai_link - Add a DAI link dynamically - * @card: The ASoC card to which the DAI link is added - * @dai_link: The new DAI link to add + * snd_soc_add_pcm_runtime - Add a pcm_runtime dynamically via dai_link + * @card: The ASoC card to which the pcm_runtime is added + * @dai_link: The DAI link to find pcm_runtime * - * This function adds a DAI link to the ASoC card's link list. + * This function adds a pcm_runtime ASoC card by using dai_link. * - * Note: Topology can use this API to add DAI links when probing the + * Note: Topology can use this API to add pcm_runtime when probing the * topology component. And machine drivers can still define static * DAI links in dai_link array. */ -int snd_soc_add_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link) +int snd_soc_add_pcm_runtime(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codec, *platform; @@ -1141,7 +998,7 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, dai_link->cpus->dai_name); goto _err_defer; } - snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component); + snd_soc_rtd_add_component(rtd, rtd->cpu_dai->component); /* Find CODEC from registered CODECs */ rtd->num_codecs = dai_link->num_codecs; @@ -1153,7 +1010,7 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, goto _err_defer; } - snd_soc_rtdcom_add(rtd, rtd->codec_dais[i]->component); + snd_soc_rtd_add_component(rtd, rtd->codec_dais[i]->component); } /* Single codec links expect codec and codec_dai in runtime data */ @@ -1165,54 +1022,135 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, if (!snd_soc_is_matching_component(platform, component)) continue; - snd_soc_rtdcom_add(rtd, component); + snd_soc_rtd_add_component(rtd, component); } } - /* see for_each_card_links */ - list_add_tail(&dai_link->list, &card->dai_link_list); - return 0; _err_defer: - soc_free_pcm_runtime(rtd); + snd_soc_remove_pcm_runtime(card, rtd); return -EPROBE_DEFER; } -EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); +EXPORT_SYMBOL_GPL(snd_soc_add_pcm_runtime); -static void soc_set_of_name_prefix(struct snd_soc_component *component) +static int soc_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, + struct snd_soc_pcm_runtime *rtd) { - struct device_node *of_node = soc_component_to_node(component); - const char *str; - int ret; + int i, ret = 0; - ret = of_property_read_string(of_node, "sound-name-prefix", &str); - if (!ret) - component->name_prefix = str; + for (i = 0; i < num_dais; ++i) { + struct snd_soc_dai_driver *drv = dais[i]->driver; + + if (drv->pcm_new) + ret = drv->pcm_new(rtd, dais[i]); + if (ret < 0) { + dev_err(dais[i]->dev, + "ASoC: Failed to bind %s with pcm device\n", + dais[i]->name); + return ret; + } + } + + return 0; +} + +static int soc_init_pcm_runtime(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_component *component; + int ret, num, i; + + /* set default power off timeout */ + rtd->pmdown_time = pmdown_time; + + /* do machine specific initialization */ + if (dai_link->init) { + ret = dai_link->init(rtd); + if (ret < 0) { + dev_err(card->dev, "ASoC: failed to init %s: %d\n", + dai_link->name, ret); + return ret; + } + } + + if (dai_link->dai_fmt) { + ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt); + if (ret) + return ret; + } + + /* add DPCM sysfs entries */ + soc_dpcm_debugfs_add(rtd); + + num = rtd->num; + + /* + * most drivers will register their PCMs using DAI link ordering but + * topology based drivers can use the DAI link id field to set PCM + * device number and then use rtd + a base offset of the BEs. + */ + for_each_rtd_components(rtd, i, component) { + if (!component->driver->use_dai_pcm_id) + continue; + + if (rtd->dai_link->no_pcm) + num += component->driver->be_pcm_base; + else + num = rtd->dai_link->id; + } + + /* create compress_device if possible */ + ret = snd_soc_dai_compress_new(cpu_dai, rtd, num); + if (ret != -ENOTSUPP) { + if (ret < 0) + dev_err(card->dev, "ASoC: can't create compress %s\n", + dai_link->stream_name); + return ret; + } + + /* create the pcm */ + ret = soc_new_pcm(rtd, num); + if (ret < 0) { + dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", + dai_link->stream_name, ret); + return ret; + } + ret = soc_dai_pcm_new(&cpu_dai, 1, rtd); + if (ret < 0) + return ret; + ret = soc_dai_pcm_new(rtd->codec_dais, + rtd->num_codecs, rtd); + return ret; } static void soc_set_name_prefix(struct snd_soc_card *card, struct snd_soc_component *component) { - int i; + struct device_node *of_node = soc_component_to_node(component); + const char *str; + int ret, i; - for (i = 0; i < card->num_configs && card->codec_conf; i++) { + for (i = 0; i < card->num_configs; i++) { struct snd_soc_codec_conf *map = &card->codec_conf[i]; - struct device_node *of_node = soc_component_to_node(component); - if (map->of_node && of_node != map->of_node) - continue; - if (map->dev_name && strcmp(component->name, map->dev_name)) - continue; - component->name_prefix = map->name_prefix; - return; + if (snd_soc_is_matching_component(&map->dlc, component)) { + component->name_prefix = map->name_prefix; + return; + } } /* * If there is no configuration table or no match in the table, * check if a prefix is provided in the node */ - soc_set_of_name_prefix(component); + ret = of_property_read_string(of_node, "sound-name-prefix", &str); + if (ret < 0) + return; + + component->name_prefix = str; } static void soc_remove_component(struct snd_soc_component *component, @@ -1419,12 +1357,11 @@ static void soc_remove_link_components(struct snd_soc_card *card) { struct snd_soc_component *component; struct snd_soc_pcm_runtime *rtd; - struct snd_soc_rtdcom_list *rtdcom; - int order; + int i, order; for_each_comp_order(order) { for_each_card_rtds(card, rtd) { - for_each_rtd_components(rtd, rtdcom, component) { + for_each_rtd_components(rtd, i, component) { if (component->driver->remove_order != order) continue; @@ -1438,12 +1375,11 @@ static int soc_probe_link_components(struct snd_soc_card *card) { struct snd_soc_component *component; struct snd_soc_pcm_runtime *rtd; - struct snd_soc_rtdcom_list *rtdcom; - int ret, order; + int i, ret, order; for_each_comp_order(order) { for_each_card_rtds(card, rtd) { - for_each_rtd_components(rtd, rtdcom, component) { + for_each_rtd_components(rtd, i, component) { if (component->driver->probe_order != order) continue; @@ -1457,111 +1393,6 @@ static int soc_probe_link_components(struct snd_soc_card *card) return 0; } -void snd_soc_disconnect_sync(struct device *dev) -{ - struct snd_soc_component *component = - snd_soc_lookup_component(dev, NULL); - - if (!component || !component->card) - return; - - snd_card_disconnect_sync(component->card->snd_card); -} -EXPORT_SYMBOL_GPL(snd_soc_disconnect_sync); - -static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, - struct snd_soc_pcm_runtime *rtd) -{ - int i, ret = 0; - - for (i = 0; i < num_dais; ++i) { - struct snd_soc_dai_driver *drv = dais[i]->driver; - - if (drv->pcm_new) - ret = drv->pcm_new(rtd, dais[i]); - if (ret < 0) { - dev_err(dais[i]->dev, - "ASoC: Failed to bind %s with pcm device\n", - dais[i]->name); - return ret; - } - } - - return 0; -} - -static int soc_link_init(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai_link *dai_link = rtd->dai_link; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_component *component; - int ret, num; - - /* set default power off timeout */ - rtd->pmdown_time = pmdown_time; - - /* do machine specific initialization */ - if (dai_link->init) { - ret = dai_link->init(rtd); - if (ret < 0) { - dev_err(card->dev, "ASoC: failed to init %s: %d\n", - dai_link->name, ret); - return ret; - } - } - - if (dai_link->dai_fmt) { - ret = snd_soc_runtime_set_dai_fmt(rtd, dai_link->dai_fmt); - if (ret) - return ret; - } - - /* add DPCM sysfs entries */ - soc_dpcm_debugfs_add(rtd); - - num = rtd->num; - - /* - * most drivers will register their PCMs using DAI link ordering but - * topology based drivers can use the DAI link id field to set PCM - * device number and then use rtd + a base offset of the BEs. - */ - for_each_rtd_components(rtd, rtdcom, component) { - if (!component->driver->use_dai_pcm_id) - continue; - - if (rtd->dai_link->no_pcm) - num += component->driver->be_pcm_base; - else - num = rtd->dai_link->id; - } - - /* create compress_device if possible */ - ret = snd_soc_dai_compress_new(cpu_dai, rtd, num); - if (ret != -ENOTSUPP) { - if (ret < 0) - dev_err(card->dev, "ASoC: can't create compress %s\n", - dai_link->stream_name); - return ret; - } - - /* create the pcm */ - ret = soc_new_pcm(rtd, num); - if (ret < 0) { - dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", - dai_link->stream_name, ret); - return ret; - } - ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); - if (ret < 0) - return ret; - ret = soc_link_dai_pcm_new(rtd->codec_dais, - rtd->num_codecs, rtd); - return ret; -} - static void soc_unbind_aux_dev(struct snd_soc_card *card) { struct snd_soc_component *component, *_component; @@ -1693,6 +1524,21 @@ EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); #ifdef CONFIG_DMI /* + * If a DMI filed contain strings in this blacklist (e.g. + * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken + * as invalid and dropped when setting the card long name from DMI info. + */ +static const char * const dmi_blacklist[] = { + "To be filled by OEM", + "TBD by OEM", + "Default String", + "Board Manufacturer", + "Board Vendor Name", + "Board Product Name", + NULL, /* terminator */ +}; + +/* * Trim special characters, and replace '-' with '_' since '-' is used to * separate different DMI fields in the card long name. Only number and * alphabet characters and a few separator characters are kept. @@ -1944,7 +1790,7 @@ static void __soc_setup_card_name(char *name, int len, static void soc_cleanup_card_resources(struct snd_soc_card *card, int card_probed) { - struct snd_soc_dai_link *link, *_link; + struct snd_soc_pcm_runtime *rtd, *n; if (card->snd_card) snd_card_disconnect_sync(card->snd_card); @@ -1955,8 +1801,8 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card, soc_remove_link_dais(card); soc_remove_link_components(card); - for_each_card_links_safe(card, link, _link) - snd_soc_remove_dai_link(card, link); + for_each_card_rtds_safe(card, rtd, n) + snd_soc_remove_pcm_runtime(card, rtd); /* remove auxiliary devices */ soc_remove_aux_devices(card); @@ -1995,6 +1841,7 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) static int snd_soc_bind_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; + struct snd_soc_component *component; struct snd_soc_dai_link *dai_link; int ret, i, card_probed = 0; @@ -2014,7 +1861,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) /* add predefined DAI links to the list */ card->num_rtd = 0; for_each_card_prelinks(card, i, dai_link) { - ret = snd_soc_add_dai_link(card, dai_link); + ret = snd_soc_add_pcm_runtime(card, dai_link); if (ret < 0) goto probe_end; } @@ -2075,8 +1922,11 @@ static int snd_soc_bind_card(struct snd_soc_card *card) goto probe_end; } - for_each_card_rtds(card, rtd) - soc_link_init(card, rtd); + for_each_card_rtds(card, rtd) { + ret = soc_init_pcm_runtime(card, rtd); + if (ret < 0) + goto probe_end; + } snd_soc_dapm_link_dai_widgets(card); snd_soc_dapm_connect_dai_link_widgets(card); @@ -2143,17 +1993,9 @@ static int snd_soc_bind_card(struct snd_soc_card *card) snd_soc_dapm_sync(&card->dapm); /* deactivate pins to sleep state */ - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *dai; - - for_each_rtd_codec_dai(rtd, i, dai) { - if (!dai->active) - pinctrl_pm_select_sleep_state(dai->dev); - } - - if (!rtd->cpu_dai->active) - pinctrl_pm_select_sleep_state(rtd->cpu_dai->dev); - } + for_each_card_components(card, component) + if (!component->active) + pinctrl_pm_select_sleep_state(component->dev); probe_end: if (ret < 0) @@ -2199,7 +2041,7 @@ static int soc_remove(struct platform_device *pdev) int snd_soc_poweroff(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); - struct snd_soc_pcm_runtime *rtd; + struct snd_soc_component *component; if (!card->instantiated) return 0; @@ -2213,16 +2055,8 @@ int snd_soc_poweroff(struct device *dev) snd_soc_dapm_shutdown(card); /* deactivate pins to sleep state */ - for_each_card_rtds(card, rtd) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai; - int i; - - pinctrl_pm_select_sleep_state(cpu_dai->dev); - for_each_rtd_codec_dai(rtd, i, codec_dai) { - pinctrl_pm_select_sleep_state(codec_dai->dev); - } - } + for_each_card_components(card, component) + pinctrl_pm_select_sleep_state(component->dev); return 0; } @@ -2406,7 +2240,6 @@ int snd_soc_register_card(struct snd_soc_card *card) INIT_LIST_HEAD(&card->aux_comp_list); INIT_LIST_HEAD(&card->component_dev_list); INIT_LIST_HEAD(&card->list); - INIT_LIST_HEAD(&card->dai_link_list); INIT_LIST_HEAD(&card->rtd_list); INIT_LIST_HEAD(&card->dapm_dirty); INIT_LIST_HEAD(&card->dobj_list); @@ -2511,6 +2344,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); * * @component: The component the DAIs are registered for * @dai_drv: DAI driver to use for the DAI + * @legacy_dai_naming: if %true, use legacy single-name format; + * if %false, use multiple-name format; * * Topology can use this API to register DAIs when probing a component. * These DAIs's widgets will be freed in the card cleanup and the DAIs @@ -3014,7 +2849,7 @@ void snd_soc_of_parse_node_prefix(struct device_node *np, return; } - codec_conf->of_node = of_node; + codec_conf->dlc.of_node = of_node; codec_conf->name_prefix = str; } EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix); |