aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h3
-rw-r--r--include/sound/soc.h2
-rw-r--r--sound/soc/soc-dapm.c81
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)
658static int dapm_power_widget(struct snd_soc_codec *codec, int event, 658static 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,
722static int dapm_power_widgets(struct snd_soc_codec *codec, int event) 712static 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