aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h5
-rw-r--r--include/sound/soc.h1
-rw-r--r--sound/soc/soc-core.c2
-rw-r--r--sound/soc/soc-dapm.c109
4 files changed, 71 insertions, 46 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c0e7c47469fc..98783510d2f1 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -471,6 +471,11 @@ struct snd_soc_dapm_context {
471 struct device *dev; /* from parent - for debug */ 471 struct device *dev; /* from parent - for debug */
472 struct snd_soc_codec *codec; /* parent codec */ 472 struct snd_soc_codec *codec; /* parent codec */
473 struct snd_soc_card *card; /* parent card */ 473 struct snd_soc_card *card; /* parent card */
474
475 /* used during DAPM updates */
476 int dev_power;
477 struct list_head list;
478
474#ifdef CONFIG_DEBUG_FS 479#ifdef CONFIG_DEBUG_FS
475 struct dentry *debugfs_dapm; 480 struct dentry *debugfs_dapm;
476#endif 481#endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
index d5fb8618fdba..74921f20a1d8 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -663,6 +663,7 @@ struct snd_soc_card {
663 663
664 struct list_head widgets; 664 struct list_head widgets;
665 struct list_head paths; 665 struct list_head paths;
666 struct list_head dapm_list;
666 667
667#ifdef CONFIG_DEBUG_FS 668#ifdef CONFIG_DEBUG_FS
668 struct dentry *debugfs_card_root; 669 struct dentry *debugfs_card_root;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index bd183a7ed696..a233607a73c6 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1427,6 +1427,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
1427 /* mark codec as probed and add to card codec list */ 1427 /* mark codec as probed and add to card codec list */
1428 codec->probed = 1; 1428 codec->probed = 1;
1429 list_add(&codec->card_list, &card->codec_dev_list); 1429 list_add(&codec->card_list, &card->codec_dev_list);
1430 list_add(&codec->dapm.list, &card->dapm_list);
1430 1431
1431 return ret; 1432 return ret;
1432} 1433}
@@ -1881,6 +1882,7 @@ static int soc_probe(struct platform_device *pdev)
1881 INIT_LIST_HEAD(&card->platform_dev_list); 1882 INIT_LIST_HEAD(&card->platform_dev_list);
1882 INIT_LIST_HEAD(&card->widgets); 1883 INIT_LIST_HEAD(&card->widgets);
1883 INIT_LIST_HEAD(&card->paths); 1884 INIT_LIST_HEAD(&card->paths);
1885 INIT_LIST_HEAD(&card->dapm_list);
1884 1886
1885 soc_init_card_debugfs(card); 1887 soc_init_card_debugfs(card);
1886 1888
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 8731e89646ae..f362d1de78f3 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -847,19 +847,22 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
847 LIST_HEAD(pending); 847 LIST_HEAD(pending);
848 int cur_sort = -1; 848 int cur_sort = -1;
849 int cur_reg = SND_SOC_NOPM; 849 int cur_reg = SND_SOC_NOPM;
850 struct snd_soc_dapm_context *cur_dapm = NULL;
850 int ret; 851 int ret;
851 852
852 list_for_each_entry_safe(w, n, list, power_list) { 853 list_for_each_entry_safe(w, n, list, power_list) {
853 ret = 0; 854 ret = 0;
854 855
855 /* Do we need to apply any queued changes? */ 856 /* Do we need to apply any queued changes? */
856 if (sort[w->id] != cur_sort || w->reg != cur_reg) { 857 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
858 w->dapm != cur_dapm) {
857 if (!list_empty(&pending)) 859 if (!list_empty(&pending))
858 dapm_seq_run_coalesced(dapm, &pending); 860 dapm_seq_run_coalesced(cur_dapm, &pending);
859 861
860 INIT_LIST_HEAD(&pending); 862 INIT_LIST_HEAD(&pending);
861 cur_sort = -1; 863 cur_sort = -1;
862 cur_reg = SND_SOC_NOPM; 864 cur_reg = SND_SOC_NOPM;
865 cur_dapm = NULL;
863 } 866 }
864 867
865 switch (w->id) { 868 switch (w->id) {
@@ -903,6 +906,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
903 /* Queue it up for application */ 906 /* Queue it up for application */
904 cur_sort = sort[w->id]; 907 cur_sort = sort[w->id];
905 cur_reg = w->reg; 908 cur_reg = w->reg;
909 cur_dapm = w->dapm;
906 list_move(&w->power_list, &pending); 910 list_move(&w->power_list, &pending);
907 break; 911 break;
908 } 912 }
@@ -929,20 +933,22 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
929{ 933{
930 struct snd_soc_card *card = dapm->codec->card; 934 struct snd_soc_card *card = dapm->codec->card;
931 struct snd_soc_dapm_widget *w; 935 struct snd_soc_dapm_widget *w;
936 struct snd_soc_dapm_context *d;
932 LIST_HEAD(up_list); 937 LIST_HEAD(up_list);
933 LIST_HEAD(down_list); 938 LIST_HEAD(down_list);
934 int ret = 0; 939 int ret = 0;
935 int power; 940 int power;
936 int sys_power = 0;
937 941
938 trace_snd_soc_dapm_start(card); 942 trace_snd_soc_dapm_start(card);
939 943
944 list_for_each_entry(d, &card->dapm_list, list)
945 if (d->n_widgets)
946 d->dev_power = 0;
947
940 /* Check which widgets we need to power and store them in 948 /* Check which widgets we need to power and store them in
941 * lists indicating if they should be powered up or down. 949 * lists indicating if they should be powered up or down.
942 */ 950 */
943 list_for_each_entry(w, &card->widgets, list) { 951 list_for_each_entry(w, &card->widgets, list) {
944 if (w->dapm != dapm)
945 continue;
946 switch (w->id) { 952 switch (w->id) {
947 case snd_soc_dapm_pre: 953 case snd_soc_dapm_pre:
948 dapm_seq_insert(w, &down_list, dapm_down_seq); 954 dapm_seq_insert(w, &down_list, dapm_down_seq);
@@ -960,7 +966,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
960 else 966 else
961 power = 1; 967 power = 1;
962 if (power) 968 if (power)
963 sys_power = 1; 969 w->dapm->dev_power = 1;
964 970
965 if (w->power == power) 971 if (w->power == power)
966 continue; 972 continue;
@@ -984,22 +990,22 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
984 switch (event) { 990 switch (event) {
985 case SND_SOC_DAPM_STREAM_START: 991 case SND_SOC_DAPM_STREAM_START:
986 case SND_SOC_DAPM_STREAM_RESUME: 992 case SND_SOC_DAPM_STREAM_RESUME:
987 sys_power = 1; 993 dapm->dev_power = 1;
988 break; 994 break;
989 case SND_SOC_DAPM_STREAM_STOP: 995 case SND_SOC_DAPM_STREAM_STOP:
990 sys_power = !!dapm->codec->active; 996 dapm->dev_power = !!dapm->codec->active;
991 break; 997 break;
992 case SND_SOC_DAPM_STREAM_SUSPEND: 998 case SND_SOC_DAPM_STREAM_SUSPEND:
993 sys_power = 0; 999 dapm->dev_power = 0;
994 break; 1000 break;
995 case SND_SOC_DAPM_STREAM_NOP: 1001 case SND_SOC_DAPM_STREAM_NOP:
996 switch (dapm->bias_level) { 1002 switch (dapm->bias_level) {
997 case SND_SOC_BIAS_STANDBY: 1003 case SND_SOC_BIAS_STANDBY:
998 case SND_SOC_BIAS_OFF: 1004 case SND_SOC_BIAS_OFF:
999 sys_power = 0; 1005 dapm->dev_power = 0;
1000 break; 1006 break;
1001 default: 1007 default:
1002 sys_power = 1; 1008 dapm->dev_power = 1;
1003 break; 1009 break;
1004 } 1010 }
1005 break; 1011 break;
@@ -1008,21 +1014,24 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1008 } 1014 }
1009 } 1015 }
1010 1016
1011 if (sys_power && dapm->bias_level == SND_SOC_BIAS_OFF) { 1017 list_for_each_entry(d, &dapm->card->dapm_list, list) {
1012 ret = snd_soc_dapm_set_bias_level(card, dapm, 1018 if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) {
1013 SND_SOC_BIAS_STANDBY); 1019 ret = snd_soc_dapm_set_bias_level(card, d,
1014 if (ret != 0) 1020 SND_SOC_BIAS_STANDBY);
1015 dev_err(dapm->dev, 1021 if (ret != 0)
1016 "Failed to turn on bias: %d\n", ret); 1022 dev_err(d->dev,
1017 } 1023 "Failed to turn on bias: %d\n", ret);
1024 }
1018 1025
1019 /* If we're changing to all on or all off then prepare */ 1026 /* If we're changing to all on or all off then prepare */
1020 if ((sys_power && dapm->bias_level == SND_SOC_BIAS_STANDBY) || 1027 if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) ||
1021 (!sys_power && dapm->bias_level == SND_SOC_BIAS_ON)) { 1028 (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
1022 ret = snd_soc_dapm_set_bias_level(card, dapm, SND_SOC_BIAS_PREPARE); 1029 ret = snd_soc_dapm_set_bias_level(card, d,
1023 if (ret != 0) 1030 SND_SOC_BIAS_PREPARE);
1024 dev_err(dapm->dev, 1031 if (ret != 0)
1025 "Failed to prepare bias: %d\n", ret); 1032 dev_err(d->dev,
1033 "Failed to prepare bias: %d\n", ret);
1034 }
1026 } 1035 }
1027 1036
1028 /* Power down widgets first; try to avoid amplifying pops. */ 1037 /* Power down widgets first; try to avoid amplifying pops. */
@@ -1031,29 +1040,36 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1031 /* Now power up. */ 1040 /* Now power up. */
1032 dapm_seq_run(dapm, &up_list, event, dapm_up_seq); 1041 dapm_seq_run(dapm, &up_list, event, dapm_up_seq);
1033 1042
1034 /* If we just powered the last thing off drop to standby bias */ 1043 list_for_each_entry(d, &dapm->card->dapm_list, list) {
1035 if (dapm->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) { 1044 /* If we just powered the last thing off drop to standby bias */
1036 ret = snd_soc_dapm_set_bias_level(card, dapm, SND_SOC_BIAS_STANDBY); 1045 if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) {
1037 if (ret != 0) 1046 ret = snd_soc_dapm_set_bias_level(card, d,
1038 dev_err(dapm->dev, 1047 SND_SOC_BIAS_STANDBY);
1039 "Failed to apply standby bias: %d\n", ret); 1048 if (ret != 0)
1040 } 1049 dev_err(d->dev,
1050 "Failed to apply standby bias: %d\n",
1051 ret);
1052 }
1041 1053
1042 /* If we're in standby and can support bias off then do that */ 1054 /* If we're in standby and can support bias off then do that */
1043 if (dapm->bias_level == SND_SOC_BIAS_STANDBY && 1055 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1044 dapm->idle_bias_off) { 1056 d->idle_bias_off) {
1045 ret = snd_soc_dapm_set_bias_level(card, dapm, SND_SOC_BIAS_OFF); 1057 ret = snd_soc_dapm_set_bias_level(card, d,
1046 if (ret != 0) 1058 SND_SOC_BIAS_OFF);
1047 dev_err(dapm->dev, 1059 if (ret != 0)
1048 "Failed to turn off bias: %d\n", ret); 1060 dev_err(d->dev,
1049 } 1061 "Failed to turn off bias: %d\n", ret);
1062 }
1050 1063
1051 /* If we just powered up then move to active bias */ 1064 /* If we just powered up then move to active bias */
1052 if (dapm->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { 1065 if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) {
1053 ret = snd_soc_dapm_set_bias_level(card, dapm, SND_SOC_BIAS_ON); 1066 ret = snd_soc_dapm_set_bias_level(card, d,
1054 if (ret != 0) 1067 SND_SOC_BIAS_ON);
1055 dev_err(dapm->dev, 1068 if (ret != 0)
1056 "Failed to apply active bias: %d\n", ret); 1069 dev_err(d->dev,
1070 "Failed to apply active bias: %d\n",
1071 ret);
1072 }
1057 } 1073 }
1058 1074
1059 pop_dbg(dapm->dev, card->pop_time, 1075 pop_dbg(dapm->dev, card->pop_time,
@@ -2309,6 +2325,7 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
2309{ 2325{
2310 snd_soc_dapm_sys_remove(dapm->dev); 2326 snd_soc_dapm_sys_remove(dapm->dev);
2311 dapm_free_widgets(dapm); 2327 dapm_free_widgets(dapm);
2328 list_del(&dapm->list);
2312} 2329}
2313EXPORT_SYMBOL_GPL(snd_soc_dapm_free); 2330EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
2314 2331