From 3de7c420a2b1737844d893cbfc689a9b2b5528cd Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 9 Nov 2015 23:19:58 +0530 Subject: ASoC: core: refactor soc_link_dai_widgets() In soc_link_dai_widgets() we refer to local widget variables as playback/capture_widget, but they are really sink/source widgets, so change the names accordingly Suggested-by: Mark Brown Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 24b096066a07..d5e0bcbafb70 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1283,35 +1283,35 @@ static int soc_link_dai_widgets(struct snd_soc_card *card, { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dapm_widget *play_w, *capture_w; + struct snd_soc_dapm_widget *sink, *source; int ret; if (rtd->num_codecs > 1) dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); /* link the DAI widgets */ - play_w = codec_dai->playback_widget; - capture_w = cpu_dai->capture_widget; - if (play_w && capture_w) { + sink = codec_dai->playback_widget; + source = cpu_dai->capture_widget; + if (sink && source) { ret = snd_soc_dapm_new_pcm(card, dai_link->params, - dai_link->num_params, capture_w, - play_w); + dai_link->num_params, + source, sink); if (ret != 0) { dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); + sink->name, source->name, ret); return ret; } } - play_w = cpu_dai->playback_widget; - capture_w = codec_dai->capture_widget; - if (play_w && capture_w) { + sink = cpu_dai->playback_widget; + source = codec_dai->capture_widget; + if (sink && source) { ret = snd_soc_dapm_new_pcm(card, dai_link->params, - dai_link->num_params, capture_w, - play_w); + dai_link->num_params, + source, sink); if (ret != 0) { dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); + sink->name, source->name, ret); return ret; } } -- cgit v1.2.3 From 1a497983a5ae62b4970187183fb3b40e68515a24 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 18 Nov 2015 02:34:11 -0500 Subject: ASoC: Change the PCM runtime array to a list Currently the number of DAI links is statically defined by the machine driver at build time using an array. This makes it difficult to shrink/ grow the number of DAI links at runtime in order to reflect any changes in topology. We can change the DAI link array in the core to a list so that PCMs and FE DAI links can be added and deleted at runtime to reflect changes in use case and DSP topology. The machine driver can still register DAI links as an array. As the 1st step, this patch change the PCM runtime array to a list. A new PCM runtime is added to the list when a DAI link is bound successfully. Later patches will further implement the DAI link list. More: - define snd_soc_new/free_pcm_runtime() to create/free a runtime. - define soc_add_pcm_runtime() to add a runtime to the rtd list. - define soc_remove_pcm_runtimes() to clean up the runtime list. - traverse the rtd list to probe the link components and dais. - Add a field "num" to PCM runtime struct, used to specify the device number when creating the pcm device, and for a soc card to access its dai_props array. - The following 3rd party machine/platform drivers iterate the rtd list to check the runtimes: sound/soc/intel/atom/sst-mfld-platform-pcm.c sound/soc/intel/boards/cht_bsw_rt5645.c sound/soc/intel/boards/cht_bsw_rt5672.c sound/soc/intel/boards/cht_bsw_max98090_ti.c Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +- sound/soc/generic/simple-card.c | 12 +- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 12 +- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 7 +- sound/soc/intel/boards/cht_bsw_rt5645.c | 7 +- sound/soc/intel/boards/cht_bsw_rt5672.c | 7 +- sound/soc/sh/rcar/core.c | 2 +- sound/soc/sh/rcar/rsrc-card.c | 6 +- sound/soc/soc-core.c | 263 ++++++++++++++++----------- sound/soc/soc-dapm.c | 7 +- sound/soc/soc-pcm.c | 22 +-- 11 files changed, 191 insertions(+), 159 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/include/sound/soc.h b/include/sound/soc.h index a8b4b9c8b1d2..232b30d3fa68 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1106,7 +1106,7 @@ struct snd_soc_card { /* CPU <--> Codec DAI links */ struct snd_soc_dai_link *dai_link; int num_links; - struct snd_soc_pcm_runtime *rtd; + struct list_head rtd_list; int num_rtd; /* optional codec specific configuration */ @@ -1201,6 +1201,9 @@ struct snd_soc_pcm_runtime { struct dentry *debugfs_dpcm_root; struct dentry *debugfs_dpcm_state; #endif + + unsigned int num; /* 0-based and monotonic increasing */ + struct list_head list; /* rtd list of the soc card */ }; /* mixer control */ diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 54c33204541f..1ded8811598e 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -45,7 +45,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; + &priv->dai_props[rtd->num]; int ret; ret = clk_prepare_enable(dai_props->cpu_dai.clk); @@ -64,7 +64,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; + &priv->dai_props[rtd->num]; clk_disable_unprepare(dai_props->cpu_dai.clk); @@ -78,8 +78,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; + struct simple_dai_props *dai_props = &priv->dai_props[rtd->num]; unsigned int mclk, mclk_fs = 0; int ret = 0; @@ -174,10 +173,9 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; struct simple_dai_props *dai_props; - int num, ret; + int ret; - num = rtd - rtd->card->rtd; - dai_props = &priv->dai_props[num]; + dai_props = &priv->dai_props[rtd->num]; ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai); if (ret < 0) return ret; diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 0487cfaac538..8e475e823205 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -760,15 +760,15 @@ static int sst_platform_remove(struct platform_device *pdev) static int sst_soc_prepare(struct device *dev) { struct sst_data *drv = dev_get_drvdata(dev); - int i; + struct snd_soc_pcm_runtime *rtd; /* suspend all pcms first */ snd_soc_suspend(drv->soc_card->dev); snd_soc_poweroff(drv->soc_card->dev); /* set the SSPs to idle */ - for (i = 0; i < drv->soc_card->num_rtd; i++) { - struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { send_ssp_cmd(dai, dai->name, 0); @@ -782,11 +782,11 @@ static int sst_soc_prepare(struct device *dev) static void sst_soc_complete(struct device *dev) { struct sst_data *drv = dev_get_drvdata(dev); - int i; + struct snd_soc_pcm_runtime *rtd; /* restart SSPs */ - for (i = 0; i < drv->soc_card->num_rtd; i++) { - struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { sst_handle_vb_timer(dai, true); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 4e2fcf188dd1..e36dad302bed 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -41,12 +41,9 @@ struct cht_mc_private { static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; - - rtd = card->rtd + i; + list_for_each_entry(rtd, &card->rtd_list, list) { if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, strlen(CHT_CODEC_DAI))) return rtd->codec_dai; diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 38d65a3529c4..1d2525a53bff 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -47,12 +47,9 @@ struct cht_mc_private { static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { - int i; - - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; + struct snd_soc_pcm_runtime *rtd; - rtd = card->rtd + i; + list_for_each_entry(rtd, &card->rtd_list, list) { if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, strlen(CHT_CODEC_DAI))) return rtd->codec_dai; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 5621ccd92992..77fb3c419ca4 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -46,12 +46,9 @@ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; - - rtd = card->rtd + i; + list_for_each_entry(rtd, &card->rtd_list, list) { if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, strlen(CHT_CODEC_DAI))) return rtd->codec_dai; diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index deed48ef28b8..8c4f54b0cb92 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1040,7 +1040,7 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = name, .info = rsnd_kctrl_info, - .index = rtd - soc_card->rtd, + .index = rtd->num, .get = rsnd_kctrl_get, .put = rsnd_kctrl_put, .private_value = (unsigned long)cfg, diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index d61db9c385ea..94d23d8f2869 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -75,7 +75,7 @@ static int rsrc_card_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct rsrc_card_dai *dai_props = - rsrc_priv_to_props(priv, rtd - rtd->card->rtd); + rsrc_priv_to_props(priv, rtd->num); return clk_prepare_enable(dai_props->clk); } @@ -85,7 +85,7 @@ static void rsrc_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct rsrc_card_dai *dai_props = - rsrc_priv_to_props(priv, rtd - rtd->card->rtd); + rsrc_priv_to_props(priv, rtd->num); clk_disable_unprepare(dai_props->clk); } @@ -101,7 +101,7 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *dai; struct snd_soc_dai_link *dai_link; struct rsrc_card_dai *dai_props; - int num = rtd - rtd->card->rtd; + int num = rtd->num; int ret; dai_link = rsrc_priv_to_link(priv, num); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 24b096066a07..2c95de723d8f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -537,26 +537,75 @@ static inline void snd_soc_debugfs_exit(void) struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, const char *dai_link, int stream) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_links; i++) { - if (card->rtd[i].dai_link->no_pcm && - !strcmp(card->rtd[i].dai_link->name, dai_link)) - return card->rtd[i].pcm->streams[stream].substream; + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->dai_link->no_pcm && + !strcmp(rtd->dai_link->name, dai_link)) + return rtd->pcm->streams[stream].substream; } dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link); return NULL; } EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); +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; + + rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); + if (!rtd) + return NULL; + + rtd->card = card; + rtd->dai_link = dai_link; + rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) * + dai_link->num_codecs, + GFP_KERNEL); + if (!rtd->codec_dais) { + kfree(rtd); + return NULL; + } + + return rtd; +} + +static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) +{ + if (rtd && rtd->codec_dais) + kfree(rtd->codec_dais); + kfree(rtd); +} + +static void soc_add_pcm_runtime(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd) +{ + list_add_tail(&rtd->list, &card->rtd_list); + rtd->num = card->num_rtd; + card->num_rtd++; +} + +static void soc_remove_pcm_runtimes(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd, *_rtd; + + list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) { + list_del(&rtd->list); + soc_free_pcm_runtime(rtd); + } + + card->num_rtd = 0; +} + struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, const char *dai_link) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_links; i++) { - if (!strcmp(card->rtd[i].dai_link->name, dai_link)) - return &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { + 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; @@ -578,7 +627,8 @@ int snd_soc_suspend(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); struct snd_soc_codec *codec; - int i, j; + struct snd_soc_pcm_runtime *rtd; + int i; /* If the card is not initialized yet there is nothing to do */ if (!card->instantiated) @@ -595,13 +645,13 @@ int snd_soc_suspend(struct device *dev) snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); /* mute any active DACs */ - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - for (j = 0; j < card->rtd[i].num_codecs; j++) { - struct snd_soc_dai *dai = card->rtd[i].codec_dais[j]; + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *dai = rtd->codec_dais[i]; struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -610,20 +660,20 @@ int snd_soc_suspend(struct device *dev) } /* suspend all pcms */ - for (i = 0; i < card->num_rtd; i++) { - if (card->rtd[i].dai_link->ignore_suspend) + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->dai_link->ignore_suspend) continue; - snd_pcm_suspend_all(card->rtd[i].pcm); + snd_pcm_suspend_all(rtd->pcm); } if (card->suspend_pre) card->suspend_pre(card); - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) @@ -631,19 +681,19 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - for (i = 0; i < card->num_rtd; i++) - flush_delayed_work(&card->rtd[i].delayed_work); + list_for_each_entry(rtd, &card->rtd_list, list) + flush_delayed_work(&rtd->delayed_work); - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_SUSPEND); - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, SND_SOC_DAPM_STREAM_SUSPEND); } @@ -690,10 +740,10 @@ int snd_soc_suspend(struct device *dev) } } - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) @@ -717,8 +767,9 @@ static void soc_resume_deferred(struct work_struct *work) { struct snd_soc_card *card = container_of(work, struct snd_soc_card, deferred_resume_work); + struct snd_soc_pcm_runtime *rtd; struct snd_soc_codec *codec; - int i, j; + int i; /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, * so userspace apps are blocked from touching us @@ -733,10 +784,10 @@ static void soc_resume_deferred(struct work_struct *work) card->resume_pre(card); /* resume control bus DAIs */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) @@ -751,28 +802,28 @@ static void soc_resume_deferred(struct work_struct *work) } } - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_RESUME); - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, SND_SOC_DAPM_STREAM_RESUME); } /* unmute any active DACs */ - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - for (j = 0; j < card->rtd[i].num_codecs; j++) { - struct snd_soc_dai *dai = card->rtd[i].codec_dais[j]; + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *dai = rtd->codec_dais[i]; struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -780,10 +831,10 @@ static void soc_resume_deferred(struct work_struct *work) } } - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) @@ -808,15 +859,14 @@ int snd_soc_resume(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); bool bus_control = false; - int i; + struct snd_soc_pcm_runtime *rtd; /* If the card is not initialized yet there is nothing to do */ if (!card->instantiated) return 0; /* activate pins from sleep state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; @@ -837,8 +887,8 @@ int snd_soc_resume(struct device *dev) * 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 (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; bus_control |= cpu_dai->driver->bus_control; } if (bus_control) { @@ -913,16 +963,20 @@ static struct snd_soc_dai *snd_soc_find_dai( static int soc_bind_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; + struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; - struct snd_soc_dai **codec_dais = rtd->codec_dais; + struct snd_soc_dai **codec_dais; struct snd_soc_platform *platform; const char *platform_name; int i; dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); + rtd = soc_new_pcm_runtime(card, dai_link); + 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; @@ -930,18 +984,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) if (!rtd->cpu_dai) { dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); - return -EPROBE_DEFER; + goto _err_defer; } rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + codec_dais = rtd->codec_dais; for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", codecs[i].dai_name); - return -EPROBE_DEFER; + goto _err_defer; } } @@ -973,9 +1028,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) return -EPROBE_DEFER; } - card->num_rtd++; - + soc_add_pcm_runtime(card, rtd); return 0; + +_err_defer: + soc_free_pcm_runtime(rtd); + return -EPROBE_DEFER; } static void soc_remove_component(struct snd_soc_component *component) @@ -1014,9 +1072,9 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) } } -static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) +static void soc_remove_link_dais(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; int i; /* unregister the rtd device */ @@ -1032,10 +1090,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) soc_remove_dai(rtd->cpu_dai, order); } -static void soc_remove_link_components(struct snd_soc_card *card, int num, - int order) +static void soc_remove_link_components(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_component *component; @@ -1061,21 +1118,20 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, static void soc_remove_dai_links(struct snd_soc_card *card) { - int dai, order; + int order; + struct snd_soc_pcm_runtime *rtd; for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (dai = 0; dai < card->num_rtd; dai++) - soc_remove_link_dais(card, dai, order); + list_for_each_entry(rtd, &card->rtd_list, list) + soc_remove_link_dais(card, rtd, order); } for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (dai = 0; dai < card->num_rtd; dai++) - soc_remove_link_components(card, dai, order); + list_for_each_entry(rtd, &card->rtd_list, list) + soc_remove_link_components(card, rtd, order); } - - card->num_rtd = 0; } static void soc_set_name_prefix(struct snd_soc_card *card, @@ -1220,10 +1276,10 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, return 0; } -static int soc_probe_link_components(struct snd_soc_card *card, int num, +static int soc_probe_link_components(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_component *component; int i, ret; @@ -1319,15 +1375,15 @@ static int soc_link_dai_widgets(struct snd_soc_card *card, return 0; } -static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) +static int soc_probe_link_dais(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_dai_link *dai_link = &card->dai_link[num]; - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; + struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int i, ret; dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", - card->name, num, order); + card->name, rtd->num, order); /* set default power off timeout */ rtd->pmdown_time = pmdown_time; @@ -1372,7 +1428,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (cpu_dai->driver->compress_new) { /*create compress_device"*/ - ret = cpu_dai->driver->compress_new(rtd, num); + ret = cpu_dai->driver->compress_new(rtd, rtd->num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create compress %s\n", dai_link->stream_name); @@ -1382,7 +1438,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (!dai_link->params) { /* create the pcm */ - ret = soc_new_pcm(rtd, num); + ret = soc_new_pcm(rtd, rtd->num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", dai_link->stream_name, ret); @@ -1552,6 +1608,7 @@ EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_codec *codec; + struct snd_soc_pcm_runtime *rtd; int ret, i, order; mutex_lock(&client_mutex); @@ -1624,8 +1681,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all components used by DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (i = 0; i < card->num_links; i++) { - ret = soc_probe_link_components(card, i, order); + list_for_each_entry(rtd, &card->rtd_list, list) { + ret = soc_probe_link_components(card, rtd, order); if (ret < 0) { dev_err(card->dev, "ASoC: failed to instantiate card %d\n", @@ -1638,8 +1695,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (i = 0; i < card->num_links; i++) { - ret = soc_probe_link_dais(card, i, order); + list_for_each_entry(rtd, &card->rtd_list, list) { + ret = soc_probe_link_dais(card, rtd, order); if (ret < 0) { dev_err(card->dev, "ASoC: failed to instantiate card %d\n", @@ -1733,6 +1790,7 @@ card_probe_error: snd_card_free(card->snd_card); base_error: + soc_remove_pcm_runtimes(card); mutex_unlock(&card->mutex); mutex_unlock(&client_mutex); @@ -1763,13 +1821,12 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { + struct snd_soc_pcm_runtime *rtd; int i; /* make sure any delayed work runs */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); - } /* remove auxiliary devices */ for (i = 0; i < card->num_aux_devs; i++) @@ -1777,6 +1834,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove and free each DAI */ soc_remove_dai_links(card); + soc_remove_pcm_runtimes(card); soc_cleanup_card_debugfs(card); @@ -1803,29 +1861,26 @@ static int soc_remove(struct platform_device *pdev) int snd_soc_poweroff(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); - int i; + struct snd_soc_pcm_runtime *rtd; if (!card->instantiated) return 0; /* Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); - } snd_soc_dapm_shutdown(card); /* deactivate pins to sleep state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int j; + int i; pinctrl_pm_select_sleep_state(cpu_dai->dev); - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; pinctrl_pm_select_sleep_state(codec_dai->dev); } } @@ -2337,6 +2392,7 @@ static int snd_soc_init_multicodec(struct snd_soc_card *card, int snd_soc_register_card(struct snd_soc_card *card) { int i, j, ret; + struct snd_soc_pcm_runtime *rtd; if (!card->name || !card->dev) return -EINVAL; @@ -2408,25 +2464,15 @@ int snd_soc_register_card(struct snd_soc_card *card) snd_soc_initialize_card_lists(card); - card->rtd = devm_kzalloc(card->dev, + INIT_LIST_HEAD(&card->rtd_list); + card->num_rtd = 0; + + card->rtd_aux = devm_kzalloc(card->dev, sizeof(struct snd_soc_pcm_runtime) * - (card->num_links + card->num_aux_devs), + card->num_aux_devs, GFP_KERNEL); - if (card->rtd == NULL) + if (card->rtd_aux == NULL) return -ENOMEM; - card->num_rtd = 0; - card->rtd_aux = &card->rtd[card->num_links]; - - for (i = 0; i < card->num_links; i++) { - card->rtd[i].card = card; - card->rtd[i].dai_link = &card->dai_link[i]; - card->rtd[i].codec_dais = devm_kzalloc(card->dev, - sizeof(struct snd_soc_dai *) * - (card->rtd[i].dai_link->num_codecs), - GFP_KERNEL); - if (card->rtd[i].codec_dais == NULL) - return -ENOMEM; - } for (i = 0; i < card->num_aux_devs; i++) card->rtd_aux[i].card = card; @@ -2442,8 +2488,7 @@ int snd_soc_register_card(struct snd_soc_card *card) return ret; /* deactivate pins to sleep state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 016eba10b1ec..3eba72c6f9dd 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3893,13 +3893,10 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = card->rtd; - int i; + struct snd_soc_pcm_runtime *rtd; /* for each BE DAI link... */ - for (i = 0; i < card->num_rtd; i++) { - rtd = &card->rtd[i]; - + list_for_each_entry(rtd, &card->rtd_list, list) { /* * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c86dc96e8986..bbeaa87a36f4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1213,11 +1213,10 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, struct snd_soc_dapm_widget *widget, int stream) { struct snd_soc_pcm_runtime *be; - int i, j; + int i; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < card->num_links; i++) { - be = &card->rtd[i]; + list_for_each_entry(be, &card->rtd_list, list) { if (!be->dai_link->no_pcm) continue; @@ -1225,16 +1224,15 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->playback_widget == widget) return be; - for (j = 0; j < be->num_codecs; j++) { - struct snd_soc_dai *dai = be->codec_dais[j]; + for (i = 0; i < be->num_codecs; i++) { + struct snd_soc_dai *dai = be->codec_dais[i]; if (dai->playback_widget == widget) return be; } } } else { - for (i = 0; i < card->num_links; i++) { - be = &card->rtd[i]; + list_for_each_entry(be, &card->rtd_list, list) { if (!be->dai_link->no_pcm) continue; @@ -1242,8 +1240,8 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->capture_widget == widget) return be; - for (j = 0; j < be->num_codecs; j++) { - struct snd_soc_dai *dai = be->codec_dais[j]; + for (i = 0; i < be->num_codecs; i++) { + struct snd_soc_dai *dai = be->codec_dais[i]; if (dai->capture_widget == widget) return be; } @@ -2343,12 +2341,12 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) */ int soc_dpcm_runtime_update(struct snd_soc_card *card) { - int i, old, new, paths; + struct snd_soc_pcm_runtime *fe; + int old, new, paths; mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(fe, &card->rtd_list, list) { struct snd_soc_dapm_widget_list *list; - struct snd_soc_pcm_runtime *fe = &card->rtd[i]; /* make sure link is FE */ if (!fe->dai_link->dynamic) -- cgit v1.2.3 From 923c5e61ecd9b0ca006a7707583287439f36c2e9 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Mon, 23 Nov 2015 11:01:49 -0500 Subject: ASoC: Define soc_init_dai_link() to wrap link intialization. Define soc_init_dai_link() to wrap link initialization, to reuse it later by snd_soc_instantiate_card() when adding new DAI links from topology in component probing phase. Move static func snd_soc_init_multicodec(), so that it can be reused by soc_init_dai_link(). This saves adding a function declaration for snd_soc_init_multicodec(). Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 181 ++++++++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 83 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2c95de723d8f..2ecd09475d88 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1134,6 +1134,100 @@ static void soc_remove_dai_links(struct snd_soc_card *card) } } +static int snd_soc_init_multicodec(struct snd_soc_card *card, + struct snd_soc_dai_link *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 int soc_init_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link) +{ + int i, ret; + + ret = snd_soc_init_multicodec(card, link); + if (ret) { + dev_err(card->dev, "ASoC: failed to init multicodec\n"); + return ret; + } + + for (i = 0; i < link->num_codecs; i++) { + /* + * Codec must be specified by 1 of name or OF node, + * not both or neither. + */ + if (!!link->codecs[i].name == + !!link->codecs[i].of_node) { + dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + /* Codec DAI name must be specified */ + if (!link->codecs[i].dai_name) { + dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", + link->name); + 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, + "ASoC: Both platform name/of_node are set for %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) { + dev_err(card->dev, + "ASoC: Neither/both cpu name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + /* + * 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)) { + dev_err(card->dev, + "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + + return 0; +} + static void soc_set_name_prefix(struct snd_soc_card *card, struct snd_soc_component *component) { @@ -2356,33 +2450,6 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); -static int snd_soc_init_multicodec(struct snd_soc_card *card, - struct snd_soc_dai_link *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; -} - /** * snd_soc_register_card - Register a card with the ASoC core * @@ -2391,7 +2458,7 @@ static int snd_soc_init_multicodec(struct snd_soc_card *card, */ int snd_soc_register_card(struct snd_soc_card *card) { - int i, j, ret; + int i, ret; struct snd_soc_pcm_runtime *rtd; if (!card->name || !card->dev) @@ -2400,63 +2467,11 @@ int snd_soc_register_card(struct snd_soc_card *card) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai_link *link = &card->dai_link[i]; - ret = snd_soc_init_multicodec(card, link); + ret = soc_init_dai_link(card, link); if (ret) { - dev_err(card->dev, "ASoC: failed to init multicodec\n"); - return ret; - } - - for (j = 0; j < link->num_codecs; j++) { - /* - * Codec must be specified by 1 of name or OF node, - * not both or neither. - */ - if (!!link->codecs[j].name == - !!link->codecs[j].of_node) { - dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - /* Codec DAI name must be specified */ - if (!link->codecs[j].dai_name) { - dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", - link->name); - 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, - "ASoC: Both platform name/of_node are set for %s\n", + dev_err(card->dev, "ASoC: failed to init link %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) { - dev_err(card->dev, - "ASoC: Neither/both cpu name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - /* - * 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)) { - dev_err(card->dev, - "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", - link->name); - return -EINVAL; + return ret; } } -- cgit v1.2.3 From 6f2f1ff0de83ad69f5a823ae77d1e0f77cc75d45 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Mon, 23 Nov 2015 11:03:52 -0500 Subject: ASoC: Change 2nd argument of soc_bind_dai_link() to DAI link pointer Just code refactoring, to reuse it if new DAI Links are added later based on topology in component probing phase. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2ecd09475d88..878a9fe92686 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -960,9 +960,9 @@ static struct snd_soc_dai *snd_soc_find_dai( return NULL; } -static int soc_bind_dai_link(struct snd_soc_card *card, int num) +static int soc_bind_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link *dai_link = &card->dai_link[num]; struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; @@ -971,7 +971,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) const char *platform_name; int i; - dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); + dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name); rtd = soc_new_pcm_runtime(card, dai_link); if (!rtd) @@ -1710,7 +1710,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* bind DAIs */ for (i = 0; i < card->num_links; i++) { - ret = soc_bind_dai_link(card, i); + ret = soc_bind_dai_link(card, &card->dai_link[i]); if (ret != 0) goto base_error; } -- cgit v1.2.3 From f8f80361d07d503093940097e967a7edaa134ca2 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 2 Dec 2015 14:11:22 +0800 Subject: ASoC: Implement DAI links in a list & define API to add/remove a link Implement a dai link list for the soc card. Add APIs to add/remove a DAI links dynamically, e.g. by topology. And a dobj is embedded into the struct snd_soc_dai_link. Topology can use the dobj to find the links created by it and remove them when the topology component is unloaded. The predefined DAI links are reserved to keep backward compatibility. And they will also be added to the list. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc.h | 15 ++++++++-- sound/soc/soc-core.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/include/sound/soc.h b/include/sound/soc.h index 232b30d3fa68..410cb0b422be 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1037,6 +1037,9 @@ struct snd_soc_dai_link { /* pmdown_time is ignored at stop */ unsigned int ignore_pmdown_time:1; + + struct list_head list; /* DAI link list of the soc card */ + struct snd_soc_dobj dobj; /* For topology */ }; struct snd_soc_codec_conf { @@ -1104,8 +1107,11 @@ struct snd_soc_card { long pmdown_time; /* CPU <--> Codec DAI links */ - struct snd_soc_dai_link *dai_link; - int num_links; + struct snd_soc_dai_link *dai_link; /* predefined links only */ + int num_links; /* predefined links only */ + struct list_head dai_link_list; /* all links */ + int num_dai_links; + struct list_head rtd_list; int num_rtd; @@ -1647,6 +1653,11 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, struct device_node *of_node, struct snd_soc_dai_link *dai_link); +int snd_soc_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link); +void snd_soc_remove_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link); + #include #ifdef CONFIG_DEBUG_FS diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 878a9fe92686..bf4bccfc4b91 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1120,6 +1120,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) { int order; struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai_link *link, *_link; for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { @@ -1132,6 +1133,15 @@ static void soc_remove_dai_links(struct snd_soc_card *card) list_for_each_entry(rtd, &card->rtd_list, list) soc_remove_link_components(card, rtd, order); } + + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) + dev_warn(card->dev, "Topology forgot to remove link %s?\n", + link->name); + + list_del(&link->list); + card->num_dai_links--; + } } static int snd_soc_init_multicodec(struct snd_soc_card *card, @@ -1228,6 +1238,68 @@ static int soc_init_dai_link(struct snd_soc_card *card, return 0; } +/** + * 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 + * + * This function adds a DAI link to the ASoC card's link list. + * + * Note: Topology can use this API to add DAI links 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) +{ + if (dai_link->dobj.type + && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { + dev_err(card->dev, "Invalid dai link type %d\n", + dai_link->dobj.type); + return -EINVAL; + } + + lockdep_assert_held(&client_mutex); + list_add_tail(&dai_link->list, &card->dai_link_list); + card->num_dai_links++; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); + +/** + * 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 + * + * 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. + */ +void snd_soc_remove_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_dai_link *link, *_link; + + if (dai_link->dobj.type + && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { + dev_err(card->dev, "Invalid dai link type %d\n", + dai_link->dobj.type); + return; + } + + lockdep_assert_held(&client_mutex); + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + if (link == dai_link) { + list_del(&link->list); + card->num_dai_links--; + return; + } + } +} +EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); + static void soc_set_name_prefix(struct snd_soc_card *card, struct snd_soc_component *component) { @@ -1722,6 +1794,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) goto base_error; } + /* add predefined DAI links to the list */ + for (i = 0; i < card->num_links; i++) + snd_soc_add_dai_link(card, card->dai_link+i); + /* initialize the register cache for each available codec */ list_for_each_entry(codec, &codec_list, list) { if (codec->cache_init) @@ -2479,6 +2555,9 @@ int snd_soc_register_card(struct snd_soc_card *card) snd_soc_initialize_card_lists(card); + INIT_LIST_HEAD(&card->dai_link_list); + card->num_dai_links = 0; + INIT_LIST_HEAD(&card->rtd_list); card->num_rtd = 0; -- cgit v1.2.3 From d6f220ea13edfd3430fb42e09ff92e321ffb5762 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 2 Dec 2015 14:11:32 +0800 Subject: ASoC: Define add/remove_dai_link ops for a soc card A machine driver can register the two ops. When a DAI link is added or removed by a component's topology, the ASoC core can call the ops to notify the machine driver for extra intialization or destruction. E.g. topology can create FE DAI links from a cpu DAI component, and the machine driver may define an add_dai_link ops to set machine-specific .init ops for the DAI link. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 12 ++++++++++++ 2 files changed, 17 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/include/sound/soc.h b/include/sound/soc.h index 410cb0b422be..af347bcdc2f6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1104,6 +1104,11 @@ struct snd_soc_card { struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); + int (*add_dai_link)(struct snd_soc_card *, + struct snd_soc_dai_link *link); + void (*remove_dai_link)(struct snd_soc_card *, + struct snd_soc_dai_link *link); + long pmdown_time; /* CPU <--> Codec DAI links */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bf4bccfc4b91..094856fa8cec 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1260,6 +1260,12 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, } lockdep_assert_held(&client_mutex); + /* Notify the machine driver for extra initialization + * on the link created by topology. + */ + if (dai_link->dobj.type && card->add_dai_link) + card->add_dai_link(card, dai_link); + list_add_tail(&dai_link->list, &card->dai_link_list); card->num_dai_links++; @@ -1290,6 +1296,12 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, } lockdep_assert_held(&client_mutex); + /* Notify the machine driver for extra destruction + * on the link created by topology. + */ + if (dai_link->dobj.type && card->remove_dai_link) + card->remove_dai_link(card, dai_link); + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { if (link == dai_link) { list_del(&link->list); -- cgit v1.2.3 From 49a5ba1cd9da4fb04e7ce1e0d94f6a5a9b7be48e Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 2 Dec 2015 14:11:40 +0800 Subject: ASoC: soc_bind_dai_link() directly returns success for a bound DAI link This function will return success immediately for a bound DAI link. No need to look for the cpu/codec DAIs again. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 094856fa8cec..11d073b6ce33 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -960,6 +960,19 @@ static struct snd_soc_dai *snd_soc_find_dai( return NULL; } +static bool soc_is_dai_link_bound(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->dai_link == dai_link) + return true; + } + + return false; +} + static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -977,6 +990,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, if (!rtd) return -ENOMEM; + if (soc_is_dai_link_bound(card, dai_link)) { + dev_dbg(card->dev, "ASoC: dai link %s already bound\n", + dai_link->name); + return 0; + } + 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; -- cgit v1.2.3 From 61b0088b6a5b98608ce00c18a057b1f5bcb5f8b3 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 2 Dec 2015 14:11:48 +0800 Subject: ASoC: Bind new DAI links after probing components Probing components can bring new DAI or DAI links based on the topology info. This patch finds the unbound DAI links and bind them. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 11d073b6ce33..6b1982dcedf1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1806,6 +1806,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_codec *codec; struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai_link *dai_link; int ret, i, order; mutex_lock(&client_mutex); @@ -1893,6 +1894,21 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } + /* Find new DAI links added during probing components and bind them. + * Components with topology may bring new DAIs and DAI links. + */ + list_for_each_entry(dai_link, &card->dai_link_list, list) { + if (soc_is_dai_link_bound(card, dai_link)) + continue; + + ret = soc_init_dai_link(card, dai_link); + if (ret) + goto probe_dai_err; + ret = soc_bind_dai_link(card, dai_link); + if (ret) + goto probe_dai_err; + } + /* probe all DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { -- cgit v1.2.3 From 5e4fb372117f476e0c7f85418ed3e39506fbb75c Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 31 Dec 2015 16:40:20 +0800 Subject: ASoC: Define soc_add_dai() to add a DAI to a component Define soc_add_dai() as a wrapper to add a single DAI to a component. It can be reused to register a DAI dynamically by topology. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 88 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 36 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6b1982dcedf1..1bd0b37b907f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2744,6 +2744,56 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) } } +/* Create a DAI and add it to the component's DAI list */ +static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming) +{ + struct device *dev = component->dev; + struct snd_soc_dai *dai; + + dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev)); + + dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); + if (dai == NULL) + return NULL; + + /* + * Back in the old days when we still had component-less DAIs, + * instead of having a static name, component-less DAIs would + * inherit the name of the parent device so it is possible to + * register multiple instances of the DAI. We still need to keep + * the same naming style even though those DAIs are not + * component-less anymore. + */ + if (legacy_dai_naming && + (dai_drv->id == 0 || dai_drv->name == NULL)) { + dai->name = fmt_single_name(dev, &dai->id); + } else { + dai->name = fmt_multiple_name(dev, dai_drv); + if (dai_drv->id) + dai->id = dai_drv->id; + else + dai->id = component->num_dai; + } + if (dai->name == NULL) { + kfree(dai); + return NULL; + } + + dai->component = component; + dai->dev = dev; + dai->driver = dai_drv; + if (!dai->driver->ops) + dai->driver->ops = &null_dai_ops; + + list_add(&dai->list, &component->dai_list); + component->num_dai++; + + dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); + return dai; +} + /** * snd_soc_register_dais - Register a DAI with the ASoC core * @@ -2765,49 +2815,15 @@ static int snd_soc_register_dais(struct snd_soc_component *component, dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); component->dai_drv = dai_drv; - component->num_dai = count; for (i = 0; i < count; i++) { - dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); + dai = soc_add_dai(component, dai_drv + i, + count == 1 && legacy_dai_naming); if (dai == NULL) { ret = -ENOMEM; goto err; } - - /* - * Back in the old days when we still had component-less DAIs, - * instead of having a static name, component-less DAIs would - * inherit the name of the parent device so it is possible to - * register multiple instances of the DAI. We still need to keep - * the same naming style even though those DAIs are not - * component-less anymore. - */ - if (count == 1 && legacy_dai_naming && - (dai_drv[i].id == 0 || dai_drv[i].name == NULL)) { - dai->name = fmt_single_name(dev, &dai->id); - } else { - dai->name = fmt_multiple_name(dev, &dai_drv[i]); - if (dai_drv[i].id) - dai->id = dai_drv[i].id; - else - dai->id = i; - } - if (dai->name == NULL) { - kfree(dai); - ret = -ENOMEM; - goto err; - } - - dai->component = component; - dai->dev = dev; - dai->driver = &dai_drv[i]; - if (!dai->driver->ops) - dai->driver->ops = &null_dai_ops; - - list_add(&dai->list, &component->dai_list); - - dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); } return 0; -- cgit v1.2.3 From 68003e6cf2bbd239a322bd8a28dacfaf8174fdee Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 31 Dec 2015 16:40:43 +0800 Subject: ASoC: Support registering a DAI dynamically Define API snd_soc_register_dai() to add a DAI dynamically and create the DAI widgets. Topology can use this API to register DAIs when probing a component with topology info. These DAIs's playback & capture widgets will be freed when the sound card is unregistered and the DAIs will be freed when cleaning up the component. And a dobj is embedded into the struct snd_soc_dai_driver. Topology can use the dobj to find the DAI drivers created by it and free them when the topology component is removed. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 + include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 212eaaf172ed..964b7de1a1cc 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -222,6 +222,7 @@ struct snd_soc_dai_driver { const char *name; unsigned int id; unsigned int base; + struct snd_soc_dobj dobj; /* DAI driver callbacks */ int (*probe)(struct snd_soc_dai *dai); diff --git a/include/sound/soc.h b/include/sound/soc.h index af347bcdc2f6..9d1383e8d039 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1663,6 +1663,9 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, void snd_soc_remove_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); +int snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv); + #include #ifdef CONFIG_DEBUG_FS diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1bd0b37b907f..c572673a5a24 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2834,6 +2834,48 @@ err: return ret; } +/** + * snd_soc_register_dai - Register a DAI dynamically & create its widgets + * + * @component: The component the DAIs are registered for + * @dai_drv: DAI driver to use for the DAI + * + * 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 + * will be freed in the component cleanup. + */ +int snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct snd_soc_dai *dai; + int ret; + + if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { + dev_err(component->dev, "Invalid dai type %d\n", + dai_drv->dobj.type); + return -EINVAL; + } + + lockdep_assert_held(&client_mutex); + dai = soc_add_dai(component, dai_drv, false); + if (!dai) + return -ENOMEM; + + /* Create the DAI widgets here. After adding DAIs, topology may + * also add routes that need these widgets as source or sink. + */ + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(component->dev, + "Failed to create DAI widgets %d\n", ret); + } + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_register_dai); + static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm, enum snd_soc_dapm_type type, int subseq) { -- cgit v1.2.3 From f2ed6b07645ed29c1e090ead2e41066385cba3ea Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 6 Jan 2016 13:29:31 +0800 Subject: ASoC: Make aux_dev more like a generic component aux_dev is mainly used by the machine driver to specify analog devices, which are registered as codecs. Making it more like a generic component can help the machine driver to use it to specify any component with topology info by name. Details: - Remove the stub 'rtd_aux' array from the soc card. - Add a list 'aux_comp_list' to store the components of aux_devs. And add a list head 'list_aux' to struct snd_soc_component, for adding such components to the above list. - Add a 'init' ops to a component for machine specific init. soc_bind_aux_dev() will set it to be aux_dev's init. And it will be called when probing the component. - soc_bind_aux_dev() will also search components by name of an aux_dev, since it may not be a codec. - Move probing of aux_devs before checking new DAI links brought by topology. - Move removal of aux_devs later than removal of links. Because topology of aux components may register DAIs and the DAI drivers will go with removal of the aux components, we want soc_remove_link_dais() to remove the DAIs at first. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc.h | 8 ++- sound/soc/soc-core.c | 146 +++++++++++++++++++++++++++------------------------ 2 files changed, 83 insertions(+), 71 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/include/sound/soc.h b/include/sound/soc.h index 9d1383e8d039..5bc5def6af02 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -787,6 +787,7 @@ struct snd_soc_component { unsigned int registered_as_component:1; struct list_head list; + struct list_head list_aux; /* for auxiliary component of the card */ struct snd_soc_dai_driver *dai_drv; int num_dai; @@ -830,6 +831,9 @@ struct snd_soc_component { int (*probe)(struct snd_soc_component *); void (*remove)(struct snd_soc_component *); + /* machine specific init */ + int (*init)(struct snd_soc_component *component); + #ifdef CONFIG_DEBUG_FS void (*init_debugfs)(struct snd_soc_component *component); const char *debugfs_prefix; @@ -1130,8 +1134,7 @@ struct snd_soc_card { */ struct snd_soc_aux_dev *aux_dev; int num_aux_devs; - struct snd_soc_pcm_runtime *rtd_aux; - int num_aux_rtd; + struct list_head aux_comp_list; const struct snd_kcontrol_new *controls; int num_controls; @@ -1537,6 +1540,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) INIT_LIST_HEAD(&card->widgets); INIT_LIST_HEAD(&card->paths); INIT_LIST_HEAD(&card->dapm_list); + INIT_LIST_HEAD(&card->aux_comp_list); } static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c572673a5a24..c10bd668659c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1413,6 +1413,16 @@ static int soc_probe_component(struct snd_soc_card *card, component->name); } + /* machine specific init */ + if (component->init) { + ret = component->init(component); + if (ret < 0) { + dev_err(component->dev, + "Failed to do machine specific init %d\n", ret); + goto err_probe; + } + } + if (component->controls) snd_soc_add_component_controls(component, component->controls, component->num_controls); @@ -1657,65 +1667,81 @@ static int soc_probe_link_dais(struct snd_soc_card *card, static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - const char *name = aux_dev->codec_name; - - rtd->component = soc_find_component(aux_dev->codec_of_node, name); - if (!rtd->component) { - if (aux_dev->codec_of_node) - name = of_node_full_name(aux_dev->codec_of_node); - - dev_err(card->dev, "ASoC: %s not registered\n", name); - return -EPROBE_DEFER; + struct snd_soc_component *component; + const char *name; + struct device_node *codec_of_node; + + if (aux_dev->codec_of_node || aux_dev->codec_name) { + /* codecs, usually analog devices */ + name = aux_dev->codec_name; + codec_of_node = aux_dev->codec_of_node; + component = soc_find_component(codec_of_node, name); + if (!component) { + if (codec_of_node) + name = of_node_full_name(codec_of_node); + goto err_defer; + } + } else if (aux_dev->name) { + /* generic components */ + name = aux_dev->name; + component = soc_find_component(NULL, name); + if (!component) + goto err_defer; + } else { + dev_err(card->dev, "ASoC: Invalid auxiliary device\n"); + return -EINVAL; } - /* - * Some places still reference rtd->codec, so we have to keep that - * initialized if the component is a CODEC. Once all those references - * have been removed, this code can be removed as well. - */ - rtd->codec = rtd->component->codec; - + component->init = aux_dev->init; + list_add(&component->list_aux, &card->aux_comp_list); return 0; + +err_defer: + dev_err(card->dev, "ASoC: %s not registered\n", name); + return -EPROBE_DEFER; } -static int soc_probe_aux_dev(struct snd_soc_card *card, int num) +static int soc_probe_aux_devices(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; + struct snd_soc_component *comp; + int order; int ret; - ret = soc_probe_component(card, rtd->component); - if (ret < 0) - return ret; - - /* do machine specific initialization */ - if (aux_dev->init) { - ret = aux_dev->init(rtd->component); - if (ret < 0) { - dev_err(card->dev, "ASoC: failed to init %s: %d\n", - aux_dev->name, ret); - return ret; + for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; + order++) { + list_for_each_entry(comp, &card->aux_comp_list, list_aux) { + if (comp->driver->probe_order == order) { + ret = soc_probe_component(card, comp); + if (ret < 0) { + dev_err(card->dev, + "ASoC: failed to probe aux component %s %d\n", + comp->name, ret); + return ret; + } + } } } - return soc_post_component_init(rtd, aux_dev->name); + return 0; } -static void soc_remove_aux_dev(struct snd_soc_card *card, int num) +static void soc_remove_aux_devices(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_component *component = rtd->component; + struct snd_soc_component *comp, *_comp; + int order; - /* unregister the rtd device */ - if (rtd->dev_registered) { - device_unregister(rtd->dev); - rtd->dev_registered = 0; + for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; + order++) { + list_for_each_entry_safe(comp, _comp, + &card->aux_comp_list, list_aux) { + if (comp->driver->remove_order == order) { + soc_remove_component(comp); + /* remove it from the card's aux_comp_list */ + list_del(&comp->list_aux); + } + } } - - if (component) - soc_remove_component(component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) @@ -1894,6 +1920,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } + /* probe auxiliary components */ + ret = soc_probe_aux_devices(card); + if (ret < 0) + goto probe_dai_err; + /* Find new DAI links added during probing components and bind them. * Components with topology may bring new DAIs and DAI links. */ @@ -1923,16 +1954,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } - for (i = 0; i < card->num_aux_devs; i++) { - ret = soc_probe_aux_dev(card, i); - if (ret < 0) { - dev_err(card->dev, - "ASoC: failed to add auxiliary devices %d\n", - ret); - goto probe_aux_dev_err; - } - } - snd_soc_dapm_link_dai_widgets(card); snd_soc_dapm_connect_dai_link_widgets(card); @@ -1992,8 +2013,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) return 0; probe_aux_dev_err: - for (i = 0; i < card->num_aux_devs; i++) - soc_remove_aux_dev(card, i); + soc_remove_aux_devices(card); probe_dai_err: soc_remove_dai_links(card); @@ -2039,20 +2059,18 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; - int i; /* make sure any delayed work runs */ list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); - /* remove auxiliary devices */ - for (i = 0; i < card->num_aux_devs; i++) - soc_remove_aux_dev(card, i); - /* remove and free each DAI */ soc_remove_dai_links(card); soc_remove_pcm_runtimes(card); + /* remove auxiliary devices */ + soc_remove_aux_devices(card); + soc_cleanup_card_debugfs(card); /* remove the card */ @@ -2608,16 +2626,6 @@ int snd_soc_register_card(struct snd_soc_card *card) INIT_LIST_HEAD(&card->rtd_list); card->num_rtd = 0; - card->rtd_aux = devm_kzalloc(card->dev, - sizeof(struct snd_soc_pcm_runtime) * - card->num_aux_devs, - GFP_KERNEL); - if (card->rtd_aux == NULL) - return -ENOMEM; - - for (i = 0; i < card->num_aux_devs; i++) - card->rtd_aux[i].card = card; - INIT_LIST_HEAD(&card->dapm_dirty); INIT_LIST_HEAD(&card->dobj_list); card->instantiated = 0; -- cgit v1.2.3