diff options
-rw-r--r-- | include/sound/soc-dapm.h | 3 | ||||
-rw-r--r-- | include/sound/soc.h | 2 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 81 |
3 files changed, 61 insertions, 25 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 533f9f256496..b3f789d0cee8 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -385,6 +385,9 @@ struct snd_soc_dapm_widget { | |||
385 | /* widget input and outputs */ | 385 | /* widget input and outputs */ |
386 | struct list_head sources; | 386 | struct list_head sources; |
387 | struct list_head sinks; | 387 | struct list_head sinks; |
388 | |||
389 | /* used during DAPM updates */ | ||
390 | struct list_head power_list; | ||
388 | }; | 391 | }; |
389 | 392 | ||
390 | #endif | 393 | #endif |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 6ab80bf7abd2..8309ce81cf3b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -372,6 +372,8 @@ struct snd_soc_codec { | |||
372 | enum snd_soc_bias_level bias_level; | 372 | enum snd_soc_bias_level bias_level; |
373 | enum snd_soc_bias_level suspend_bias_level; | 373 | enum snd_soc_bias_level suspend_bias_level; |
374 | struct delayed_work delayed_work; | 374 | struct delayed_work delayed_work; |
375 | struct list_head up_list; | ||
376 | struct list_head down_list; | ||
375 | 377 | ||
376 | /* codec DAI's */ | 378 | /* codec DAI's */ |
377 | struct snd_soc_dai *dai; | 379 | struct snd_soc_dai *dai; |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7847f80e96d1..04ef84106d7c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -658,7 +658,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
658 | static int dapm_power_widget(struct snd_soc_codec *codec, int event, | 658 | static int dapm_power_widget(struct snd_soc_codec *codec, int event, |
659 | struct snd_soc_dapm_widget *w) | 659 | struct snd_soc_dapm_widget *w) |
660 | { | 660 | { |
661 | int power, ret; | 661 | int ret; |
662 | 662 | ||
663 | switch (w->id) { | 663 | switch (w->id) { |
664 | case snd_soc_dapm_pre: | 664 | case snd_soc_dapm_pre: |
@@ -696,18 +696,8 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event, | |||
696 | return 0; | 696 | return 0; |
697 | 697 | ||
698 | default: | 698 | default: |
699 | break; | 699 | return dapm_generic_apply_power(w); |
700 | } | 700 | } |
701 | |||
702 | if (!w->power_check) | ||
703 | return 0; | ||
704 | |||
705 | power = w->power_check(w); | ||
706 | if (w->power == power) | ||
707 | return 0; | ||
708 | w->power = power; | ||
709 | |||
710 | return dapm_generic_apply_power(w); | ||
711 | } | 701 | } |
712 | 702 | ||
713 | /* | 703 | /* |
@@ -722,27 +712,68 @@ static int dapm_power_widget(struct snd_soc_codec *codec, int event, | |||
722 | static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | 712 | static int dapm_power_widgets(struct snd_soc_codec *codec, int event) |
723 | { | 713 | { |
724 | struct snd_soc_dapm_widget *w; | 714 | struct snd_soc_dapm_widget *w; |
725 | int i, c = 1, *seq = NULL, ret = 0; | 715 | int ret = 0; |
726 | 716 | int i, power; | |
727 | /* do we have a sequenced stream event */ | 717 | |
728 | if (event == SND_SOC_DAPM_STREAM_START) { | 718 | INIT_LIST_HEAD(&codec->up_list); |
729 | c = ARRAY_SIZE(dapm_up_seq); | 719 | INIT_LIST_HEAD(&codec->down_list); |
730 | seq = dapm_up_seq; | 720 | |
731 | } else if (event == SND_SOC_DAPM_STREAM_STOP) { | 721 | /* Check which widgets we need to power and store them in |
732 | c = ARRAY_SIZE(dapm_down_seq); | 722 | * lists indicating if they should be powered up or down. |
733 | seq = dapm_down_seq; | 723 | */ |
724 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
725 | switch (w->id) { | ||
726 | case snd_soc_dapm_pre: | ||
727 | list_add_tail(&codec->down_list, &w->power_list); | ||
728 | break; | ||
729 | case snd_soc_dapm_post: | ||
730 | list_add_tail(&codec->up_list, &w->power_list); | ||
731 | break; | ||
732 | |||
733 | default: | ||
734 | if (!w->power_check) | ||
735 | continue; | ||
736 | |||
737 | power = w->power_check(w); | ||
738 | if (w->power == power) | ||
739 | continue; | ||
740 | |||
741 | if (power) | ||
742 | list_add_tail(&w->power_list, &codec->up_list); | ||
743 | else | ||
744 | list_add_tail(&w->power_list, | ||
745 | &codec->down_list); | ||
746 | |||
747 | w->power = power; | ||
748 | break; | ||
749 | } | ||
734 | } | 750 | } |
735 | 751 | ||
736 | for (i = 0; i < c; i++) { | 752 | /* Power down widgets first; try to avoid amplifying pops. */ |
737 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 753 | for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) { |
754 | list_for_each_entry(w, &codec->down_list, power_list) { | ||
755 | /* is widget in stream order */ | ||
756 | if (w->id != dapm_down_seq[i]) | ||
757 | continue; | ||
758 | |||
759 | ret = dapm_power_widget(codec, event, w); | ||
760 | if (ret != 0) | ||
761 | pr_err("Failed to power down %s: %d\n", | ||
762 | w->name, ret); | ||
763 | } | ||
764 | } | ||
738 | 765 | ||
766 | /* Now power up. */ | ||
767 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) { | ||
768 | list_for_each_entry(w, &codec->up_list, power_list) { | ||
739 | /* is widget in stream order */ | 769 | /* is widget in stream order */ |
740 | if (seq && seq[i] && w->id != seq[i]) | 770 | if (w->id != dapm_up_seq[i]) |
741 | continue; | 771 | continue; |
742 | 772 | ||
743 | ret = dapm_power_widget(codec, event, w); | 773 | ret = dapm_power_widget(codec, event, w); |
744 | if (ret != 0) | 774 | if (ret != 0) |
745 | return ret; | 775 | pr_err("Failed to power up %s: %d\n", |
776 | w->name, ret); | ||
746 | } | 777 | } |
747 | } | 778 | } |
748 | 779 | ||