X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sound%2Fsoc%2Fsoc-dapm.c;h=69e9452386e6d8306f6a7dc62c361143a90aa7a8;hb=497098beffaa898ea9fa0076e626f055ef5c832e;hp=6241490fff30e2e850e4be82e177bb6656ecfbc0;hpb=281b05392fc2cb26209b4d85abaf4889ab1991f3;p=deliverable%2Flinux.git diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6241490fff30..69e9452386e6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -206,7 +206,23 @@ static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) return -1; } -static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, +static inline void soc_widget_lock(struct snd_soc_dapm_widget *w) +{ + if (w->codec && !w->codec->using_regmap) + mutex_lock(&w->codec->mutex); + else if (w->platform) + mutex_lock(&w->platform->mutex); +} + +static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w) +{ + if (w->codec && !w->codec->using_regmap) + mutex_unlock(&w->codec->mutex); + else if (w->platform) + mutex_unlock(&w->platform->mutex); +} + +static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w, unsigned short reg, unsigned int mask, unsigned int value) { bool change; @@ -219,18 +235,24 @@ static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, if (ret != 0) return ret; } else { + soc_widget_lock(w); ret = soc_widget_read(w, reg); - if (ret < 0) + if (ret < 0) { + soc_widget_unlock(w); return ret; + } old = ret; new = (old & ~mask) | (value & mask); change = old != new; if (change) { ret = soc_widget_write(w, reg, new); - if (ret < 0) + if (ret < 0) { + soc_widget_unlock(w); return ret; + } } + soc_widget_unlock(w); } return change; @@ -847,7 +869,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, else val = w->off_val; - soc_widget_update_bits(w, -(w->reg + 1), + soc_widget_update_bits_locked(w, -(w->reg + 1), w->mask << w->shift, val << w->shift); return 0; @@ -861,9 +883,9 @@ 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); + return regulator_enable(w->regulator); else - return regulator_disable_deferred(w->priv, w->shift); + return regulator_disable_deferred(w->regulator, w->shift); } EXPORT_SYMBOL_GPL(dapm_regulator_event); @@ -1105,7 +1127,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, "pop test : Applying 0x%x/0x%x to %x in %dms\n", value, mask, reg, card->pop_time); pop_wait(card->pop_time); - soc_widget_update_bits(w, reg, mask, value); + soc_widget_update_bits_locked(w, reg, mask, value); } list_for_each_entry(w, pending, power_list) { @@ -1235,7 +1257,7 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm) w->name, ret); } - ret = snd_soc_update_bits(w->codec, update->reg, update->mask, + ret = soc_widget_update_bits_locked(w, update->reg, update->mask, update->val); if (ret < 0) pr_err("%s DAPM update failed: %d\n", w->name, ret); @@ -1419,12 +1441,10 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) trace_snd_soc_dapm_start(card); list_for_each_entry(d, &card->dapm_list, list) { - if (d->n_widgets || d->codec == NULL) { - if (d->idle_bias_off) - d->target_bias_level = SND_SOC_BIAS_OFF; - else - d->target_bias_level = SND_SOC_BIAS_STANDBY; - } + if (d->idle_bias_off) + d->target_bias_level = SND_SOC_BIAS_OFF; + else + d->target_bias_level = SND_SOC_BIAS_STANDBY; } dapm_reset(card); @@ -1469,32 +1489,6 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) } - /* If there are no DAPM widgets then try to figure out power from the - * event type. - */ - if (!dapm->n_widgets) { - switch (event) { - case SND_SOC_DAPM_STREAM_START: - case SND_SOC_DAPM_STREAM_RESUME: - dapm->target_bias_level = SND_SOC_BIAS_ON; - break; - case SND_SOC_DAPM_STREAM_STOP: - if (dapm->codec && dapm->codec->active) - dapm->target_bias_level = SND_SOC_BIAS_ON; - else - dapm->target_bias_level = SND_SOC_BIAS_STANDBY; - break; - case SND_SOC_DAPM_STREAM_SUSPEND: - dapm->target_bias_level = SND_SOC_BIAS_STANDBY; - break; - case SND_SOC_DAPM_STREAM_NOP: - dapm->target_bias_level = dapm->bias_level; - break; - default: - break; - } - } - /* Force all contexts in the card to the same bias state if * they're not ground referenced. */ @@ -1719,7 +1713,7 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) #endif /* test and update the power status of a mux widget */ -int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, +static int 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; @@ -1758,10 +1752,22 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, return 0; } + +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_card *card = widget->dapm->card; + int ret; + + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e); + mutex_unlock(&card->dapm_mutex); + return ret; +} EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); /* test and update the power status of a mixer or switch widget */ -int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, +static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, int connect) { struct snd_soc_dapm_path *path; @@ -1790,6 +1796,18 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, return 0; } + +int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int connect) +{ + struct snd_soc_card *card = widget->dapm->card; + int ret; + + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + ret = soc_dapm_mixer_update_power(widget, kcontrol, connect); + mutex_unlock(&card->dapm_mutex); + return ret; +} EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); /* show dapm widget status in sys fs */ @@ -1949,6 +1967,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, */ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) { + int ret; + /* * Suppress early reports (eg, jacks syncing their state) to avoid * silly DAPM runs during card startup. @@ -1956,7 +1976,10 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) if (!dapm->card || !dapm->card->instantiated) return 0; - return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); + mutex_unlock(&dapm->card->dapm_mutex); + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); @@ -2122,6 +2145,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, { int i, ret; + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); for (i = 0; i < num; i++) { ret = snd_soc_dapm_add_route(dapm, route); if (ret < 0) { @@ -2131,6 +2155,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, } route++; } + mutex_unlock(&dapm->card->dapm_mutex); return 0; } @@ -2203,12 +2228,14 @@ int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, int i, err; int ret = 0; + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); for (i = 0; i < num; i++) { err = snd_soc_dapm_weak_route(dapm, route); if (err) ret = err; route++; } + mutex_unlock(&dapm->card->dapm_mutex); return ret; } @@ -2227,6 +2254,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) struct snd_soc_dapm_widget *w; unsigned int val; + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); + list_for_each_entry(w, &dapm->card->widgets, list) { if (w->new) @@ -2236,8 +2265,10 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) w->kcontrols = kzalloc(w->num_kcontrols * sizeof(struct snd_kcontrol *), GFP_KERNEL); - if (!w->kcontrols) + if (!w->kcontrols) { + mutex_unlock(&dapm->card->dapm_mutex); return -ENOMEM; + } } switch(w->id) { @@ -2277,6 +2308,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) } dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); + mutex_unlock(&dapm->card->dapm_mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); @@ -2336,6 +2368,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct snd_soc_codec *codec = widget->codec; + struct snd_soc_card *card = codec->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int reg = mc->reg; @@ -2362,7 +2395,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, /* old connection must be powered down */ connect = invert ? 1 : 0; - mutex_lock(&codec->mutex); + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); change = snd_soc_test_bits(widget->codec, reg, mask, val); if (change) { @@ -2378,13 +2411,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - snd_soc_dapm_mixer_update_power(widget, kcontrol, connect); + soc_dapm_mixer_update_power(widget, kcontrol, connect); widget->dapm->update = NULL; } } - mutex_unlock(&codec->mutex); + mutex_unlock(&card->dapm_mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); @@ -2433,6 +2466,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct snd_soc_codec *codec = widget->codec; + struct snd_soc_card *card = codec->card; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int val, mux, change; unsigned int mask, bitmask; @@ -2453,7 +2487,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, mask |= (bitmask - 1) << e->shift_r; } - mutex_lock(&codec->mutex); + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); change = snd_soc_test_bits(widget->codec, e->reg, mask, val); if (change) { @@ -2469,13 +2503,13 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); + soc_dapm_mux_update_power(widget, kcontrol, mux, e); widget->dapm->update = NULL; } } - mutex_unlock(&codec->mutex); + mutex_unlock(&card->dapm_mutex); return change; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); @@ -2512,6 +2546,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct snd_soc_codec *codec = widget->codec; + struct snd_soc_card *card = codec->card; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int change; @@ -2521,7 +2556,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, if (ucontrol->value.enumerated.item[0] >= e->max) return -EINVAL; - mutex_lock(&codec->mutex); + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); change = widget->value != ucontrol->value.enumerated.item[0]; if (change) { @@ -2530,11 +2565,11 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, widget->value = ucontrol->value.enumerated.item[0]; - snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); + soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); } } - mutex_unlock(&codec->mutex); + mutex_unlock(&card->dapm_mutex); return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); @@ -2599,6 +2634,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct snd_soc_codec *codec = widget->codec; + struct snd_soc_card *card = codec->card; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int val, mux, change; unsigned int mask; @@ -2617,7 +2653,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, mask |= e->mask << e->shift_r; } - mutex_lock(&codec->mutex); + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); change = snd_soc_test_bits(widget->codec, e->reg, mask, val); if (change) { @@ -2633,13 +2669,13 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); + soc_dapm_mux_update_power(widget, kcontrol, mux, e); widget->dapm->update = NULL; } } - mutex_unlock(&codec->mutex); + mutex_unlock(&card->dapm_mutex); return change; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); @@ -2676,12 +2712,12 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); const char *pin = (const char *)kcontrol->private_value; - mutex_lock(&card->mutex); + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); ucontrol->value.integer.value[0] = snd_soc_dapm_get_pin_status(&card->dapm, pin); - mutex_unlock(&card->mutex); + mutex_unlock(&card->dapm_mutex); return 0; } @@ -2699,17 +2735,16 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); const char *pin = (const char *)kcontrol->private_value; - mutex_lock(&card->mutex); + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); if (ucontrol->value.integer.value[0]) snd_soc_dapm_enable_pin(&card->dapm, pin); else snd_soc_dapm_disable_pin(&card->dapm, pin); - snd_soc_dapm_sync(&card->dapm); - - mutex_unlock(&card->mutex); + mutex_unlock(&card->dapm_mutex); + snd_soc_dapm_sync(&card->dapm); return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); @@ -2727,9 +2762,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, 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); + w->regulator = devm_regulator_get(dapm->dev, w->name); + if (IS_ERR(w->regulator)) { + ret = PTR_ERR(w->regulator); dev_err(dapm->dev, "Failed to request %s: %d\n", w->name, ret); return NULL; @@ -2827,6 +2862,7 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *w; int i; + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); for (i = 0; i < num; i++) { w = snd_soc_dapm_new_control(dapm, widget); if (!w) { @@ -2837,6 +2873,7 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, } widget++; } + mutex_unlock(&dapm->card->dapm_mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); @@ -2944,37 +2981,61 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) return 0; } -static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, - int stream, struct snd_soc_dai *dai, - int event) +static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, + int event) { - struct snd_soc_dapm_widget *w; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - w = dai->playback_widget; - else - w = dai->capture_widget; + struct snd_soc_dapm_widget *w_cpu, *w_codec; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; - if (!w) - return; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + w_cpu = cpu_dai->playback_widget; + w_codec = codec_dai->playback_widget; + } else { + w_cpu = cpu_dai->capture_widget; + w_codec = codec_dai->capture_widget; + } - dapm_mark_dirty(w, "stream event"); + if (w_cpu) { - 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_mark_dirty(w_cpu, "stream event"); + + switch (event) { + case SND_SOC_DAPM_STREAM_START: + w_cpu->active = 1; + break; + case SND_SOC_DAPM_STREAM_STOP: + w_cpu->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); + if (w_codec) { + + dapm_mark_dirty(w_codec, "stream event"); + + switch (event) { + case SND_SOC_DAPM_STREAM_START: + w_codec->active = 1; + break; + case SND_SOC_DAPM_STREAM_STOP: + w_codec->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(&rtd->card->dapm, event); } /** @@ -2988,15 +3049,14 @@ 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, int stream, - struct snd_soc_dai *dai, int event) +void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, + int event) { - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_card *card = rtd->card; - mutex_lock(&codec->mutex); - soc_dapm_stream_event(&codec->dapm, stream, dai, event); - mutex_unlock(&codec->mutex); - return 0; + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + soc_dapm_stream_event(rtd, stream, event); + mutex_unlock(&card->dapm_mutex); } /**