diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-05-16 12:47:29 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-05-18 10:53:14 -0400 |
commit | 6d3ddc81f5762d54ce7d1db70eb757c6c12fabbc (patch) | |
tree | b476a394790be86d97d9fc47beff0de6e1186c96 /sound/soc/soc-dapm.c | |
parent | b7a755a8a145a7e34e735bda9c452317de7a538a (diff) |
ASoC: Split DAPM power checks from sequencing of power changes
DAPM has always applied any changes to the power state of widgets as soon
as it has determined that they are required. Instead of doing this store
all the changes that are required on lists of widgets to power up and
down, then iterate over those lists and apply the changes. This changes
the sequence in which changes are implemented, doing all power downs
before power ups and always using the up/down sequences (previously they
were only used when changes were due to DAC/ADC power events). The error
handling is also changed so that we continue attempting to power widgets
if some changes fail.
The main benefit of this is to allow future changes to do optimisations
over the whole power sequence and to reduce the number of walks of the
widget graph required to check the power status of widgets.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 81 |
1 files changed, 56 insertions, 25 deletions
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 | ||