summaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c437
1 files changed, 217 insertions, 220 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 461d951917c0..a5178845065b 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -18,7 +18,6 @@
// device reopen.
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/async.h>
#include <linux/delay.h>
@@ -364,10 +363,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
ret = PTR_ERR(data->widget);
goto err_data;
}
- if (!data->widget) {
- ret = -ENOMEM;
- goto err_data;
- }
}
break;
case snd_soc_dapm_demux:
@@ -402,10 +397,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
ret = PTR_ERR(data->widget);
goto err_data;
}
- if (!data->widget) {
- ret = -ENOMEM;
- goto err_data;
- }
snd_soc_dapm_add_path(widget->dapm, data->widget,
widget, NULL, NULL);
@@ -1026,9 +1017,10 @@ static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
struct snd_kcontrol *kcontrol;
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_card *card = dapm->card->snd_card;
+ struct snd_soc_pcm_runtime *rtd = w->priv;
/* create control for links with > 1 config */
- if (w->num_params <= 1)
+ if (rtd->dai_link->num_params <= 1)
return 0;
/* add kcontrol */
@@ -1320,14 +1312,13 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w,
soc_dapm_async_complete(w->dapm);
-#ifdef CONFIG_HAVE_CLK
if (SND_SOC_DAPM_EVENT_ON(event)) {
return clk_prepare_enable(w->clk);
} else {
clk_disable_unprepare(w->clk);
return 0;
}
-#endif
+
return 0;
}
EXPORT_SYMBOL_GPL(dapm_clock_event);
@@ -1953,7 +1944,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
dapm_pre_sequence_async(&card->dapm, 0);
/* Run other bias changes in parallel */
list_for_each_entry(d, &card->dapm_list, list) {
- if (d != &card->dapm)
+ if (d != &card->dapm && d->bias_level != d->target_bias_level)
async_schedule_domain(dapm_pre_sequence_async, d,
&async_domain);
}
@@ -1977,7 +1968,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
/* Run all the bias changes in parallel */
list_for_each_entry(d, &card->dapm_list, list) {
- if (d != &card->dapm)
+ if (d != &card->dapm && d->bias_level != d->target_bias_level)
async_schedule_domain(dapm_post_sequence_async, d,
&async_domain);
}
@@ -2371,12 +2362,13 @@ static ssize_t dapm_widget_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
+ struct snd_soc_dai *codec_dai;
int i, count = 0;
mutex_lock(&rtd->card->dapm_mutex);
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component;
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
+ struct snd_soc_component *cmpnt = codec_dai->component;
count += dapm_widget_show_component(cmpnt, buf + count);
}
@@ -3426,35 +3418,6 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
struct snd_soc_dapm_widget *
-snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_widget *widget)
-{
- struct snd_soc_dapm_widget *w;
-
- mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- w = snd_soc_dapm_new_control_unlocked(dapm, widget);
- /* Do not nag about probe deferrals */
- if (IS_ERR(w)) {
- int ret = PTR_ERR(w);
-
- if (ret != -EPROBE_DEFER)
- dev_err(dapm->dev,
- "ASoC: Failed to create DAPM control %s (%d)\n",
- widget->name, ret);
- goto out_unlock;
- }
- if (!w)
- dev_err(dapm->dev,
- "ASoC: Failed to create DAPM control %s\n",
- widget->name);
-
-out_unlock:
- mutex_unlock(&dapm->card->dapm_mutex);
- return w;
-}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
-
-struct snd_soc_dapm_widget *
snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget)
{
@@ -3464,53 +3427,37 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
int ret;
if ((w = dapm_cnew_widget(widget)) == NULL)
- return NULL;
+ return ERR_PTR(-ENOMEM);
switch (w->id) {
case snd_soc_dapm_regulator_supply:
w->regulator = devm_regulator_get(dapm->dev, w->name);
if (IS_ERR(w->regulator)) {
ret = PTR_ERR(w->regulator);
- if (ret == -EPROBE_DEFER)
- return ERR_PTR(ret);
- dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
- w->name, ret);
- return NULL;
+ goto request_failed;
}
if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0)
- dev_warn(w->dapm->dev,
+ dev_warn(dapm->dev,
"ASoC: Failed to bypass %s: %d\n",
w->name, ret);
}
break;
case snd_soc_dapm_pinctrl:
w->pinctrl = devm_pinctrl_get(dapm->dev);
- if (IS_ERR_OR_NULL(w->pinctrl)) {
+ if (IS_ERR(w->pinctrl)) {
ret = PTR_ERR(w->pinctrl);
- if (ret == -EPROBE_DEFER)
- return ERR_PTR(ret);
- dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
- w->name, ret);
- return NULL;
+ goto request_failed;
}
break;
case snd_soc_dapm_clock_supply:
-#ifdef CONFIG_CLKDEV_LOOKUP
w->clk = devm_clk_get(dapm->dev, w->name);
if (IS_ERR(w->clk)) {
ret = PTR_ERR(w->clk);
- if (ret == -EPROBE_DEFER)
- return ERR_PTR(ret);
- dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
- w->name, ret);
- return NULL;
+ goto request_failed;
}
-#else
- return NULL;
-#endif
break;
default:
break;
@@ -3523,7 +3470,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
w->name = kstrdup_const(widget->name, GFP_KERNEL);
if (w->name == NULL) {
kfree(w);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
switch (w->id) {
@@ -3600,7 +3547,37 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
/* machine layer sets up unconnected pins and insertions */
w->connected = 1;
return w;
+
+request_failed:
+ if (ret != -EPROBE_DEFER)
+ dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
+ w->name, ret);
+
+ return ERR_PTR(ret);
+}
+
+/**
+ * snd_soc_dapm_new_control - create new dapm control
+ * @dapm: DAPM context
+ * @widget: widget template
+ *
+ * Creates new DAPM control based upon a template.
+ *
+ * Returns a widget pointer on success or an error pointer on failure
+ */
+struct snd_soc_dapm_widget *
+snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
+ const struct snd_soc_dapm_widget *widget)
+{
+ struct snd_soc_dapm_widget *w;
+
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ w = snd_soc_dapm_new_control_unlocked(dapm, widget);
+ mutex_unlock(&dapm->card->dapm_mutex);
+
+ return w;
}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
/**
* snd_soc_dapm_new_controls - create new dapm controls
@@ -3625,19 +3602,6 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
w = snd_soc_dapm_new_control_unlocked(dapm, widget);
if (IS_ERR(w)) {
ret = PTR_ERR(w);
- /* Do not nag about probe deferrals */
- if (ret == -EPROBE_DEFER)
- break;
- dev_err(dapm->dev,
- "ASoC: Failed to create DAPM control %s (%d)\n",
- widget->name, ret);
- break;
- }
- if (!w) {
- dev_err(dapm->dev,
- "ASoC: Failed to create DAPM control %s\n",
- widget->name);
- ret = -ENOMEM;
break;
}
widget++;
@@ -3650,32 +3614,23 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_dapm_path *source_p, *sink_p;
+ struct snd_soc_dapm_path *path;
struct snd_soc_dai *source, *sink;
struct snd_soc_pcm_runtime *rtd = w->priv;
- const struct snd_soc_pcm_stream *config = w->params + w->params_select;
+ const struct snd_soc_pcm_stream *config;
struct snd_pcm_substream substream;
struct snd_pcm_hw_params *params = NULL;
struct snd_pcm_runtime *runtime = NULL;
unsigned int fmt;
- int ret;
+ int ret = 0;
+
+ config = rtd->dai_link->params + rtd->params_select;
if (WARN_ON(!config) ||
WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
return -EINVAL;
- /* We only support a single source and sink, pick the first */
- source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT],
- struct snd_soc_dapm_path,
- list_node[SND_SOC_DAPM_DIR_OUT]);
- sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN],
- struct snd_soc_dapm_path,
- list_node[SND_SOC_DAPM_DIR_IN]);
-
- source = source_p->source->priv;
- sink = sink_p->sink->priv;
-
/* Be a little careful as we don't want to overflow the mask array */
if (config->formats) {
fmt = ffs(config->formats) - 1;
@@ -3717,59 +3672,95 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- if (source->driver->ops->startup) {
- ret = source->driver->ops->startup(&substream, source);
- if (ret < 0) {
- dev_err(source->dev,
- "ASoC: startup() failed: %d\n", ret);
- goto out;
+ snd_soc_dapm_widget_for_each_source_path(w, path) {
+ source = path->source->priv;
+
+ if (source->driver->ops->startup) {
+ ret = source->driver->ops->startup(&substream,
+ source);
+ if (ret < 0) {
+ dev_err(source->dev,
+ "ASoC: startup() failed: %d\n",
+ ret);
+ goto out;
+ }
+ source->active++;
}
- source->active++;
+ ret = soc_dai_hw_params(&substream, params, source);
+ if (ret < 0)
+ goto out;
}
- ret = soc_dai_hw_params(&substream, params, source);
- if (ret < 0)
- goto out;
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- if (sink->driver->ops->startup) {
- ret = sink->driver->ops->startup(&substream, sink);
- if (ret < 0) {
- dev_err(sink->dev,
- "ASoC: startup() failed: %d\n", ret);
- goto out;
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ if (sink->driver->ops->startup) {
+ ret = sink->driver->ops->startup(&substream,
+ sink);
+ if (ret < 0) {
+ dev_err(sink->dev,
+ "ASoC: startup() failed: %d\n",
+ ret);
+ goto out;
+ }
+ sink->active++;
}
- sink->active++;
+ ret = soc_dai_hw_params(&substream, params, sink);
+ if (ret < 0)
+ goto out;
}
- ret = soc_dai_hw_params(&substream, params, sink);
- if (ret < 0)
- goto out;
break;
case SND_SOC_DAPM_POST_PMU:
- ret = snd_soc_dai_digital_mute(sink, 0,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret != 0 && ret != -ENOTSUPP)
- dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
- ret = 0;
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ ret = snd_soc_dai_digital_mute(sink, 0,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret != 0 && ret != -ENOTSUPP)
+ dev_warn(sink->dev,
+ "ASoC: Failed to unmute: %d\n", ret);
+ ret = 0;
+ }
break;
case SND_SOC_DAPM_PRE_PMD:
- ret = snd_soc_dai_digital_mute(sink, 1,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret != 0 && ret != -ENOTSUPP)
- dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
- ret = 0;
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ ret = snd_soc_dai_digital_mute(sink, 1,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret != 0 && ret != -ENOTSUPP)
+ dev_warn(sink->dev,
+ "ASoC: Failed to mute: %d\n", ret);
+ ret = 0;
+ }
- source->active--;
- if (source->driver->ops->shutdown) {
- substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- source->driver->ops->shutdown(&substream, source);
+ substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+ snd_soc_dapm_widget_for_each_source_path(w, path) {
+ source = path->source->priv;
+
+ if (source->driver->ops->hw_free)
+ source->driver->ops->hw_free(&substream,
+ source);
+
+ source->active--;
+ if (source->driver->ops->shutdown)
+ source->driver->ops->shutdown(&substream,
+ source);
}
- sink->active--;
- if (sink->driver->ops->shutdown) {
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- sink->driver->ops->shutdown(&substream, sink);
+ substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ if (sink->driver->ops->hw_free)
+ sink->driver->ops->hw_free(&substream, sink);
+
+ sink->active--;
+ if (sink->driver->ops->shutdown)
+ sink->driver->ops->shutdown(&substream, sink);
}
break;
@@ -3788,8 +3779,9 @@ static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_pcm_runtime *rtd = w->priv;
- ucontrol->value.enumerated.item[0] = w->params_select;
+ ucontrol->value.enumerated.item[0] = rtd->params_select;
return 0;
}
@@ -3798,18 +3790,19 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_pcm_runtime *rtd = w->priv;
/* Can't change the config when widget is already powered */
if (w->power)
return -EBUSY;
- if (ucontrol->value.enumerated.item[0] == w->params_select)
+ if (ucontrol->value.enumerated.item[0] == rtd->params_select)
return 0;
- if (ucontrol->value.enumerated.item[0] >= w->num_params)
+ if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_params)
return -EINVAL;
- w->params_select = ucontrol->value.enumerated.item[0];
+ rtd->params_select = ucontrol->value.enumerated.item[0];
return 0;
}
@@ -3896,12 +3889,10 @@ outfree_w_param:
return NULL;
}
-int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
- struct snd_soc_pcm_runtime *rtd,
- const struct snd_soc_pcm_stream *params,
- unsigned int num_params,
- struct snd_soc_dapm_widget *source,
- struct snd_soc_dapm_widget *sink)
+static struct snd_soc_dapm_widget *
+snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
{
struct snd_soc_dapm_widget template;
struct snd_soc_dapm_widget *w;
@@ -3913,7 +3904,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
source->name, sink->name);
if (!link_name)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
memset(&template, 0, sizeof(template));
template.reg = SND_SOC_NOPM;
@@ -3925,9 +3916,10 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
template.kcontrol_news = NULL;
/* allocate memory for control, only in case of multiple configs */
- if (num_params > 1) {
- w_param_text = devm_kcalloc(card->dev, num_params,
- sizeof(char *), GFP_KERNEL);
+ if (rtd->dai_link->num_params > 1) {
+ w_param_text = devm_kcalloc(card->dev,
+ rtd->dai_link->num_params,
+ sizeof(char *), GFP_KERNEL);
if (!w_param_text) {
ret = -ENOMEM;
goto param_fail;
@@ -3936,7 +3928,9 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
template.num_kcontrols = 1;
template.kcontrol_news =
snd_soc_dapm_alloc_kcontrol(card,
- link_name, params, num_params,
+ link_name,
+ rtd->dai_link->params,
+ rtd->dai_link->num_params,
w_param_text, &private_value);
if (!template.kcontrol_news) {
ret = -ENOMEM;
@@ -3950,37 +3944,20 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
if (IS_ERR(w)) {
ret = PTR_ERR(w);
- /* Do not nag about probe deferrals */
- if (ret != -EPROBE_DEFER)
- dev_err(card->dev,
- "ASoC: Failed to create %s widget (%d)\n",
- link_name, ret);
- goto outfree_kcontrol_news;
- }
- if (!w) {
- dev_err(card->dev, "ASoC: Failed to create %s widget\n",
- link_name);
- ret = -ENOMEM;
goto outfree_kcontrol_news;
}
- w->params = params;
- w->num_params = num_params;
w->priv = rtd;
- ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
- if (ret)
- goto outfree_w;
- return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
+ return w;
-outfree_w:
- devm_kfree(card->dev, w);
outfree_kcontrol_news:
devm_kfree(card->dev, (void *)template.kcontrol_news);
- snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text);
+ snd_soc_dapm_free_kcontrol(card, &private_value,
+ rtd->dai_link->num_params, w_param_text);
param_fail:
devm_kfree(card->dev, link_name);
- return ret;
+ return ERR_PTR(ret);
}
int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
@@ -4003,21 +3980,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
template.name);
w = snd_soc_dapm_new_control_unlocked(dapm, &template);
- if (IS_ERR(w)) {
- int ret = PTR_ERR(w);
-
- /* Do not nag about probe deferrals */
- if (ret != -EPROBE_DEFER)
- dev_err(dapm->dev,
- "ASoC: Failed to create %s widget (%d)\n",
- dai->driver->playback.stream_name, ret);
- return ret;
- }
- if (!w) {
- dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
- dai->driver->playback.stream_name);
- return -ENOMEM;
- }
+ if (IS_ERR(w))
+ return PTR_ERR(w);
w->priv = dai;
dai->playback_widget = w;
@@ -4032,21 +3996,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
template.name);
w = snd_soc_dapm_new_control_unlocked(dapm, &template);
- if (IS_ERR(w)) {
- int ret = PTR_ERR(w);
-
- /* Do not nag about probe deferrals */
- if (ret != -EPROBE_DEFER)
- dev_err(dapm->dev,
- "ASoC: Failed to create %s widget (%d)\n",
- dai->driver->playback.stream_name, ret);
- return ret;
- }
- if (!w) {
- dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
- dai->driver->capture.stream_name);
- return -ENOMEM;
- }
+ if (IS_ERR(w))
+ return PTR_ERR(w);
w->priv = dai;
dai->capture_widget = w;
@@ -4115,34 +4066,79 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dapm_widget *sink, *source;
+ struct snd_soc_dai *codec_dai;
+ struct snd_soc_dapm_widget *playback = NULL, *capture = NULL;
+ struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu;
int i;
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+ if (rtd->dai_link->params) {
+ playback_cpu = cpu_dai->capture_widget;
+ capture_cpu = cpu_dai->playback_widget;
+ } else {
+ playback = cpu_dai->playback_widget;
+ capture = cpu_dai->capture_widget;
+ playback_cpu = playback;
+ capture_cpu = capture;
+ }
+
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
/* connect BE DAI playback if widgets are valid */
- if (codec_dai->playback_widget && cpu_dai->playback_widget) {
- source = cpu_dai->playback_widget;
- sink = codec_dai->playback_widget;
+ codec = codec_dai->playback_widget;
+
+ if (playback_cpu && codec) {
+ if (!playback) {
+ playback = snd_soc_dapm_new_dai(card, rtd,
+ playback_cpu,
+ codec);
+ if (IS_ERR(playback)) {
+ dev_err(rtd->dev,
+ "ASoC: Failed to create DAI %s: %ld\n",
+ codec_dai->name,
+ PTR_ERR(playback));
+ continue;
+ }
+
+ snd_soc_dapm_add_path(&card->dapm, playback_cpu,
+ playback, NULL, NULL);
+ }
+
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
- cpu_dai->component->name, source->name,
- codec_dai->component->name, sink->name);
+ cpu_dai->component->name, playback_cpu->name,
+ codec_dai->component->name, codec->name);
- snd_soc_dapm_add_path(&card->dapm, source, sink,
- NULL, NULL);
+ snd_soc_dapm_add_path(&card->dapm, playback, codec,
+ NULL, NULL);
}
+ }
+ for_each_rtd_codec_dai(rtd, i, codec_dai) {
/* connect BE DAI capture if widgets are valid */
- if (codec_dai->capture_widget && cpu_dai->capture_widget) {
- source = codec_dai->capture_widget;
- sink = cpu_dai->capture_widget;
+ codec = codec_dai->capture_widget;
+
+ if (codec && capture_cpu) {
+ if (!capture) {
+ capture = snd_soc_dapm_new_dai(card, rtd,
+ codec,
+ capture_cpu);
+ if (IS_ERR(capture)) {
+ dev_err(rtd->dev,
+ "ASoC: Failed to create DAI %s: %ld\n",
+ codec_dai->name,
+ PTR_ERR(capture));
+ continue;
+ }
+
+ snd_soc_dapm_add_path(&card->dapm, capture,
+ capture_cpu, NULL, NULL);
+ }
+
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
- codec_dai->component->name, source->name,
- cpu_dai->component->name, sink->name);
+ codec_dai->component->name, codec->name,
+ cpu_dai->component->name, capture_cpu->name);
- snd_soc_dapm_add_path(&card->dapm, source, sink,
- NULL, NULL);
+ snd_soc_dapm_add_path(&card->dapm, codec, capture,
+ NULL, NULL);
}
}
}
@@ -4192,12 +4188,12 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
struct snd_soc_pcm_runtime *rtd;
/* for each BE DAI link... */
- list_for_each_entry(rtd, &card->rtd_list, list) {
+ for_each_card_rtds(card, rtd) {
/*
* dynamic FE links have no fixed DAI mapping.
* CODEC<->CODEC links have no direct connection.
*/
- if (rtd->dai_link->dynamic || rtd->dai_link->params)
+ if (rtd->dai_link->dynamic)
continue;
dapm_connect_dai_link_widgets(card, rtd);
@@ -4207,11 +4203,12 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
int event)
{
+ struct snd_soc_dai *codec_dai;
int i;
soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
- for (i = 0; i < rtd->num_codecs; i++)
- soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
+ for_each_rtd_codec_dai(rtd, i, codec_dai)
+ soc_dapm_dai_stream_event(codec_dai, stream, event);
dapm_power_widgets(rtd->card, event);
}