diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 102 |
1 files changed, 76 insertions, 26 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b9dc6acbba8c..5c01ac1cfc0a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -115,6 +115,12 @@ static int dapm_down_seq[] = { [snd_soc_dapm_post] = 14, }; +static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) +{ + if (dapm->card && dapm->card->instantiated) + lockdep_assert_held(&dapm->card->dapm_mutex); +} + static void pop_wait(u32 pop_time) { if (pop_time) @@ -146,15 +152,16 @@ static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w) return !list_empty(&w->dirty); } -void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) +static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) { + dapm_assert_locked(w->dapm); + if (!dapm_dirty_widget(w)) { dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n", w->name, reason); list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty); } } -EXPORT_SYMBOL_GPL(dapm_mark_dirty); void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) { @@ -361,6 +368,8 @@ static void dapm_reset(struct snd_soc_card *card) { struct snd_soc_dapm_widget *w; + lockdep_assert_held(&card->dapm_mutex); + memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); list_for_each_entry(w, &card->widgets, list) { @@ -386,7 +395,8 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, return -1; } -static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) +static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, + unsigned int val) { if (w->codec) return snd_soc_write(w->codec, reg, val); @@ -506,7 +516,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: { - int val; + unsigned int val; struct soc_mixer_control *mc = (struct soc_mixer_control *) w->kcontrol_news[i].private_value; int reg = mc->reg; @@ -530,7 +540,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_mux: { struct soc_enum *e = (struct soc_enum *) w->kcontrol_news[i].private_value; - int val, item; + unsigned int val, item; soc_widget_read(w, e->reg, &val); item = (val >> e->shift_l) & e->mask; @@ -559,7 +569,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_value_mux: { struct soc_enum *e = (struct soc_enum *) w->kcontrol_news[i].private_value; - int val, item; + unsigned int val, item; soc_widget_read(w, e->reg, &val); val = (val >> e->shift_l) & e->mask; @@ -1823,6 +1833,8 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) ASYNC_DOMAIN_EXCLUSIVE(async_domain); enum snd_soc_bias_level bias; + lockdep_assert_held(&card->dapm_mutex); + trace_snd_soc_dapm_start(card); list_for_each_entry(d, &card->dapm_list, list) { @@ -1897,10 +1909,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) trace_snd_soc_dapm_walk_done(card); - /* Run all the bias changes in parallel */ - list_for_each_entry(d, &card->dapm_list, list) - async_schedule_domain(dapm_pre_sequence_async, d, - &async_domain); + /* Run card bias changes at first */ + 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) + async_schedule_domain(dapm_pre_sequence_async, d, + &async_domain); + } async_synchronize_full_domain(&async_domain); list_for_each_entry(w, &down_list, power_list) { @@ -1920,10 +1936,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) dapm_seq_run(card, &up_list, event, true); /* Run all the bias changes in parallel */ - list_for_each_entry(d, &card->dapm_list, list) - async_schedule_domain(dapm_post_sequence_async, d, - &async_domain); + list_for_each_entry(d, &card->dapm_list, list) { + if (d != &card->dapm) + async_schedule_domain(dapm_post_sequence_async, d, + &async_domain); + } async_synchronize_full_domain(&async_domain); + /* Run card bias changes at last */ + dapm_post_sequence_async(&card->dapm, 0); /* do we need to notify any clients that DAPM event is complete */ list_for_each_entry(d, &card->dapm_list, list) { @@ -2110,6 +2130,8 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card, struct snd_soc_dapm_path *path; int found = 0; + lockdep_assert_held(&card->dapm_mutex); + /* find dapm widget path assoc with kcontrol */ dapm_kcontrol_for_each_path(path, kcontrol) { if (!path->name || !e->texts[mux]) @@ -2160,6 +2182,8 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, struct snd_soc_dapm_path *path; int found = 0; + lockdep_assert_held(&card->dapm_mutex); + /* find dapm widget path assoc with kcontrol */ dapm_kcontrol_for_each_path(path, kcontrol) { found = 1; @@ -2325,6 +2349,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, { struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); + dapm_assert_locked(dapm); + if (!w) { dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); return -EINVAL; @@ -2341,18 +2367,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, } /** - * snd_soc_dapm_sync - scan and power dapm paths + * snd_soc_dapm_sync_unlocked - scan and power dapm paths * @dapm: DAPM context * * Walks all dapm audio paths and powers widgets according to their * stream or path usage. * + * Requires external locking. + * * Returns 0 for success. */ -int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) +int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm) { - int ret; - /* * Suppress early reports (eg, jacks syncing their state) to avoid * silly DAPM runs during card startup. @@ -2360,8 +2386,25 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) if (!dapm->card || !dapm->card->instantiated) return 0; + return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked); + +/** + * snd_soc_dapm_sync - scan and power dapm paths + * @dapm: DAPM context + * + * Walks all dapm audio paths and powers widgets according to their + * stream or path usage. + * + * Returns 0 for success. + */ +int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) +{ + int ret; + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); + ret = snd_soc_dapm_sync_unlocked(dapm); mutex_unlock(&dapm->card->dapm_mutex); return ret; } @@ -4098,7 +4141,7 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) } EXPORT_SYMBOL_GPL(snd_soc_dapm_free); -static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) +static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) { struct snd_soc_card *card = dapm->card; struct snd_soc_dapm_widget *w; @@ -4138,14 +4181,21 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) */ void snd_soc_dapm_shutdown(struct snd_soc_card *card) { - struct snd_soc_codec *codec; - - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - soc_dapm_shutdown_codec(&codec->dapm); - if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) - snd_soc_dapm_set_bias_level(&codec->dapm, - SND_SOC_BIAS_OFF); + struct snd_soc_dapm_context *dapm; + + list_for_each_entry(dapm, &card->dapm_list, list) { + if (dapm != &card->dapm) { + soc_dapm_shutdown_dapm(dapm); + if (dapm->bias_level == SND_SOC_BIAS_STANDBY) + snd_soc_dapm_set_bias_level(dapm, + SND_SOC_BIAS_OFF); + } } + + soc_dapm_shutdown_dapm(&card->dapm); + if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) + snd_soc_dapm_set_bias_level(&card->dapm, + SND_SOC_BIAS_OFF); } /* Module information */ |