diff options
-rw-r--r-- | include/sound/soc-dapm.h | 5 | ||||
-rw-r--r-- | include/sound/soc.h | 1 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 2 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 109 |
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 | } |
2313 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); | 2330 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); |
2314 | 2331 | ||