diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 257 |
1 files changed, 172 insertions, 85 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1790f83ee665..81c4052c127c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/moduleparam.h> | 33 | #include <linux/moduleparam.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/async.h> | ||
35 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
36 | #include <linux/pm.h> | 37 | #include <linux/pm.h> |
37 | #include <linux/bitops.h> | 38 | #include <linux/bitops.h> |
@@ -125,17 +126,17 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | |||
125 | 126 | ||
126 | /** | 127 | /** |
127 | * snd_soc_dapm_set_bias_level - set the bias level for the system | 128 | * snd_soc_dapm_set_bias_level - set the bias level for the system |
128 | * @card: audio device | 129 | * @dapm: DAPM context |
129 | * @level: level to configure | 130 | * @level: level to configure |
130 | * | 131 | * |
131 | * Configure the bias (power) levels for the SoC audio device. | 132 | * Configure the bias (power) levels for the SoC audio device. |
132 | * | 133 | * |
133 | * Returns 0 for success else error. | 134 | * Returns 0 for success else error. |
134 | */ | 135 | */ |
135 | static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card, | 136 | static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, |
136 | struct snd_soc_dapm_context *dapm, | ||
137 | enum snd_soc_bias_level level) | 137 | enum snd_soc_bias_level level) |
138 | { | 138 | { |
139 | struct snd_soc_card *card = dapm->card; | ||
139 | int ret = 0; | 140 | int ret = 0; |
140 | 141 | ||
141 | switch (level) { | 142 | switch (level) { |
@@ -365,9 +366,20 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | |||
365 | struct snd_soc_dapm_widget *w) | 366 | struct snd_soc_dapm_widget *w) |
366 | { | 367 | { |
367 | int i, ret = 0; | 368 | int i, ret = 0; |
368 | size_t name_len; | 369 | size_t name_len, prefix_len; |
369 | struct snd_soc_dapm_path *path; | 370 | struct snd_soc_dapm_path *path; |
370 | struct snd_card *card = dapm->codec->card->snd_card; | 371 | struct snd_card *card = dapm->card->snd_card; |
372 | const char *prefix; | ||
373 | |||
374 | if (dapm->codec) | ||
375 | prefix = dapm->codec->name_prefix; | ||
376 | else | ||
377 | prefix = NULL; | ||
378 | |||
379 | if (prefix) | ||
380 | prefix_len = strlen(prefix) + 1; | ||
381 | else | ||
382 | prefix_len = 0; | ||
371 | 383 | ||
372 | /* add kcontrol */ | 384 | /* add kcontrol */ |
373 | for (i = 0; i < w->num_kcontrols; i++) { | 385 | for (i = 0; i < w->num_kcontrols; i++) { |
@@ -396,8 +408,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | |||
396 | 408 | ||
397 | switch (w->id) { | 409 | switch (w->id) { |
398 | default: | 410 | default: |
411 | /* The control will get a prefix from | ||
412 | * the control creation process but | ||
413 | * we're also using the same prefix | ||
414 | * for widgets so cut the prefix off | ||
415 | * the front of the widget name. | ||
416 | */ | ||
399 | snprintf(path->long_name, name_len, "%s %s", | 417 | snprintf(path->long_name, name_len, "%s %s", |
400 | w->name, w->kcontrols[i].name); | 418 | w->name + prefix_len, |
419 | w->kcontrols[i].name); | ||
401 | break; | 420 | break; |
402 | case snd_soc_dapm_mixer_named_ctl: | 421 | case snd_soc_dapm_mixer_named_ctl: |
403 | snprintf(path->long_name, name_len, "%s", | 422 | snprintf(path->long_name, name_len, "%s", |
@@ -408,7 +427,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | |||
408 | path->long_name[name_len - 1] = '\0'; | 427 | path->long_name[name_len - 1] = '\0'; |
409 | 428 | ||
410 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, | 429 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, |
411 | path->long_name); | 430 | path->long_name, prefix); |
412 | ret = snd_ctl_add(card, path->kcontrol); | 431 | ret = snd_ctl_add(card, path->kcontrol); |
413 | if (ret < 0) { | 432 | if (ret < 0) { |
414 | dev_err(dapm->dev, | 433 | dev_err(dapm->dev, |
@@ -429,7 +448,9 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm, | |||
429 | { | 448 | { |
430 | struct snd_soc_dapm_path *path = NULL; | 449 | struct snd_soc_dapm_path *path = NULL; |
431 | struct snd_kcontrol *kcontrol; | 450 | struct snd_kcontrol *kcontrol; |
432 | struct snd_card *card = dapm->codec->card->snd_card; | 451 | struct snd_card *card = dapm->card->snd_card; |
452 | const char *prefix; | ||
453 | size_t prefix_len; | ||
433 | int ret = 0; | 454 | int ret = 0; |
434 | 455 | ||
435 | if (!w->num_kcontrols) { | 456 | if (!w->num_kcontrols) { |
@@ -437,7 +458,22 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm, | |||
437 | return -EINVAL; | 458 | return -EINVAL; |
438 | } | 459 | } |
439 | 460 | ||
440 | kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); | 461 | if (dapm->codec) |
462 | prefix = dapm->codec->name_prefix; | ||
463 | else | ||
464 | prefix = NULL; | ||
465 | |||
466 | if (prefix) | ||
467 | prefix_len = strlen(prefix) + 1; | ||
468 | else | ||
469 | prefix_len = 0; | ||
470 | |||
471 | /* The control will get a prefix from the control creation | ||
472 | * process but we're also using the same prefix for widgets so | ||
473 | * cut the prefix off the front of the widget name. | ||
474 | */ | ||
475 | kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name + prefix_len, | ||
476 | prefix); | ||
441 | ret = snd_ctl_add(card, kcontrol); | 477 | ret = snd_ctl_add(card, kcontrol); |
442 | 478 | ||
443 | if (ret < 0) | 479 | if (ret < 0) |
@@ -479,7 +515,7 @@ static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm) | |||
479 | */ | 515 | */ |
480 | static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) | 516 | static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) |
481 | { | 517 | { |
482 | int level = snd_power_get_state(widget->dapm->codec->card->snd_card); | 518 | int level = snd_power_get_state(widget->dapm->card->snd_card); |
483 | 519 | ||
484 | switch (level) { | 520 | switch (level) { |
485 | case SNDRV_CTL_POWER_D3hot: | 521 | case SNDRV_CTL_POWER_D3hot: |
@@ -734,10 +770,23 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
734 | 770 | ||
735 | static int dapm_seq_compare(struct snd_soc_dapm_widget *a, | 771 | static int dapm_seq_compare(struct snd_soc_dapm_widget *a, |
736 | struct snd_soc_dapm_widget *b, | 772 | struct snd_soc_dapm_widget *b, |
737 | int sort[]) | 773 | bool power_up) |
738 | { | 774 | { |
775 | int *sort; | ||
776 | |||
777 | if (power_up) | ||
778 | sort = dapm_up_seq; | ||
779 | else | ||
780 | sort = dapm_down_seq; | ||
781 | |||
739 | if (sort[a->id] != sort[b->id]) | 782 | if (sort[a->id] != sort[b->id]) |
740 | return sort[a->id] - sort[b->id]; | 783 | return sort[a->id] - sort[b->id]; |
784 | if (a->subseq != b->subseq) { | ||
785 | if (power_up) | ||
786 | return a->subseq - b->subseq; | ||
787 | else | ||
788 | return b->subseq - a->subseq; | ||
789 | } | ||
741 | if (a->reg != b->reg) | 790 | if (a->reg != b->reg) |
742 | return a->reg - b->reg; | 791 | return a->reg - b->reg; |
743 | if (a->dapm != b->dapm) | 792 | if (a->dapm != b->dapm) |
@@ -749,12 +798,12 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, | |||
749 | /* Insert a widget in order into a DAPM power sequence. */ | 798 | /* Insert a widget in order into a DAPM power sequence. */ |
750 | static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, | 799 | static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, |
751 | struct list_head *list, | 800 | struct list_head *list, |
752 | int sort[]) | 801 | bool power_up) |
753 | { | 802 | { |
754 | struct snd_soc_dapm_widget *w; | 803 | struct snd_soc_dapm_widget *w; |
755 | 804 | ||
756 | list_for_each_entry(w, list, power_list) | 805 | list_for_each_entry(w, list, power_list) |
757 | if (dapm_seq_compare(new_widget, w, sort) < 0) { | 806 | if (dapm_seq_compare(new_widget, w, power_up) < 0) { |
758 | list_add_tail(&new_widget->power_list, &w->power_list); | 807 | list_add_tail(&new_widget->power_list, &w->power_list); |
759 | return; | 808 | return; |
760 | } | 809 | } |
@@ -865,26 +914,42 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
865 | * handled. | 914 | * handled. |
866 | */ | 915 | */ |
867 | static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | 916 | static void dapm_seq_run(struct snd_soc_dapm_context *dapm, |
868 | struct list_head *list, int event, int sort[]) | 917 | struct list_head *list, int event, bool power_up) |
869 | { | 918 | { |
870 | struct snd_soc_dapm_widget *w, *n; | 919 | struct snd_soc_dapm_widget *w, *n; |
871 | LIST_HEAD(pending); | 920 | LIST_HEAD(pending); |
872 | int cur_sort = -1; | 921 | int cur_sort = -1; |
922 | int cur_subseq = -1; | ||
873 | int cur_reg = SND_SOC_NOPM; | 923 | int cur_reg = SND_SOC_NOPM; |
874 | struct snd_soc_dapm_context *cur_dapm = NULL; | 924 | struct snd_soc_dapm_context *cur_dapm = NULL; |
875 | int ret; | 925 | int ret, i; |
926 | int *sort; | ||
927 | |||
928 | if (power_up) | ||
929 | sort = dapm_up_seq; | ||
930 | else | ||
931 | sort = dapm_down_seq; | ||
876 | 932 | ||
877 | list_for_each_entry_safe(w, n, list, power_list) { | 933 | list_for_each_entry_safe(w, n, list, power_list) { |
878 | ret = 0; | 934 | ret = 0; |
879 | 935 | ||
880 | /* Do we need to apply any queued changes? */ | 936 | /* Do we need to apply any queued changes? */ |
881 | if (sort[w->id] != cur_sort || w->reg != cur_reg || | 937 | if (sort[w->id] != cur_sort || w->reg != cur_reg || |
882 | w->dapm != cur_dapm) { | 938 | w->dapm != cur_dapm || w->subseq != cur_subseq) { |
883 | if (!list_empty(&pending)) | 939 | if (!list_empty(&pending)) |
884 | dapm_seq_run_coalesced(cur_dapm, &pending); | 940 | dapm_seq_run_coalesced(cur_dapm, &pending); |
885 | 941 | ||
942 | if (cur_dapm && cur_dapm->seq_notifier) { | ||
943 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | ||
944 | if (sort[i] == cur_sort) | ||
945 | cur_dapm->seq_notifier(cur_dapm, | ||
946 | i, | ||
947 | cur_subseq); | ||
948 | } | ||
949 | |||
886 | INIT_LIST_HEAD(&pending); | 950 | INIT_LIST_HEAD(&pending); |
887 | cur_sort = -1; | 951 | cur_sort = -1; |
952 | cur_subseq = -1; | ||
888 | cur_reg = SND_SOC_NOPM; | 953 | cur_reg = SND_SOC_NOPM; |
889 | cur_dapm = NULL; | 954 | cur_dapm = NULL; |
890 | } | 955 | } |
@@ -929,6 +994,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
929 | default: | 994 | default: |
930 | /* Queue it up for application */ | 995 | /* Queue it up for application */ |
931 | cur_sort = sort[w->id]; | 996 | cur_sort = sort[w->id]; |
997 | cur_subseq = w->subseq; | ||
932 | cur_reg = w->reg; | 998 | cur_reg = w->reg; |
933 | cur_dapm = w->dapm; | 999 | cur_dapm = w->dapm; |
934 | list_move(&w->power_list, &pending); | 1000 | list_move(&w->power_list, &pending); |
@@ -942,6 +1008,13 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
942 | 1008 | ||
943 | if (!list_empty(&pending)) | 1009 | if (!list_empty(&pending)) |
944 | dapm_seq_run_coalesced(cur_dapm, &pending); | 1010 | dapm_seq_run_coalesced(cur_dapm, &pending); |
1011 | |||
1012 | if (cur_dapm && cur_dapm->seq_notifier) { | ||
1013 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | ||
1014 | if (sort[i] == cur_sort) | ||
1015 | cur_dapm->seq_notifier(cur_dapm, | ||
1016 | i, cur_subseq); | ||
1017 | } | ||
945 | } | 1018 | } |
946 | 1019 | ||
947 | static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | 1020 | static void dapm_widget_update(struct snd_soc_dapm_context *dapm) |
@@ -977,7 +1050,62 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | |||
977 | } | 1050 | } |
978 | } | 1051 | } |
979 | 1052 | ||
1053 | /* Async callback run prior to DAPM sequences - brings to _PREPARE if | ||
1054 | * they're changing state. | ||
1055 | */ | ||
1056 | static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) | ||
1057 | { | ||
1058 | struct snd_soc_dapm_context *d = data; | ||
1059 | int ret; | ||
980 | 1060 | ||
1061 | if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) { | ||
1062 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); | ||
1063 | if (ret != 0) | ||
1064 | dev_err(d->dev, | ||
1065 | "Failed to turn on bias: %d\n", ret); | ||
1066 | } | ||
1067 | |||
1068 | /* If we're changing to all on or all off then prepare */ | ||
1069 | if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) || | ||
1070 | (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) { | ||
1071 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); | ||
1072 | if (ret != 0) | ||
1073 | dev_err(d->dev, | ||
1074 | "Failed to prepare bias: %d\n", ret); | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | /* Async callback run prior to DAPM sequences - brings to their final | ||
1079 | * state. | ||
1080 | */ | ||
1081 | static void dapm_post_sequence_async(void *data, async_cookie_t cookie) | ||
1082 | { | ||
1083 | struct snd_soc_dapm_context *d = data; | ||
1084 | int ret; | ||
1085 | |||
1086 | /* If we just powered the last thing off drop to standby bias */ | ||
1087 | if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) { | ||
1088 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); | ||
1089 | if (ret != 0) | ||
1090 | dev_err(d->dev, "Failed to apply standby bias: %d\n", | ||
1091 | ret); | ||
1092 | } | ||
1093 | |||
1094 | /* If we're in standby and can support bias off then do that */ | ||
1095 | if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) { | ||
1096 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); | ||
1097 | if (ret != 0) | ||
1098 | dev_err(d->dev, "Failed to turn off bias: %d\n", ret); | ||
1099 | } | ||
1100 | |||
1101 | /* If we just powered up then move to active bias */ | ||
1102 | if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) { | ||
1103 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); | ||
1104 | if (ret != 0) | ||
1105 | dev_err(d->dev, "Failed to apply active bias: %d\n", | ||
1106 | ret); | ||
1107 | } | ||
1108 | } | ||
981 | 1109 | ||
982 | /* | 1110 | /* |
983 | * Scan each dapm widget for complete audio path. | 1111 | * Scan each dapm widget for complete audio path. |
@@ -990,12 +1118,12 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | |||
990 | */ | 1118 | */ |
991 | static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | 1119 | static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) |
992 | { | 1120 | { |
993 | struct snd_soc_card *card = dapm->codec->card; | 1121 | struct snd_soc_card *card = dapm->card; |
994 | struct snd_soc_dapm_widget *w; | 1122 | struct snd_soc_dapm_widget *w; |
995 | struct snd_soc_dapm_context *d; | 1123 | struct snd_soc_dapm_context *d; |
996 | LIST_HEAD(up_list); | 1124 | LIST_HEAD(up_list); |
997 | LIST_HEAD(down_list); | 1125 | LIST_HEAD(down_list); |
998 | int ret = 0; | 1126 | LIST_HEAD(async_domain); |
999 | int power; | 1127 | int power; |
1000 | 1128 | ||
1001 | trace_snd_soc_dapm_start(card); | 1129 | trace_snd_soc_dapm_start(card); |
@@ -1010,10 +1138,10 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1010 | list_for_each_entry(w, &card->widgets, list) { | 1138 | list_for_each_entry(w, &card->widgets, list) { |
1011 | switch (w->id) { | 1139 | switch (w->id) { |
1012 | case snd_soc_dapm_pre: | 1140 | case snd_soc_dapm_pre: |
1013 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 1141 | dapm_seq_insert(w, &down_list, false); |
1014 | break; | 1142 | break; |
1015 | case snd_soc_dapm_post: | 1143 | case snd_soc_dapm_post: |
1016 | dapm_seq_insert(w, &up_list, dapm_up_seq); | 1144 | dapm_seq_insert(w, &up_list, true); |
1017 | break; | 1145 | break; |
1018 | 1146 | ||
1019 | default: | 1147 | default: |
@@ -1033,9 +1161,9 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1033 | trace_snd_soc_dapm_widget_power(w, power); | 1161 | trace_snd_soc_dapm_widget_power(w, power); |
1034 | 1162 | ||
1035 | if (power) | 1163 | if (power) |
1036 | dapm_seq_insert(w, &up_list, dapm_up_seq); | 1164 | dapm_seq_insert(w, &up_list, true); |
1037 | else | 1165 | else |
1038 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 1166 | dapm_seq_insert(w, &down_list, false); |
1039 | 1167 | ||
1040 | w->power = power; | 1168 | w->power = power; |
1041 | break; | 1169 | break; |
@@ -1073,65 +1201,25 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1073 | } | 1201 | } |
1074 | } | 1202 | } |
1075 | 1203 | ||
1076 | list_for_each_entry(d, &dapm->card->dapm_list, list) { | 1204 | /* Run all the bias changes in parallel */ |
1077 | if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) { | 1205 | list_for_each_entry(d, &dapm->card->dapm_list, list) |
1078 | ret = snd_soc_dapm_set_bias_level(card, d, | 1206 | async_schedule_domain(dapm_pre_sequence_async, d, |
1079 | SND_SOC_BIAS_STANDBY); | 1207 | &async_domain); |
1080 | if (ret != 0) | 1208 | async_synchronize_full_domain(&async_domain); |
1081 | dev_err(d->dev, | ||
1082 | "Failed to turn on bias: %d\n", ret); | ||
1083 | } | ||
1084 | |||
1085 | /* If we're changing to all on or all off then prepare */ | ||
1086 | if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) || | ||
1087 | (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) { | ||
1088 | ret = snd_soc_dapm_set_bias_level(card, d, | ||
1089 | SND_SOC_BIAS_PREPARE); | ||
1090 | if (ret != 0) | ||
1091 | dev_err(d->dev, | ||
1092 | "Failed to prepare bias: %d\n", ret); | ||
1093 | } | ||
1094 | } | ||
1095 | 1209 | ||
1096 | /* Power down widgets first; try to avoid amplifying pops. */ | 1210 | /* Power down widgets first; try to avoid amplifying pops. */ |
1097 | dapm_seq_run(dapm, &down_list, event, dapm_down_seq); | 1211 | dapm_seq_run(dapm, &down_list, event, false); |
1098 | 1212 | ||
1099 | dapm_widget_update(dapm); | 1213 | dapm_widget_update(dapm); |
1100 | 1214 | ||
1101 | /* Now power up. */ | 1215 | /* Now power up. */ |
1102 | dapm_seq_run(dapm, &up_list, event, dapm_up_seq); | 1216 | dapm_seq_run(dapm, &up_list, event, true); |
1103 | |||
1104 | list_for_each_entry(d, &dapm->card->dapm_list, list) { | ||
1105 | /* If we just powered the last thing off drop to standby bias */ | ||
1106 | if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) { | ||
1107 | ret = snd_soc_dapm_set_bias_level(card, d, | ||
1108 | SND_SOC_BIAS_STANDBY); | ||
1109 | if (ret != 0) | ||
1110 | dev_err(d->dev, | ||
1111 | "Failed to apply standby bias: %d\n", | ||
1112 | ret); | ||
1113 | } | ||
1114 | 1217 | ||
1115 | /* If we're in standby and can support bias off then do that */ | 1218 | /* Run all the bias changes in parallel */ |
1116 | if (d->bias_level == SND_SOC_BIAS_STANDBY && | 1219 | list_for_each_entry(d, &dapm->card->dapm_list, list) |
1117 | d->idle_bias_off) { | 1220 | async_schedule_domain(dapm_post_sequence_async, d, |
1118 | ret = snd_soc_dapm_set_bias_level(card, d, | 1221 | &async_domain); |
1119 | SND_SOC_BIAS_OFF); | 1222 | async_synchronize_full_domain(&async_domain); |
1120 | if (ret != 0) | ||
1121 | dev_err(d->dev, | ||
1122 | "Failed to turn off bias: %d\n", ret); | ||
1123 | } | ||
1124 | |||
1125 | /* If we just powered up then move to active bias */ | ||
1126 | if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) { | ||
1127 | ret = snd_soc_dapm_set_bias_level(card, d, | ||
1128 | SND_SOC_BIAS_ON); | ||
1129 | if (ret != 0) | ||
1130 | dev_err(d->dev, | ||
1131 | "Failed to apply active bias: %d\n", | ||
1132 | ret); | ||
1133 | } | ||
1134 | } | ||
1135 | 1223 | ||
1136 | pop_dbg(dapm->dev, card->pop_time, | 1224 | pop_dbg(dapm->dev, card->pop_time, |
1137 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); | 1225 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); |
@@ -1189,7 +1277,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1189 | 1277 | ||
1190 | if (p->connect) | 1278 | if (p->connect) |
1191 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1279 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1192 | " in %s %s\n", | 1280 | " in \"%s\" \"%s\"\n", |
1193 | p->name ? p->name : "static", | 1281 | p->name ? p->name : "static", |
1194 | p->source->name); | 1282 | p->source->name); |
1195 | } | 1283 | } |
@@ -1199,7 +1287,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1199 | 1287 | ||
1200 | if (p->connect) | 1288 | if (p->connect) |
1201 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1289 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1202 | " out %s %s\n", | 1290 | " out \"%s\" \"%s\"\n", |
1203 | p->name ? p->name : "static", | 1291 | p->name ? p->name : "static", |
1204 | p->sink->name); | 1292 | p->sink->name); |
1205 | } | 1293 | } |
@@ -1464,7 +1552,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
1464 | char prefixed_source[80]; | 1552 | char prefixed_source[80]; |
1465 | int ret = 0; | 1553 | int ret = 0; |
1466 | 1554 | ||
1467 | if (dapm->codec->name_prefix) { | 1555 | if (dapm->codec && dapm->codec->name_prefix) { |
1468 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | 1556 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", |
1469 | dapm->codec->name_prefix, route->sink); | 1557 | dapm->codec->name_prefix, route->sink); |
1470 | sink = prefixed_sink; | 1558 | sink = prefixed_sink; |
@@ -2114,14 +2202,14 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2114 | return -ENOMEM; | 2202 | return -ENOMEM; |
2115 | 2203 | ||
2116 | name_len = strlen(widget->name) + 1; | 2204 | name_len = strlen(widget->name) + 1; |
2117 | if (dapm->codec->name_prefix) | 2205 | if (dapm->codec && dapm->codec->name_prefix) |
2118 | name_len += 1 + strlen(dapm->codec->name_prefix); | 2206 | name_len += 1 + strlen(dapm->codec->name_prefix); |
2119 | w->name = kmalloc(name_len, GFP_KERNEL); | 2207 | w->name = kmalloc(name_len, GFP_KERNEL); |
2120 | if (w->name == NULL) { | 2208 | if (w->name == NULL) { |
2121 | kfree(w); | 2209 | kfree(w); |
2122 | return -ENOMEM; | 2210 | return -ENOMEM; |
2123 | } | 2211 | } |
2124 | if (dapm->codec->name_prefix) | 2212 | if (dapm->codec && dapm->codec->name_prefix) |
2125 | snprintf(w->name, name_len, "%s %s", | 2213 | snprintf(w->name, name_len, "%s %s", |
2126 | dapm->codec->name_prefix, widget->name); | 2214 | dapm->codec->name_prefix, widget->name); |
2127 | else | 2215 | else |
@@ -2226,7 +2314,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, | |||
2226 | mutex_unlock(&codec->mutex); | 2314 | mutex_unlock(&codec->mutex); |
2227 | return 0; | 2315 | return 0; |
2228 | } | 2316 | } |
2229 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | ||
2230 | 2317 | ||
2231 | /** | 2318 | /** |
2232 | * snd_soc_dapm_enable_pin - enable pin. | 2319 | * snd_soc_dapm_enable_pin - enable pin. |
@@ -2393,7 +2480,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
2393 | if (w->dapm != dapm) | 2480 | if (w->dapm != dapm) |
2394 | continue; | 2481 | continue; |
2395 | if (w->power) { | 2482 | if (w->power) { |
2396 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 2483 | dapm_seq_insert(w, &down_list, false); |
2397 | w->power = 0; | 2484 | w->power = 0; |
2398 | powerdown = 1; | 2485 | powerdown = 1; |
2399 | } | 2486 | } |
@@ -2403,9 +2490,9 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
2403 | * standby. | 2490 | * standby. |
2404 | */ | 2491 | */ |
2405 | if (powerdown) { | 2492 | if (powerdown) { |
2406 | snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_PREPARE); | 2493 | snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE); |
2407 | dapm_seq_run(dapm, &down_list, 0, dapm_down_seq); | 2494 | dapm_seq_run(dapm, &down_list, 0, false); |
2408 | snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_STANDBY); | 2495 | snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); |
2409 | } | 2496 | } |
2410 | } | 2497 | } |
2411 | 2498 | ||
@@ -2418,7 +2505,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card) | |||
2418 | 2505 | ||
2419 | list_for_each_entry(codec, &card->codec_dev_list, list) { | 2506 | list_for_each_entry(codec, &card->codec_dev_list, list) { |
2420 | soc_dapm_shutdown_codec(&codec->dapm); | 2507 | soc_dapm_shutdown_codec(&codec->dapm); |
2421 | snd_soc_dapm_set_bias_level(card, &codec->dapm, SND_SOC_BIAS_OFF); | 2508 | snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF); |
2422 | } | 2509 | } |
2423 | } | 2510 | } |
2424 | 2511 | ||