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 | ||
