diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-03-18 17:22:37 (GMT) |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-03-18 17:22:37 (GMT) |
commit | cb3f2adc03ab055b19c677a6283523861fafebdd (patch) | |
tree | 59cfb6800f0635a4aec16c8e0da619f27e51ee79 /sound/soc/soc-dapm.c | |
parent | 44c76a960a62fcc46cbcaa0a22a34e666a729329 (diff) | |
parent | 828006de1bddf83b6ecf03ec459c15f7c7c22db7 (diff) | |
download | linux-cb3f2adc03ab055b19c677a6283523861fafebdd.tar.xz |
Merge branch 'topic/asoc' into for-linus
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 400 |
1 files changed, 285 insertions, 115 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1315663..6241490 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -14,19 +14,13 @@ * dynamic configuration of codec internal audio paths and active * DACs/ADCs. * o Platform power domain - can support external components i.e. amps and - * mic/meadphone insertion events. + * mic/headphone insertion events. * o Automatic Mic Bias support * o Jack insertion power event initiation - e.g. hp insertion will enable * sinks, dacs, etc - * o Delayed powerdown of audio susbsystem to reduce pops between a quick + * o Delayed power down of audio subsystem to reduce pops between a quick * device reopen. * - * Todo: - * o DAPM power change sequencing - allow for configurable per - * codec sequences. - * o Support for analogue bias optimisation. - * o Support for reduced codec oversampling rates. - * o Support for reduced codec bias currents. */ #include <linux/module.h> @@ -40,6 +34,7 @@ #include <linux/jiffies.h> #include <linux/debugfs.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -55,7 +50,9 @@ static int dapm_up_seq[] = { [snd_soc_dapm_pre] = 0, [snd_soc_dapm_supply] = 1, + [snd_soc_dapm_regulator_supply] = 1, [snd_soc_dapm_micbias] = 2, + [snd_soc_dapm_dai] = 3, [snd_soc_dapm_aif_in] = 3, [snd_soc_dapm_aif_out] = 3, [snd_soc_dapm_mic] = 4, @@ -90,6 +87,8 @@ static int dapm_down_seq[] = { [snd_soc_dapm_value_mux] = 9, [snd_soc_dapm_aif_in] = 10, [snd_soc_dapm_aif_out] = 10, + [snd_soc_dapm_dai] = 10, + [snd_soc_dapm_regulator_supply] = 11, [snd_soc_dapm_supply] = 11, [snd_soc_dapm_post] = 12, }; @@ -172,6 +171,19 @@ static inline struct snd_soc_card *dapm_get_soc_card( return NULL; } +static void dapm_reset(struct snd_soc_card *card) +{ + struct snd_soc_dapm_widget *w; + + memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); + + list_for_each_entry(w, &card->widgets, list) { + w->power_checked = false; + w->inputs = -1; + w->outputs = -1; + } +} + static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) { if (w->codec) @@ -197,21 +209,28 @@ static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, unsigned short reg, unsigned int mask, unsigned int value) { - int change; + bool change; unsigned int old, new; int ret; - ret = soc_widget_read(w, reg); - if (ret < 0) - return ret; - - old = ret; - new = (old & ~mask) | (value & mask); - change = old != new; - if (change) { - ret = soc_widget_write(w, reg, new); + if (w->codec && w->codec->using_regmap) { + ret = regmap_update_bits_check(w->codec->control_data, + reg, mask, value, &change); + if (ret != 0) + return ret; + } else { + ret = soc_widget_read(w, reg); if (ret < 0) return ret; + + old = ret; + new = (old & ~mask) | (value & mask); + change = old != new; + if (change) { + ret = soc_widget_write(w, reg, new); + if (ret < 0) + return ret; + } } return change; @@ -345,8 +364,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_micbias: case snd_soc_dapm_vmid: case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai: case snd_soc_dapm_hp: case snd_soc_dapm_mic: case snd_soc_dapm_spk: @@ -504,17 +525,17 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) * for widgets so cut the prefix off * the front of the widget name. */ - snprintf(path->long_name, name_len, "%s %s", - w->name + prefix_len, + snprintf((char *)path->long_name, name_len, + "%s %s", w->name + prefix_len, w->kcontrol_news[i].name); break; case snd_soc_dapm_mixer_named_ctl: - snprintf(path->long_name, name_len, "%s", - w->kcontrol_news[i].name); + snprintf((char *)path->long_name, name_len, + "%s", w->kcontrol_news[i].name); break; } - path->long_name[name_len - 1] = '\0'; + ((char *)path->long_name)[name_len - 1] = '\0'; path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], wlist, path->long_name, @@ -548,7 +569,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) struct snd_soc_dapm_widget_list *wlist; int shared, wlistentries; size_t wlistsize; - char *name; + const char *name; if (w->num_kcontrols != 1) { dev_err(dapm->dev, @@ -673,12 +694,18 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) DAPM_UPDATE_STAT(widget, path_checks); - if (widget->id == snd_soc_dapm_supply) + switch (widget->id) { + case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: return 0; + default: + break; + } switch (widget->id) { case snd_soc_dapm_adc: case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai: if (widget->active) { widget->outputs = snd_soc_dapm_suspend_check(widget); return widget->outputs; @@ -738,13 +765,19 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) DAPM_UPDATE_STAT(widget, path_checks); - if (widget->id == snd_soc_dapm_supply) + switch (widget->id) { + case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: return 0; + default: + break; + } /* active stream ? */ switch (widget->id) { case snd_soc_dapm_dac: case snd_soc_dapm_aif_in: + case snd_soc_dapm_dai: if (widget->active) { widget->inputs = snd_soc_dapm_suspend_check(widget); return widget->inputs; @@ -821,6 +854,19 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, } EXPORT_SYMBOL_GPL(dapm_reg_event); +/* + * Handler for regulator supply widget. + */ +int dapm_regulator_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + return regulator_enable(w->priv); + else + return regulator_disable_deferred(w->priv, w->shift); +} +EXPORT_SYMBOL_GPL(dapm_regulator_event); + static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) { if (w->power_checked) @@ -851,6 +897,13 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) return out != 0 && in != 0; } +static int dapm_dai_check_power(struct snd_soc_dapm_widget *w) +{ + DAPM_UPDATE_STAT(w, power_checks); + + return w->active; +} + /* Check to see if an ADC has power */ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) { @@ -1251,7 +1304,7 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) dev_err(d->dev, "Failed to turn off bias: %d\n", ret); if (d->dev) - pm_runtime_put_sync(d->dev); + pm_runtime_put(d->dev); } /* If we just powered up then move to active bias */ @@ -1301,6 +1354,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, } switch (w->id) { case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: /* Supplies can't affect their outputs, only their inputs */ break; default: @@ -1373,13 +1427,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) } } - memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); - - list_for_each_entry(w, &card->widgets, list) { - w->power_checked = false; - w->inputs = -1; - w->outputs = -1; - } + dapm_reset(card); /* Check which widgets we need to power and store them in * lists indicating if they should be powered up or down. We @@ -1400,10 +1448,15 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) /* Supplies and micbiases only bring the * context up to STANDBY as unless something * else is active and passing audio they - * generally don't require full power. + * generally don't require full power. Signal + * generators are virtual pins and have no + * power impact themselves. */ switch (w->id) { + case snd_soc_dapm_siggen: + break; case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: case snd_soc_dapm_micbias: if (d->target_bias_level < SND_SOC_BIAS_STANDBY) d->target_bias_level = SND_SOC_BIAS_STANDBY; @@ -1475,6 +1528,12 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) &async_domain); async_synchronize_full_domain(&async_domain); + /* do we need to notify any clients that DAPM event is complete */ + list_for_each_entry(d, &card->dapm_list, list) { + if (d->stream_event) + d->stream_event(d, event); + } + pop_dbg(dapm->dev, card->pop_time, "DAPM sequencing finished, waiting %dms\n", card->pop_time); pop_wait(card->pop_time); @@ -1510,8 +1569,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, out = is_connected_output_ep(w); dapm_clear_walk(w->dapm); - ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", - w->name, w->power ? "On" : "Off", in, out); + ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", + w->name, w->power ? "On" : "Off", + w->force ? " (forced)" : "", in, out); if (w->reg >= 0) ret += snprintf(buf + ret, PAGE_SIZE - ret, @@ -1607,7 +1667,7 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); if (!dapm->debugfs_dapm) { - printk(KERN_WARNING + dev_warn(dapm->dev, "Failed to create DAPM debugfs directory\n"); return; } @@ -1659,9 +1719,8 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) #endif /* test and update the power status of a mux widget */ -static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int change, - int mux, struct soc_enum *e) +int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) { struct snd_soc_dapm_path *path; int found = 0; @@ -1671,9 +1730,6 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, widget->id != snd_soc_dapm_value_mux) return -ENODEV; - if (!change) - return 0; - /* find dapm widget path assoc with kcontrol */ list_for_each_entry(path, &widget->dapm->card->paths, list) { if (path->kcontrol != kcontrol) @@ -1702,9 +1758,10 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, return 0; } +EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); /* test and update the power status of a mixer or switch widget */ -static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, +int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, int connect) { struct snd_soc_dapm_path *path; @@ -1733,6 +1790,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, return 0; } +EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); /* show dapm widget status in sys fs */ static ssize_t dapm_widget_show(struct device *dev, @@ -1762,6 +1820,7 @@ static ssize_t dapm_widget_show(struct device *dev, case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: if (w->name) count += sprintf(buf + count, "%s: %s\n", w->name, w->power ? "On":"Off"); @@ -1869,10 +1928,12 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, return -EINVAL; } + if (w->connected != status) + dapm_mark_dirty(w, "pin configuration"); + w->connected = status; if (status == 0) w->force = 0; - dapm_mark_dirty(w, "pin configuration"); return 0; } @@ -2000,8 +2061,10 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, case snd_soc_dapm_pre: case snd_soc_dapm_post: case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai: list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); @@ -2315,7 +2378,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - dapm_mixer_update_power(widget, kcontrol, connect); + snd_soc_dapm_mixer_update_power(widget, kcontrol, connect); widget->dapm->update = NULL; } @@ -2406,7 +2469,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - dapm_mux_update_power(widget, kcontrol, change, mux, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); widget->dapm->update = NULL; } @@ -2467,8 +2530,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, widget->value = ucontrol->value.enumerated.item[0]; - dapm_mux_update_power(widget, kcontrol, change, - widget->value, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); } } @@ -2571,7 +2633,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - dapm_mux_update_power(widget, kcontrol, change, mux, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); widget->dapm->update = NULL; } @@ -2611,15 +2673,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch); int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); const char *pin = (const char *)kcontrol->private_value; - mutex_lock(&codec->mutex); + mutex_lock(&card->mutex); ucontrol->value.integer.value[0] = - snd_soc_dapm_get_pin_status(&codec->dapm, pin); + snd_soc_dapm_get_pin_status(&card->dapm, pin); - mutex_unlock(&codec->mutex); + mutex_unlock(&card->mutex); return 0; } @@ -2634,41 +2696,48 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch); int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); const char *pin = (const char *)kcontrol->private_value; - mutex_lock(&codec->mutex); + mutex_lock(&card->mutex); if (ucontrol->value.integer.value[0]) - snd_soc_dapm_enable_pin(&codec->dapm, pin); + snd_soc_dapm_enable_pin(&card->dapm, pin); else - snd_soc_dapm_disable_pin(&codec->dapm, pin); + snd_soc_dapm_disable_pin(&card->dapm, pin); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_sync(&card->dapm); - mutex_unlock(&codec->mutex); + mutex_unlock(&card->mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); -/** - * snd_soc_dapm_new_control - create new dapm control - * @dapm: DAPM context - * @widget: widget template - * - * Creates a new dapm control based upon the template. - * - * Returns 0 for success else error. - */ -int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget) +static 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; size_t name_len; + int ret; if ((w = dapm_cnew_widget(widget)) == NULL) - return -ENOMEM; + return NULL; + + switch (w->id) { + case snd_soc_dapm_regulator_supply: + w->priv = devm_regulator_get(dapm->dev, w->name); + if (IS_ERR(w->priv)) { + ret = PTR_ERR(w->priv); + dev_err(dapm->dev, "Failed to request %s: %d\n", + w->name, ret); + return NULL; + } + break; + default: + break; + } name_len = strlen(widget->name) + 1; if (dapm->codec && dapm->codec->name_prefix) @@ -2676,13 +2745,13 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->name = kmalloc(name_len, GFP_KERNEL); if (w->name == NULL) { kfree(w); - return -ENOMEM; + return NULL; } if (dapm->codec && dapm->codec->name_prefix) - snprintf(w->name, name_len, "%s %s", + snprintf((char *)w->name, name_len, "%s %s", dapm->codec->name_prefix, widget->name); else - snprintf(w->name, name_len, "%s", widget->name); + snprintf((char *)w->name, name_len, "%s", widget->name); switch (w->id) { case snd_soc_dapm_switch: @@ -2715,8 +2784,12 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_supply: + case snd_soc_dapm_regulator_supply: w->power_check = dapm_supply_check_power; break; + case snd_soc_dapm_dai: + w->power_check = dapm_dai_check_power; + break; default: w->power_check = dapm_always_on_check_power; break; @@ -2734,9 +2807,8 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, /* machine layer set ups unconnected pins and insertions */ w->connected = 1; - return 0; + return w; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); /** * snd_soc_dapm_new_controls - create new dapm controls @@ -2752,15 +2824,16 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, int num) { - int i, ret; + struct snd_soc_dapm_widget *w; + int i; for (i = 0; i < num; i++) { - ret = snd_soc_dapm_new_control(dapm, widget); - if (ret < 0) { + w = snd_soc_dapm_new_control(dapm, widget); + if (!w) { dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s: %d\n", - widget->name, ret); - return ret; + "ASoC: Failed to create DAPM control %s\n", + widget->name); + return -ENOMEM; } widget++; } @@ -2768,40 +2841,140 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); -static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, - const char *stream, int event) +int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, + struct snd_soc_dai *dai) { + struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; - list_for_each_entry(w, &dapm->card->widgets, list) - { - if (!w->sname || w->dapm != dapm) + WARN_ON(dapm->dev != dai->dev); + + memset(&template, 0, sizeof(template)); + template.reg = SND_SOC_NOPM; + + if (dai->driver->playback.stream_name) { + template.id = snd_soc_dapm_dai; + template.name = dai->driver->playback.stream_name; + template.sname = dai->driver->playback.stream_name; + + dev_dbg(dai->dev, "adding %s widget\n", + template.name); + + w = snd_soc_dapm_new_control(dapm, &template); + if (!w) { + dev_err(dapm->dev, "Failed to create %s widget\n", + dai->driver->playback.stream_name); + } + + w->priv = dai; + dai->playback_widget = w; + } + + if (dai->driver->capture.stream_name) { + template.id = snd_soc_dapm_dai; + template.name = dai->driver->capture.stream_name; + template.sname = dai->driver->capture.stream_name; + + dev_dbg(dai->dev, "adding %s widget\n", + template.name); + + w = snd_soc_dapm_new_control(dapm, &template); + if (!w) { + dev_err(dapm->dev, "Failed to create %s widget\n", + dai->driver->capture.stream_name); + } + + w->priv = dai; + dai->capture_widget = w; + } + + return 0; +} + +int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) +{ + struct snd_soc_dapm_widget *dai_w, *w; + struct snd_soc_dai *dai; + struct snd_soc_dapm_route r; + + memset(&r, 0, sizeof(r)); + + /* For each DAI widget... */ + list_for_each_entry(dai_w, &card->widgets, list) { + if (dai_w->id != snd_soc_dapm_dai) continue; - dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", - w->name, w->sname, stream, event); - if (strstr(w->sname, stream)) { - dapm_mark_dirty(w, "stream event"); - switch(event) { - case SND_SOC_DAPM_STREAM_START: - w->active = 1; - break; - case SND_SOC_DAPM_STREAM_STOP: - w->active = 0; - break; - case SND_SOC_DAPM_STREAM_SUSPEND: - case SND_SOC_DAPM_STREAM_RESUME: - case SND_SOC_DAPM_STREAM_PAUSE_PUSH: - case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: - break; + + dai = dai_w->priv; + + /* ...find all widgets with the same stream and link them */ + list_for_each_entry(w, &card->widgets, list) { + if (w->dapm != dai_w->dapm) + continue; + + if (w->id == snd_soc_dapm_dai) + continue; + + if (!w->sname) + continue; + + if (dai->driver->playback.stream_name && + strstr(w->sname, + dai->driver->playback.stream_name)) { + r.source = dai->playback_widget->name; + r.sink = w->name; + dev_dbg(dai->dev, "%s -> %s\n", + r.source, r.sink); + + snd_soc_dapm_add_route(w->dapm, &r); + } + + if (dai->driver->capture.stream_name && + strstr(w->sname, + dai->driver->capture.stream_name)) { + r.source = w->name; + r.sink = dai->capture_widget->name; + dev_dbg(dai->dev, "%s -> %s\n", + r.source, r.sink); + + snd_soc_dapm_add_route(w->dapm, &r); } } } - dapm_power_widgets(dapm, event); + return 0; +} - /* do we need to notify any clients that DAPM stream is complete */ - if (dapm->stream_event) - dapm->stream_event(dapm, event); +static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, + int stream, struct snd_soc_dai *dai, + int event) +{ + struct snd_soc_dapm_widget *w; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + w = dai->playback_widget; + else + w = dai->capture_widget; + + if (!w) + return; + + dapm_mark_dirty(w, "stream event"); + + switch (event) { + case SND_SOC_DAPM_STREAM_START: + w->active = 1; + break; + case SND_SOC_DAPM_STREAM_STOP: + w->active = 0; + break; + case SND_SOC_DAPM_STREAM_SUSPEND: + case SND_SOC_DAPM_STREAM_RESUME: + case SND_SOC_DAPM_STREAM_PAUSE_PUSH: + case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: + break; + } + + dapm_power_widgets(dapm, event); } /** @@ -2815,16 +2988,13 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, * * Returns 0 for success else error. */ -int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, - const char *stream, int event) +int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, + struct snd_soc_dai *dai, int event) { struct snd_soc_codec *codec = rtd->codec; - if (stream == NULL) - return 0; - mutex_lock(&codec->mutex); - soc_dapm_stream_event(&codec->dapm, stream, event); + soc_dapm_stream_event(&codec->dapm, stream, dai, event); mutex_unlock(&codec->mutex); return 0; } |