diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 578 |
1 files changed, 447 insertions, 131 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dc7dbfe61cd0..90ee77d2409d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -52,6 +52,7 @@ static int dapm_up_seq[] = { | |||
52 | [snd_soc_dapm_supply] = 1, | 52 | [snd_soc_dapm_supply] = 1, |
53 | [snd_soc_dapm_regulator_supply] = 1, | 53 | [snd_soc_dapm_regulator_supply] = 1, |
54 | [snd_soc_dapm_micbias] = 2, | 54 | [snd_soc_dapm_micbias] = 2, |
55 | [snd_soc_dapm_dai_link] = 2, | ||
55 | [snd_soc_dapm_dai] = 3, | 56 | [snd_soc_dapm_dai] = 3, |
56 | [snd_soc_dapm_aif_in] = 3, | 57 | [snd_soc_dapm_aif_in] = 3, |
57 | [snd_soc_dapm_aif_out] = 3, | 58 | [snd_soc_dapm_aif_out] = 3, |
@@ -90,9 +91,10 @@ static int dapm_down_seq[] = { | |||
90 | [snd_soc_dapm_aif_in] = 10, | 91 | [snd_soc_dapm_aif_in] = 10, |
91 | [snd_soc_dapm_aif_out] = 10, | 92 | [snd_soc_dapm_aif_out] = 10, |
92 | [snd_soc_dapm_dai] = 10, | 93 | [snd_soc_dapm_dai] = 10, |
93 | [snd_soc_dapm_regulator_supply] = 11, | 94 | [snd_soc_dapm_dai_link] = 11, |
94 | [snd_soc_dapm_supply] = 11, | 95 | [snd_soc_dapm_regulator_supply] = 12, |
95 | [snd_soc_dapm_post] = 12, | 96 | [snd_soc_dapm_supply] = 12, |
97 | [snd_soc_dapm_post] = 13, | ||
96 | }; | 98 | }; |
97 | 99 | ||
98 | static void pop_wait(u32 pop_time) | 100 | static void pop_wait(u32 pop_time) |
@@ -208,7 +210,23 @@ static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) | |||
208 | return -1; | 210 | return -1; |
209 | } | 211 | } |
210 | 212 | ||
211 | static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, | 213 | static inline void soc_widget_lock(struct snd_soc_dapm_widget *w) |
214 | { | ||
215 | if (w->codec && !w->codec->using_regmap) | ||
216 | mutex_lock(&w->codec->mutex); | ||
217 | else if (w->platform) | ||
218 | mutex_lock(&w->platform->mutex); | ||
219 | } | ||
220 | |||
221 | static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w) | ||
222 | { | ||
223 | if (w->codec && !w->codec->using_regmap) | ||
224 | mutex_unlock(&w->codec->mutex); | ||
225 | else if (w->platform) | ||
226 | mutex_unlock(&w->platform->mutex); | ||
227 | } | ||
228 | |||
229 | static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w, | ||
212 | unsigned short reg, unsigned int mask, unsigned int value) | 230 | unsigned short reg, unsigned int mask, unsigned int value) |
213 | { | 231 | { |
214 | bool change; | 232 | bool change; |
@@ -221,18 +239,24 @@ static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, | |||
221 | if (ret != 0) | 239 | if (ret != 0) |
222 | return ret; | 240 | return ret; |
223 | } else { | 241 | } else { |
242 | soc_widget_lock(w); | ||
224 | ret = soc_widget_read(w, reg); | 243 | ret = soc_widget_read(w, reg); |
225 | if (ret < 0) | 244 | if (ret < 0) { |
245 | soc_widget_unlock(w); | ||
226 | return ret; | 246 | return ret; |
247 | } | ||
227 | 248 | ||
228 | old = ret; | 249 | old = ret; |
229 | new = (old & ~mask) | (value & mask); | 250 | new = (old & ~mask) | (value & mask); |
230 | change = old != new; | 251 | change = old != new; |
231 | if (change) { | 252 | if (change) { |
232 | ret = soc_widget_write(w, reg, new); | 253 | ret = soc_widget_write(w, reg, new); |
233 | if (ret < 0) | 254 | if (ret < 0) { |
255 | soc_widget_unlock(w); | ||
234 | return ret; | 256 | return ret; |
257 | } | ||
235 | } | 258 | } |
259 | soc_widget_unlock(w); | ||
236 | } | 260 | } |
237 | 261 | ||
238 | return change; | 262 | return change; |
@@ -374,6 +398,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
374 | case snd_soc_dapm_mic: | 398 | case snd_soc_dapm_mic: |
375 | case snd_soc_dapm_spk: | 399 | case snd_soc_dapm_spk: |
376 | case snd_soc_dapm_line: | 400 | case snd_soc_dapm_line: |
401 | case snd_soc_dapm_dai_link: | ||
377 | p->connect = 1; | 402 | p->connect = 1; |
378 | break; | 403 | break; |
379 | /* does affect routing - dynamically connected */ | 404 | /* does affect routing - dynamically connected */ |
@@ -682,11 +707,51 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) | |||
682 | } | 707 | } |
683 | } | 708 | } |
684 | 709 | ||
710 | /* add widget to list if it's not already in the list */ | ||
711 | static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list, | ||
712 | struct snd_soc_dapm_widget *w) | ||
713 | { | ||
714 | struct snd_soc_dapm_widget_list *wlist; | ||
715 | int wlistsize, wlistentries, i; | ||
716 | |||
717 | if (*list == NULL) | ||
718 | return -EINVAL; | ||
719 | |||
720 | wlist = *list; | ||
721 | |||
722 | /* is this widget already in the list */ | ||
723 | for (i = 0; i < wlist->num_widgets; i++) { | ||
724 | if (wlist->widgets[i] == w) | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | /* allocate some new space */ | ||
729 | wlistentries = wlist->num_widgets + 1; | ||
730 | wlistsize = sizeof(struct snd_soc_dapm_widget_list) + | ||
731 | wlistentries * sizeof(struct snd_soc_dapm_widget *); | ||
732 | *list = krealloc(wlist, wlistsize, GFP_KERNEL); | ||
733 | if (*list == NULL) { | ||
734 | dev_err(w->dapm->dev, "can't allocate widget list for %s\n", | ||
735 | w->name); | ||
736 | return -ENOMEM; | ||
737 | } | ||
738 | wlist = *list; | ||
739 | |||
740 | /* insert the widget */ | ||
741 | dev_dbg(w->dapm->dev, "added %s in widget list pos %d\n", | ||
742 | w->name, wlist->num_widgets); | ||
743 | |||
744 | wlist->widgets[wlist->num_widgets] = w; | ||
745 | wlist->num_widgets++; | ||
746 | return 1; | ||
747 | } | ||
748 | |||
685 | /* | 749 | /* |
686 | * Recursively check for a completed path to an active or physically connected | 750 | * Recursively check for a completed path to an active or physically connected |
687 | * output widget. Returns number of complete paths. | 751 | * output widget. Returns number of complete paths. |
688 | */ | 752 | */ |
689 | static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) | 753 | static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, |
754 | struct snd_soc_dapm_widget_list **list) | ||
690 | { | 755 | { |
691 | struct snd_soc_dapm_path *path; | 756 | struct snd_soc_dapm_path *path; |
692 | int con = 0; | 757 | int con = 0; |
@@ -742,9 +807,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) | |||
742 | if (path->walked) | 807 | if (path->walked) |
743 | continue; | 808 | continue; |
744 | 809 | ||
810 | trace_snd_soc_dapm_output_path(widget, path); | ||
811 | |||
745 | if (path->sink && path->connect) { | 812 | if (path->sink && path->connect) { |
746 | path->walked = 1; | 813 | path->walked = 1; |
747 | con += is_connected_output_ep(path->sink); | 814 | |
815 | /* do we need to add this widget to the list ? */ | ||
816 | if (list) { | ||
817 | int err; | ||
818 | err = dapm_list_add_widget(list, path->sink); | ||
819 | if (err < 0) { | ||
820 | dev_err(widget->dapm->dev, "could not add widget %s\n", | ||
821 | widget->name); | ||
822 | return con; | ||
823 | } | ||
824 | } | ||
825 | |||
826 | con += is_connected_output_ep(path->sink, list); | ||
748 | } | 827 | } |
749 | } | 828 | } |
750 | 829 | ||
@@ -757,7 +836,8 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) | |||
757 | * Recursively check for a completed path to an active or physically connected | 836 | * Recursively check for a completed path to an active or physically connected |
758 | * input widget. Returns number of complete paths. | 837 | * input widget. Returns number of complete paths. |
759 | */ | 838 | */ |
760 | static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) | 839 | static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, |
840 | struct snd_soc_dapm_widget_list **list) | ||
761 | { | 841 | { |
762 | struct snd_soc_dapm_path *path; | 842 | struct snd_soc_dapm_path *path; |
763 | int con = 0; | 843 | int con = 0; |
@@ -825,9 +905,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) | |||
825 | if (path->walked) | 905 | if (path->walked) |
826 | continue; | 906 | continue; |
827 | 907 | ||
908 | trace_snd_soc_dapm_input_path(widget, path); | ||
909 | |||
828 | if (path->source && path->connect) { | 910 | if (path->source && path->connect) { |
829 | path->walked = 1; | 911 | path->walked = 1; |
830 | con += is_connected_input_ep(path->source); | 912 | |
913 | /* do we need to add this widget to the list ? */ | ||
914 | if (list) { | ||
915 | int err; | ||
916 | err = dapm_list_add_widget(list, path->sink); | ||
917 | if (err < 0) { | ||
918 | dev_err(widget->dapm->dev, "could not add widget %s\n", | ||
919 | widget->name); | ||
920 | return con; | ||
921 | } | ||
922 | } | ||
923 | |||
924 | con += is_connected_input_ep(path->source, list); | ||
831 | } | 925 | } |
832 | } | 926 | } |
833 | 927 | ||
@@ -836,6 +930,39 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) | |||
836 | return con; | 930 | return con; |
837 | } | 931 | } |
838 | 932 | ||
933 | /** | ||
934 | * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets. | ||
935 | * @dai: the soc DAI. | ||
936 | * @stream: stream direction. | ||
937 | * @list: list of active widgets for this stream. | ||
938 | * | ||
939 | * Queries DAPM graph as to whether an valid audio stream path exists for | ||
940 | * the initial stream specified by name. This takes into account | ||
941 | * current mixer and mux kcontrol settings. Creates list of valid widgets. | ||
942 | * | ||
943 | * Returns the number of valid paths or negative error. | ||
944 | */ | ||
945 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, | ||
946 | struct snd_soc_dapm_widget_list **list) | ||
947 | { | ||
948 | struct snd_soc_card *card = dai->card; | ||
949 | int paths; | ||
950 | |||
951 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
952 | dapm_reset(card); | ||
953 | |||
954 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
955 | paths = is_connected_output_ep(dai->playback_widget, list); | ||
956 | else | ||
957 | paths = is_connected_input_ep(dai->playback_widget, list); | ||
958 | |||
959 | trace_snd_soc_dapm_connected(paths, stream); | ||
960 | dapm_clear_walk(&card->dapm); | ||
961 | mutex_unlock(&card->dapm_mutex); | ||
962 | |||
963 | return paths; | ||
964 | } | ||
965 | |||
839 | /* | 966 | /* |
840 | * Handler for generic register modifier widget. | 967 | * Handler for generic register modifier widget. |
841 | */ | 968 | */ |
@@ -849,7 +976,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, | |||
849 | else | 976 | else |
850 | val = w->off_val; | 977 | val = w->off_val; |
851 | 978 | ||
852 | soc_widget_update_bits(w, -(w->reg + 1), | 979 | soc_widget_update_bits_locked(w, -(w->reg + 1), |
853 | w->mask << w->shift, val << w->shift); | 980 | w->mask << w->shift, val << w->shift); |
854 | 981 | ||
855 | return 0; | 982 | return 0; |
@@ -863,9 +990,9 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
863 | struct snd_kcontrol *kcontrol, int event) | 990 | struct snd_kcontrol *kcontrol, int event) |
864 | { | 991 | { |
865 | if (SND_SOC_DAPM_EVENT_ON(event)) | 992 | if (SND_SOC_DAPM_EVENT_ON(event)) |
866 | return regulator_enable(w->priv); | 993 | return regulator_enable(w->regulator); |
867 | else | 994 | else |
868 | return regulator_disable_deferred(w->priv, w->shift); | 995 | return regulator_disable_deferred(w->regulator, w->shift); |
869 | } | 996 | } |
870 | EXPORT_SYMBOL_GPL(dapm_regulator_event); | 997 | EXPORT_SYMBOL_GPL(dapm_regulator_event); |
871 | 998 | ||
@@ -892,9 +1019,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) | |||
892 | 1019 | ||
893 | DAPM_UPDATE_STAT(w, power_checks); | 1020 | DAPM_UPDATE_STAT(w, power_checks); |
894 | 1021 | ||
895 | in = is_connected_input_ep(w); | 1022 | in = is_connected_input_ep(w, NULL); |
896 | dapm_clear_walk(w->dapm); | 1023 | dapm_clear_walk(w->dapm); |
897 | out = is_connected_output_ep(w); | 1024 | out = is_connected_output_ep(w, NULL); |
898 | dapm_clear_walk(w->dapm); | 1025 | dapm_clear_walk(w->dapm); |
899 | return out != 0 && in != 0; | 1026 | return out != 0 && in != 0; |
900 | } | 1027 | } |
@@ -903,7 +1030,10 @@ static int dapm_dai_check_power(struct snd_soc_dapm_widget *w) | |||
903 | { | 1030 | { |
904 | DAPM_UPDATE_STAT(w, power_checks); | 1031 | DAPM_UPDATE_STAT(w, power_checks); |
905 | 1032 | ||
906 | return w->active; | 1033 | if (w->active) |
1034 | return w->active; | ||
1035 | |||
1036 | return dapm_generic_check_power(w); | ||
907 | } | 1037 | } |
908 | 1038 | ||
909 | /* Check to see if an ADC has power */ | 1039 | /* Check to see if an ADC has power */ |
@@ -914,7 +1044,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) | |||
914 | DAPM_UPDATE_STAT(w, power_checks); | 1044 | DAPM_UPDATE_STAT(w, power_checks); |
915 | 1045 | ||
916 | if (w->active) { | 1046 | if (w->active) { |
917 | in = is_connected_input_ep(w); | 1047 | in = is_connected_input_ep(w, NULL); |
918 | dapm_clear_walk(w->dapm); | 1048 | dapm_clear_walk(w->dapm); |
919 | return in != 0; | 1049 | return in != 0; |
920 | } else { | 1050 | } else { |
@@ -930,7 +1060,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) | |||
930 | DAPM_UPDATE_STAT(w, power_checks); | 1060 | DAPM_UPDATE_STAT(w, power_checks); |
931 | 1061 | ||
932 | if (w->active) { | 1062 | if (w->active) { |
933 | out = is_connected_output_ep(w); | 1063 | out = is_connected_output_ep(w, NULL); |
934 | dapm_clear_walk(w->dapm); | 1064 | dapm_clear_walk(w->dapm); |
935 | return out != 0; | 1065 | return out != 0; |
936 | } else { | 1066 | } else { |
@@ -1107,7 +1237,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
1107 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", | 1237 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", |
1108 | value, mask, reg, card->pop_time); | 1238 | value, mask, reg, card->pop_time); |
1109 | pop_wait(card->pop_time); | 1239 | pop_wait(card->pop_time); |
1110 | soc_widget_update_bits(w, reg, mask, value); | 1240 | soc_widget_update_bits_locked(w, reg, mask, value); |
1111 | } | 1241 | } |
1112 | 1242 | ||
1113 | list_for_each_entry(w, pending, power_list) { | 1243 | list_for_each_entry(w, pending, power_list) { |
@@ -1237,7 +1367,7 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | |||
1237 | w->name, ret); | 1367 | w->name, ret); |
1238 | } | 1368 | } |
1239 | 1369 | ||
1240 | ret = snd_soc_update_bits(w->codec, update->reg, update->mask, | 1370 | ret = soc_widget_update_bits_locked(w, update->reg, update->mask, |
1241 | update->val); | 1371 | update->val); |
1242 | if (ret < 0) | 1372 | if (ret < 0) |
1243 | pr_err("%s DAPM update failed: %d\n", w->name, ret); | 1373 | pr_err("%s DAPM update failed: %d\n", w->name, ret); |
@@ -1421,12 +1551,10 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1421 | trace_snd_soc_dapm_start(card); | 1551 | trace_snd_soc_dapm_start(card); |
1422 | 1552 | ||
1423 | list_for_each_entry(d, &card->dapm_list, list) { | 1553 | list_for_each_entry(d, &card->dapm_list, list) { |
1424 | if (d->n_widgets || d->codec == NULL) { | 1554 | if (d->idle_bias_off) |
1425 | if (d->idle_bias_off) | 1555 | d->target_bias_level = SND_SOC_BIAS_OFF; |
1426 | d->target_bias_level = SND_SOC_BIAS_OFF; | 1556 | else |
1427 | else | 1557 | d->target_bias_level = SND_SOC_BIAS_STANDBY; |
1428 | d->target_bias_level = SND_SOC_BIAS_STANDBY; | ||
1429 | } | ||
1430 | } | 1558 | } |
1431 | 1559 | ||
1432 | dapm_reset(card); | 1560 | dapm_reset(card); |
@@ -1471,32 +1599,6 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1471 | 1599 | ||
1472 | } | 1600 | } |
1473 | 1601 | ||
1474 | /* If there are no DAPM widgets then try to figure out power from the | ||
1475 | * event type. | ||
1476 | */ | ||
1477 | if (!dapm->n_widgets) { | ||
1478 | switch (event) { | ||
1479 | case SND_SOC_DAPM_STREAM_START: | ||
1480 | case SND_SOC_DAPM_STREAM_RESUME: | ||
1481 | dapm->target_bias_level = SND_SOC_BIAS_ON; | ||
1482 | break; | ||
1483 | case SND_SOC_DAPM_STREAM_STOP: | ||
1484 | if (dapm->codec && dapm->codec->active) | ||
1485 | dapm->target_bias_level = SND_SOC_BIAS_ON; | ||
1486 | else | ||
1487 | dapm->target_bias_level = SND_SOC_BIAS_STANDBY; | ||
1488 | break; | ||
1489 | case SND_SOC_DAPM_STREAM_SUSPEND: | ||
1490 | dapm->target_bias_level = SND_SOC_BIAS_STANDBY; | ||
1491 | break; | ||
1492 | case SND_SOC_DAPM_STREAM_NOP: | ||
1493 | dapm->target_bias_level = dapm->bias_level; | ||
1494 | break; | ||
1495 | default: | ||
1496 | break; | ||
1497 | } | ||
1498 | } | ||
1499 | |||
1500 | /* Force all contexts in the card to the same bias state if | 1602 | /* Force all contexts in the card to the same bias state if |
1501 | * they're not ground referenced. | 1603 | * they're not ground referenced. |
1502 | */ | 1604 | */ |
@@ -1546,12 +1648,6 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1546 | } | 1648 | } |
1547 | 1649 | ||
1548 | #ifdef CONFIG_DEBUG_FS | 1650 | #ifdef CONFIG_DEBUG_FS |
1549 | static int dapm_widget_power_open_file(struct inode *inode, struct file *file) | ||
1550 | { | ||
1551 | file->private_data = inode->i_private; | ||
1552 | return 0; | ||
1553 | } | ||
1554 | |||
1555 | static ssize_t dapm_widget_power_read_file(struct file *file, | 1651 | static ssize_t dapm_widget_power_read_file(struct file *file, |
1556 | char __user *user_buf, | 1652 | char __user *user_buf, |
1557 | size_t count, loff_t *ppos) | 1653 | size_t count, loff_t *ppos) |
@@ -1566,9 +1662,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1566 | if (!buf) | 1662 | if (!buf) |
1567 | return -ENOMEM; | 1663 | return -ENOMEM; |
1568 | 1664 | ||
1569 | in = is_connected_input_ep(w); | 1665 | in = is_connected_input_ep(w, NULL); |
1570 | dapm_clear_walk(w->dapm); | 1666 | dapm_clear_walk(w->dapm); |
1571 | out = is_connected_output_ep(w); | 1667 | out = is_connected_output_ep(w, NULL); |
1572 | dapm_clear_walk(w->dapm); | 1668 | dapm_clear_walk(w->dapm); |
1573 | 1669 | ||
1574 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", | 1670 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", |
@@ -1615,17 +1711,11 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1615 | } | 1711 | } |
1616 | 1712 | ||
1617 | static const struct file_operations dapm_widget_power_fops = { | 1713 | static const struct file_operations dapm_widget_power_fops = { |
1618 | .open = dapm_widget_power_open_file, | 1714 | .open = simple_open, |
1619 | .read = dapm_widget_power_read_file, | 1715 | .read = dapm_widget_power_read_file, |
1620 | .llseek = default_llseek, | 1716 | .llseek = default_llseek, |
1621 | }; | 1717 | }; |
1622 | 1718 | ||
1623 | static int dapm_bias_open_file(struct inode *inode, struct file *file) | ||
1624 | { | ||
1625 | file->private_data = inode->i_private; | ||
1626 | return 0; | ||
1627 | } | ||
1628 | |||
1629 | static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, | 1719 | static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, |
1630 | size_t count, loff_t *ppos) | 1720 | size_t count, loff_t *ppos) |
1631 | { | 1721 | { |
@@ -1656,7 +1746,7 @@ static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, | |||
1656 | } | 1746 | } |
1657 | 1747 | ||
1658 | static const struct file_operations dapm_bias_fops = { | 1748 | static const struct file_operations dapm_bias_fops = { |
1659 | .open = dapm_bias_open_file, | 1749 | .open = simple_open, |
1660 | .read = dapm_bias_read_file, | 1750 | .read = dapm_bias_read_file, |
1661 | .llseek = default_llseek, | 1751 | .llseek = default_llseek, |
1662 | }; | 1752 | }; |
@@ -1721,7 +1811,7 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | |||
1721 | #endif | 1811 | #endif |
1722 | 1812 | ||
1723 | /* test and update the power status of a mux widget */ | 1813 | /* test and update the power status of a mux widget */ |
1724 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 1814 | static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, |
1725 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 1815 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) |
1726 | { | 1816 | { |
1727 | struct snd_soc_dapm_path *path; | 1817 | struct snd_soc_dapm_path *path; |
@@ -1758,12 +1848,26 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1758 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); | 1848 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); |
1759 | } | 1849 | } |
1760 | 1850 | ||
1761 | return 0; | 1851 | return found; |
1852 | } | ||
1853 | |||
1854 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | ||
1855 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | ||
1856 | { | ||
1857 | struct snd_soc_card *card = widget->dapm->card; | ||
1858 | int ret; | ||
1859 | |||
1860 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
1861 | ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e); | ||
1862 | mutex_unlock(&card->dapm_mutex); | ||
1863 | if (ret > 0) | ||
1864 | soc_dpcm_runtime_update(widget); | ||
1865 | return ret; | ||
1762 | } | 1866 | } |
1763 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); | 1867 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); |
1764 | 1868 | ||
1765 | /* test and update the power status of a mixer or switch widget */ | 1869 | /* test and update the power status of a mixer or switch widget */ |
1766 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 1870 | static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, |
1767 | struct snd_kcontrol *kcontrol, int connect) | 1871 | struct snd_kcontrol *kcontrol, int connect) |
1768 | { | 1872 | { |
1769 | struct snd_soc_dapm_path *path; | 1873 | struct snd_soc_dapm_path *path; |
@@ -1790,7 +1894,21 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1790 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); | 1894 | dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); |
1791 | } | 1895 | } |
1792 | 1896 | ||
1793 | return 0; | 1897 | return found; |
1898 | } | ||
1899 | |||
1900 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | ||
1901 | struct snd_kcontrol *kcontrol, int connect) | ||
1902 | { | ||
1903 | struct snd_soc_card *card = widget->dapm->card; | ||
1904 | int ret; | ||
1905 | |||
1906 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
1907 | ret = soc_dapm_mixer_update_power(widget, kcontrol, connect); | ||
1908 | mutex_unlock(&card->dapm_mutex); | ||
1909 | if (ret > 0) | ||
1910 | soc_dpcm_runtime_update(widget); | ||
1911 | return ret; | ||
1794 | } | 1912 | } |
1795 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); | 1913 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); |
1796 | 1914 | ||
@@ -1951,6 +2069,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
1951 | */ | 2069 | */ |
1952 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | 2070 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) |
1953 | { | 2071 | { |
2072 | int ret; | ||
2073 | |||
1954 | /* | 2074 | /* |
1955 | * Suppress early reports (eg, jacks syncing their state) to avoid | 2075 | * Suppress early reports (eg, jacks syncing their state) to avoid |
1956 | * silly DAPM runs during card startup. | 2076 | * silly DAPM runs during card startup. |
@@ -1958,7 +2078,10 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
1958 | if (!dapm->card || !dapm->card->instantiated) | 2078 | if (!dapm->card || !dapm->card->instantiated) |
1959 | return 0; | 2079 | return 0; |
1960 | 2080 | ||
1961 | return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | 2081 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2082 | ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | ||
2083 | mutex_unlock(&dapm->card->dapm_mutex); | ||
2084 | return ret; | ||
1962 | } | 2085 | } |
1963 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 2086 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
1964 | 2087 | ||
@@ -2067,6 +2190,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2067 | case snd_soc_dapm_aif_in: | 2190 | case snd_soc_dapm_aif_in: |
2068 | case snd_soc_dapm_aif_out: | 2191 | case snd_soc_dapm_aif_out: |
2069 | case snd_soc_dapm_dai: | 2192 | case snd_soc_dapm_dai: |
2193 | case snd_soc_dapm_dai_link: | ||
2070 | list_add(&path->list, &dapm->card->paths); | 2194 | list_add(&path->list, &dapm->card->paths); |
2071 | list_add(&path->list_sink, &wsink->sources); | 2195 | list_add(&path->list_sink, &wsink->sources); |
2072 | list_add(&path->list_source, &wsource->sinks); | 2196 | list_add(&path->list_source, &wsource->sinks); |
@@ -2122,19 +2246,21 @@ err: | |||
2122 | int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, | 2246 | int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, |
2123 | const struct snd_soc_dapm_route *route, int num) | 2247 | const struct snd_soc_dapm_route *route, int num) |
2124 | { | 2248 | { |
2125 | int i, ret; | 2249 | int i, ret = 0; |
2126 | 2250 | ||
2251 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | ||
2127 | for (i = 0; i < num; i++) { | 2252 | for (i = 0; i < num; i++) { |
2128 | ret = snd_soc_dapm_add_route(dapm, route); | 2253 | ret = snd_soc_dapm_add_route(dapm, route); |
2129 | if (ret < 0) { | 2254 | if (ret < 0) { |
2130 | dev_err(dapm->dev, "Failed to add route %s->%s\n", | 2255 | dev_err(dapm->dev, "Failed to add route %s->%s\n", |
2131 | route->source, route->sink); | 2256 | route->source, route->sink); |
2132 | return ret; | 2257 | break; |
2133 | } | 2258 | } |
2134 | route++; | 2259 | route++; |
2135 | } | 2260 | } |
2261 | mutex_unlock(&dapm->card->dapm_mutex); | ||
2136 | 2262 | ||
2137 | return 0; | 2263 | return ret; |
2138 | } | 2264 | } |
2139 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); | 2265 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); |
2140 | 2266 | ||
@@ -2205,12 +2331,14 @@ int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, | |||
2205 | int i, err; | 2331 | int i, err; |
2206 | int ret = 0; | 2332 | int ret = 0; |
2207 | 2333 | ||
2334 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | ||
2208 | for (i = 0; i < num; i++) { | 2335 | for (i = 0; i < num; i++) { |
2209 | err = snd_soc_dapm_weak_route(dapm, route); | 2336 | err = snd_soc_dapm_weak_route(dapm, route); |
2210 | if (err) | 2337 | if (err) |
2211 | ret = err; | 2338 | ret = err; |
2212 | route++; | 2339 | route++; |
2213 | } | 2340 | } |
2341 | mutex_unlock(&dapm->card->dapm_mutex); | ||
2214 | 2342 | ||
2215 | return ret; | 2343 | return ret; |
2216 | } | 2344 | } |
@@ -2229,6 +2357,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2229 | struct snd_soc_dapm_widget *w; | 2357 | struct snd_soc_dapm_widget *w; |
2230 | unsigned int val; | 2358 | unsigned int val; |
2231 | 2359 | ||
2360 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | ||
2361 | |||
2232 | list_for_each_entry(w, &dapm->card->widgets, list) | 2362 | list_for_each_entry(w, &dapm->card->widgets, list) |
2233 | { | 2363 | { |
2234 | if (w->new) | 2364 | if (w->new) |
@@ -2238,8 +2368,10 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2238 | w->kcontrols = kzalloc(w->num_kcontrols * | 2368 | w->kcontrols = kzalloc(w->num_kcontrols * |
2239 | sizeof(struct snd_kcontrol *), | 2369 | sizeof(struct snd_kcontrol *), |
2240 | GFP_KERNEL); | 2370 | GFP_KERNEL); |
2241 | if (!w->kcontrols) | 2371 | if (!w->kcontrols) { |
2372 | mutex_unlock(&dapm->card->dapm_mutex); | ||
2242 | return -ENOMEM; | 2373 | return -ENOMEM; |
2374 | } | ||
2243 | } | 2375 | } |
2244 | 2376 | ||
2245 | switch(w->id) { | 2377 | switch(w->id) { |
@@ -2279,6 +2411,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
2279 | } | 2411 | } |
2280 | 2412 | ||
2281 | dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); | 2413 | dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); |
2414 | mutex_unlock(&dapm->card->dapm_mutex); | ||
2282 | return 0; | 2415 | return 0; |
2283 | } | 2416 | } |
2284 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | 2417 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); |
@@ -2338,6 +2471,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2338 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2471 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2339 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | 2472 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; |
2340 | struct snd_soc_codec *codec = widget->codec; | 2473 | struct snd_soc_codec *codec = widget->codec; |
2474 | struct snd_soc_card *card = codec->card; | ||
2341 | struct soc_mixer_control *mc = | 2475 | struct soc_mixer_control *mc = |
2342 | (struct soc_mixer_control *)kcontrol->private_value; | 2476 | (struct soc_mixer_control *)kcontrol->private_value; |
2343 | unsigned int reg = mc->reg; | 2477 | unsigned int reg = mc->reg; |
@@ -2364,7 +2498,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2364 | /* old connection must be powered down */ | 2498 | /* old connection must be powered down */ |
2365 | connect = invert ? 1 : 0; | 2499 | connect = invert ? 1 : 0; |
2366 | 2500 | ||
2367 | mutex_lock(&codec->mutex); | 2501 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2368 | 2502 | ||
2369 | change = snd_soc_test_bits(widget->codec, reg, mask, val); | 2503 | change = snd_soc_test_bits(widget->codec, reg, mask, val); |
2370 | if (change) { | 2504 | if (change) { |
@@ -2380,13 +2514,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2380 | update.val = val; | 2514 | update.val = val; |
2381 | widget->dapm->update = &update; | 2515 | widget->dapm->update = &update; |
2382 | 2516 | ||
2383 | snd_soc_dapm_mixer_update_power(widget, kcontrol, connect); | 2517 | soc_dapm_mixer_update_power(widget, kcontrol, connect); |
2384 | 2518 | ||
2385 | widget->dapm->update = NULL; | 2519 | widget->dapm->update = NULL; |
2386 | } | 2520 | } |
2387 | } | 2521 | } |
2388 | 2522 | ||
2389 | mutex_unlock(&codec->mutex); | 2523 | mutex_unlock(&card->dapm_mutex); |
2390 | return 0; | 2524 | return 0; |
2391 | } | 2525 | } |
2392 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | 2526 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); |
@@ -2435,6 +2569,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2435 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2569 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2436 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | 2570 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; |
2437 | struct snd_soc_codec *codec = widget->codec; | 2571 | struct snd_soc_codec *codec = widget->codec; |
2572 | struct snd_soc_card *card = codec->card; | ||
2438 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2573 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2439 | unsigned int val, mux, change; | 2574 | unsigned int val, mux, change; |
2440 | unsigned int mask, bitmask; | 2575 | unsigned int mask, bitmask; |
@@ -2455,7 +2590,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2455 | mask |= (bitmask - 1) << e->shift_r; | 2590 | mask |= (bitmask - 1) << e->shift_r; |
2456 | } | 2591 | } |
2457 | 2592 | ||
2458 | mutex_lock(&codec->mutex); | 2593 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2459 | 2594 | ||
2460 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 2595 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
2461 | if (change) { | 2596 | if (change) { |
@@ -2471,13 +2606,13 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2471 | update.val = val; | 2606 | update.val = val; |
2472 | widget->dapm->update = &update; | 2607 | widget->dapm->update = &update; |
2473 | 2608 | ||
2474 | snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 2609 | soc_dapm_mux_update_power(widget, kcontrol, mux, e); |
2475 | 2610 | ||
2476 | widget->dapm->update = NULL; | 2611 | widget->dapm->update = NULL; |
2477 | } | 2612 | } |
2478 | } | 2613 | } |
2479 | 2614 | ||
2480 | mutex_unlock(&codec->mutex); | 2615 | mutex_unlock(&card->dapm_mutex); |
2481 | return change; | 2616 | return change; |
2482 | } | 2617 | } |
2483 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | 2618 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
@@ -2514,6 +2649,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | |||
2514 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2649 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2515 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | 2650 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; |
2516 | struct snd_soc_codec *codec = widget->codec; | 2651 | struct snd_soc_codec *codec = widget->codec; |
2652 | struct snd_soc_card *card = codec->card; | ||
2517 | struct soc_enum *e = | 2653 | struct soc_enum *e = |
2518 | (struct soc_enum *)kcontrol->private_value; | 2654 | (struct soc_enum *)kcontrol->private_value; |
2519 | int change; | 2655 | int change; |
@@ -2523,7 +2659,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | |||
2523 | if (ucontrol->value.enumerated.item[0] >= e->max) | 2659 | if (ucontrol->value.enumerated.item[0] >= e->max) |
2524 | return -EINVAL; | 2660 | return -EINVAL; |
2525 | 2661 | ||
2526 | mutex_lock(&codec->mutex); | 2662 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2527 | 2663 | ||
2528 | change = widget->value != ucontrol->value.enumerated.item[0]; | 2664 | change = widget->value != ucontrol->value.enumerated.item[0]; |
2529 | if (change) { | 2665 | if (change) { |
@@ -2532,11 +2668,11 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | |||
2532 | 2668 | ||
2533 | widget->value = ucontrol->value.enumerated.item[0]; | 2669 | widget->value = ucontrol->value.enumerated.item[0]; |
2534 | 2670 | ||
2535 | snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); | 2671 | soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); |
2536 | } | 2672 | } |
2537 | } | 2673 | } |
2538 | 2674 | ||
2539 | mutex_unlock(&codec->mutex); | 2675 | mutex_unlock(&card->dapm_mutex); |
2540 | return ret; | 2676 | return ret; |
2541 | } | 2677 | } |
2542 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | 2678 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); |
@@ -2601,6 +2737,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2601 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); | 2737 | struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); |
2602 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; | 2738 | struct snd_soc_dapm_widget *widget = wlist->widgets[0]; |
2603 | struct snd_soc_codec *codec = widget->codec; | 2739 | struct snd_soc_codec *codec = widget->codec; |
2740 | struct snd_soc_card *card = codec->card; | ||
2604 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2741 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2605 | unsigned int val, mux, change; | 2742 | unsigned int val, mux, change; |
2606 | unsigned int mask; | 2743 | unsigned int mask; |
@@ -2619,7 +2756,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2619 | mask |= e->mask << e->shift_r; | 2756 | mask |= e->mask << e->shift_r; |
2620 | } | 2757 | } |
2621 | 2758 | ||
2622 | mutex_lock(&codec->mutex); | 2759 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2623 | 2760 | ||
2624 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); | 2761 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
2625 | if (change) { | 2762 | if (change) { |
@@ -2635,13 +2772,13 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2635 | update.val = val; | 2772 | update.val = val; |
2636 | widget->dapm->update = &update; | 2773 | widget->dapm->update = &update; |
2637 | 2774 | ||
2638 | snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); | 2775 | soc_dapm_mux_update_power(widget, kcontrol, mux, e); |
2639 | 2776 | ||
2640 | widget->dapm->update = NULL; | 2777 | widget->dapm->update = NULL; |
2641 | } | 2778 | } |
2642 | } | 2779 | } |
2643 | 2780 | ||
2644 | mutex_unlock(&codec->mutex); | 2781 | mutex_unlock(&card->dapm_mutex); |
2645 | return change; | 2782 | return change; |
2646 | } | 2783 | } |
2647 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | 2784 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); |
@@ -2678,12 +2815,12 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, | |||
2678 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); | 2815 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
2679 | const char *pin = (const char *)kcontrol->private_value; | 2816 | const char *pin = (const char *)kcontrol->private_value; |
2680 | 2817 | ||
2681 | mutex_lock(&card->mutex); | 2818 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2682 | 2819 | ||
2683 | ucontrol->value.integer.value[0] = | 2820 | ucontrol->value.integer.value[0] = |
2684 | snd_soc_dapm_get_pin_status(&card->dapm, pin); | 2821 | snd_soc_dapm_get_pin_status(&card->dapm, pin); |
2685 | 2822 | ||
2686 | mutex_unlock(&card->mutex); | 2823 | mutex_unlock(&card->dapm_mutex); |
2687 | 2824 | ||
2688 | return 0; | 2825 | return 0; |
2689 | } | 2826 | } |
@@ -2701,17 +2838,16 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, | |||
2701 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); | 2838 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
2702 | const char *pin = (const char *)kcontrol->private_value; | 2839 | const char *pin = (const char *)kcontrol->private_value; |
2703 | 2840 | ||
2704 | mutex_lock(&card->mutex); | 2841 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2705 | 2842 | ||
2706 | if (ucontrol->value.integer.value[0]) | 2843 | if (ucontrol->value.integer.value[0]) |
2707 | snd_soc_dapm_enable_pin(&card->dapm, pin); | 2844 | snd_soc_dapm_enable_pin(&card->dapm, pin); |
2708 | else | 2845 | else |
2709 | snd_soc_dapm_disable_pin(&card->dapm, pin); | 2846 | snd_soc_dapm_disable_pin(&card->dapm, pin); |
2710 | 2847 | ||
2711 | snd_soc_dapm_sync(&card->dapm); | 2848 | mutex_unlock(&card->dapm_mutex); |
2712 | |||
2713 | mutex_unlock(&card->mutex); | ||
2714 | 2849 | ||
2850 | snd_soc_dapm_sync(&card->dapm); | ||
2715 | return 0; | 2851 | return 0; |
2716 | } | 2852 | } |
2717 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); | 2853 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); |
@@ -2729,9 +2865,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2729 | 2865 | ||
2730 | switch (w->id) { | 2866 | switch (w->id) { |
2731 | case snd_soc_dapm_regulator_supply: | 2867 | case snd_soc_dapm_regulator_supply: |
2732 | w->priv = devm_regulator_get(dapm->dev, w->name); | 2868 | w->regulator = devm_regulator_get(dapm->dev, w->name); |
2733 | if (IS_ERR(w->priv)) { | 2869 | if (IS_ERR(w->regulator)) { |
2734 | ret = PTR_ERR(w->priv); | 2870 | ret = PTR_ERR(w->regulator); |
2735 | dev_err(dapm->dev, "Failed to request %s: %d\n", | 2871 | dev_err(dapm->dev, "Failed to request %s: %d\n", |
2736 | w->name, ret); | 2872 | w->name, ret); |
2737 | return NULL; | 2873 | return NULL; |
@@ -2783,6 +2919,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2783 | case snd_soc_dapm_hp: | 2919 | case snd_soc_dapm_hp: |
2784 | case snd_soc_dapm_mic: | 2920 | case snd_soc_dapm_mic: |
2785 | case snd_soc_dapm_line: | 2921 | case snd_soc_dapm_line: |
2922 | case snd_soc_dapm_dai_link: | ||
2786 | w->power_check = dapm_generic_check_power; | 2923 | w->power_check = dapm_generic_check_power; |
2787 | break; | 2924 | break; |
2788 | case snd_soc_dapm_supply: | 2925 | case snd_soc_dapm_supply: |
@@ -2828,21 +2965,177 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, | |||
2828 | { | 2965 | { |
2829 | struct snd_soc_dapm_widget *w; | 2966 | struct snd_soc_dapm_widget *w; |
2830 | int i; | 2967 | int i; |
2968 | int ret = 0; | ||
2831 | 2969 | ||
2970 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | ||
2832 | for (i = 0; i < num; i++) { | 2971 | for (i = 0; i < num; i++) { |
2833 | w = snd_soc_dapm_new_control(dapm, widget); | 2972 | w = snd_soc_dapm_new_control(dapm, widget); |
2834 | if (!w) { | 2973 | if (!w) { |
2835 | dev_err(dapm->dev, | 2974 | dev_err(dapm->dev, |
2836 | "ASoC: Failed to create DAPM control %s\n", | 2975 | "ASoC: Failed to create DAPM control %s\n", |
2837 | widget->name); | 2976 | widget->name); |
2838 | return -ENOMEM; | 2977 | ret = -ENOMEM; |
2978 | break; | ||
2839 | } | 2979 | } |
2840 | widget++; | 2980 | widget++; |
2841 | } | 2981 | } |
2842 | return 0; | 2982 | mutex_unlock(&dapm->card->dapm_mutex); |
2983 | return ret; | ||
2843 | } | 2984 | } |
2844 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); | 2985 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); |
2845 | 2986 | ||
2987 | static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, | ||
2988 | struct snd_kcontrol *kcontrol, int event) | ||
2989 | { | ||
2990 | struct snd_soc_dapm_path *source_p, *sink_p; | ||
2991 | struct snd_soc_dai *source, *sink; | ||
2992 | const struct snd_soc_pcm_stream *config = w->params; | ||
2993 | struct snd_pcm_substream substream; | ||
2994 | struct snd_pcm_hw_params *params = NULL; | ||
2995 | u64 fmt; | ||
2996 | int ret; | ||
2997 | |||
2998 | BUG_ON(!config); | ||
2999 | BUG_ON(list_empty(&w->sources) || list_empty(&w->sinks)); | ||
3000 | |||
3001 | /* We only support a single source and sink, pick the first */ | ||
3002 | source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path, | ||
3003 | list_sink); | ||
3004 | sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path, | ||
3005 | list_source); | ||
3006 | |||
3007 | BUG_ON(!source_p || !sink_p); | ||
3008 | BUG_ON(!sink_p->source || !source_p->sink); | ||
3009 | BUG_ON(!source_p->source || !sink_p->sink); | ||
3010 | |||
3011 | source = source_p->source->priv; | ||
3012 | sink = sink_p->sink->priv; | ||
3013 | |||
3014 | /* Be a little careful as we don't want to overflow the mask array */ | ||
3015 | if (config->formats) { | ||
3016 | fmt = ffs(config->formats) - 1; | ||
3017 | } else { | ||
3018 | dev_warn(w->dapm->dev, "Invalid format %llx specified\n", | ||
3019 | config->formats); | ||
3020 | fmt = 0; | ||
3021 | } | ||
3022 | |||
3023 | /* Currently very limited parameter selection */ | ||
3024 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
3025 | if (!params) { | ||
3026 | ret = -ENOMEM; | ||
3027 | goto out; | ||
3028 | } | ||
3029 | snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); | ||
3030 | |||
3031 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = | ||
3032 | config->rate_min; | ||
3033 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = | ||
3034 | config->rate_max; | ||
3035 | |||
3036 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min | ||
3037 | = config->channels_min; | ||
3038 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max | ||
3039 | = config->channels_max; | ||
3040 | |||
3041 | memset(&substream, 0, sizeof(substream)); | ||
3042 | |||
3043 | switch (event) { | ||
3044 | case SND_SOC_DAPM_PRE_PMU: | ||
3045 | if (source->driver->ops && source->driver->ops->hw_params) { | ||
3046 | substream.stream = SNDRV_PCM_STREAM_CAPTURE; | ||
3047 | ret = source->driver->ops->hw_params(&substream, | ||
3048 | params, source); | ||
3049 | if (ret != 0) { | ||
3050 | dev_err(source->dev, | ||
3051 | "hw_params() failed: %d\n", ret); | ||
3052 | goto out; | ||
3053 | } | ||
3054 | } | ||
3055 | |||
3056 | if (sink->driver->ops && sink->driver->ops->hw_params) { | ||
3057 | substream.stream = SNDRV_PCM_STREAM_PLAYBACK; | ||
3058 | ret = sink->driver->ops->hw_params(&substream, params, | ||
3059 | sink); | ||
3060 | if (ret != 0) { | ||
3061 | dev_err(sink->dev, | ||
3062 | "hw_params() failed: %d\n", ret); | ||
3063 | goto out; | ||
3064 | } | ||
3065 | } | ||
3066 | break; | ||
3067 | |||
3068 | case SND_SOC_DAPM_POST_PMU: | ||
3069 | ret = snd_soc_dai_digital_mute(sink, 0); | ||
3070 | if (ret != 0 && ret != -ENOTSUPP) | ||
3071 | dev_warn(sink->dev, "Failed to unmute: %d\n", ret); | ||
3072 | ret = 0; | ||
3073 | break; | ||
3074 | |||
3075 | case SND_SOC_DAPM_PRE_PMD: | ||
3076 | ret = snd_soc_dai_digital_mute(sink, 1); | ||
3077 | if (ret != 0 && ret != -ENOTSUPP) | ||
3078 | dev_warn(sink->dev, "Failed to mute: %d\n", ret); | ||
3079 | ret = 0; | ||
3080 | break; | ||
3081 | |||
3082 | default: | ||
3083 | BUG(); | ||
3084 | return -EINVAL; | ||
3085 | } | ||
3086 | |||
3087 | out: | ||
3088 | kfree(params); | ||
3089 | return ret; | ||
3090 | } | ||
3091 | |||
3092 | int snd_soc_dapm_new_pcm(struct snd_soc_card *card, | ||
3093 | const struct snd_soc_pcm_stream *params, | ||
3094 | struct snd_soc_dapm_widget *source, | ||
3095 | struct snd_soc_dapm_widget *sink) | ||
3096 | { | ||
3097 | struct snd_soc_dapm_route routes[2]; | ||
3098 | struct snd_soc_dapm_widget template; | ||
3099 | struct snd_soc_dapm_widget *w; | ||
3100 | size_t len; | ||
3101 | char *link_name; | ||
3102 | |||
3103 | len = strlen(source->name) + strlen(sink->name) + 2; | ||
3104 | link_name = devm_kzalloc(card->dev, len, GFP_KERNEL); | ||
3105 | if (!link_name) | ||
3106 | return -ENOMEM; | ||
3107 | snprintf(link_name, len, "%s-%s", source->name, sink->name); | ||
3108 | |||
3109 | memset(&template, 0, sizeof(template)); | ||
3110 | template.reg = SND_SOC_NOPM; | ||
3111 | template.id = snd_soc_dapm_dai_link; | ||
3112 | template.name = link_name; | ||
3113 | template.event = snd_soc_dai_link_event; | ||
3114 | template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
3115 | SND_SOC_DAPM_PRE_PMD; | ||
3116 | |||
3117 | dev_dbg(card->dev, "adding %s widget\n", link_name); | ||
3118 | |||
3119 | w = snd_soc_dapm_new_control(&card->dapm, &template); | ||
3120 | if (!w) { | ||
3121 | dev_err(card->dev, "Failed to create %s widget\n", | ||
3122 | link_name); | ||
3123 | return -ENOMEM; | ||
3124 | } | ||
3125 | |||
3126 | w->params = params; | ||
3127 | |||
3128 | memset(&routes, 0, sizeof(routes)); | ||
3129 | |||
3130 | routes[0].source = source->name; | ||
3131 | routes[0].sink = link_name; | ||
3132 | routes[1].source = link_name; | ||
3133 | routes[1].sink = sink->name; | ||
3134 | |||
3135 | return snd_soc_dapm_add_routes(&card->dapm, routes, | ||
3136 | ARRAY_SIZE(routes)); | ||
3137 | } | ||
3138 | |||
2846 | int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, | 3139 | int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, |
2847 | struct snd_soc_dai *dai) | 3140 | struct snd_soc_dai *dai) |
2848 | { | 3141 | { |
@@ -2946,37 +3239,61 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | |||
2946 | return 0; | 3239 | return 0; |
2947 | } | 3240 | } |
2948 | 3241 | ||
2949 | static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, | 3242 | static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, |
2950 | int stream, struct snd_soc_dai *dai, | 3243 | int event) |
2951 | int event) | ||
2952 | { | 3244 | { |
2953 | struct snd_soc_dapm_widget *w; | ||
2954 | 3245 | ||
2955 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 3246 | struct snd_soc_dapm_widget *w_cpu, *w_codec; |
2956 | w = dai->playback_widget; | 3247 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
2957 | else | 3248 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
2958 | w = dai->capture_widget; | ||
2959 | 3249 | ||
2960 | if (!w) | 3250 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
2961 | return; | 3251 | w_cpu = cpu_dai->playback_widget; |
3252 | w_codec = codec_dai->playback_widget; | ||
3253 | } else { | ||
3254 | w_cpu = cpu_dai->capture_widget; | ||
3255 | w_codec = codec_dai->capture_widget; | ||
3256 | } | ||
2962 | 3257 | ||
2963 | dapm_mark_dirty(w, "stream event"); | 3258 | if (w_cpu) { |
2964 | 3259 | ||
2965 | switch (event) { | 3260 | dapm_mark_dirty(w_cpu, "stream event"); |
2966 | case SND_SOC_DAPM_STREAM_START: | 3261 | |
2967 | w->active = 1; | 3262 | switch (event) { |
2968 | break; | 3263 | case SND_SOC_DAPM_STREAM_START: |
2969 | case SND_SOC_DAPM_STREAM_STOP: | 3264 | w_cpu->active = 1; |
2970 | w->active = 0; | 3265 | break; |
2971 | break; | 3266 | case SND_SOC_DAPM_STREAM_STOP: |
2972 | case SND_SOC_DAPM_STREAM_SUSPEND: | 3267 | w_cpu->active = 0; |
2973 | case SND_SOC_DAPM_STREAM_RESUME: | 3268 | break; |
2974 | case SND_SOC_DAPM_STREAM_PAUSE_PUSH: | 3269 | case SND_SOC_DAPM_STREAM_SUSPEND: |
2975 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | 3270 | case SND_SOC_DAPM_STREAM_RESUME: |
2976 | break; | 3271 | case SND_SOC_DAPM_STREAM_PAUSE_PUSH: |
3272 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | ||
3273 | break; | ||
3274 | } | ||
2977 | } | 3275 | } |
2978 | 3276 | ||
2979 | dapm_power_widgets(dapm, event); | 3277 | if (w_codec) { |
3278 | |||
3279 | dapm_mark_dirty(w_codec, "stream event"); | ||
3280 | |||
3281 | switch (event) { | ||
3282 | case SND_SOC_DAPM_STREAM_START: | ||
3283 | w_codec->active = 1; | ||
3284 | break; | ||
3285 | case SND_SOC_DAPM_STREAM_STOP: | ||
3286 | w_codec->active = 0; | ||
3287 | break; | ||
3288 | case SND_SOC_DAPM_STREAM_SUSPEND: | ||
3289 | case SND_SOC_DAPM_STREAM_RESUME: | ||
3290 | case SND_SOC_DAPM_STREAM_PAUSE_PUSH: | ||
3291 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | ||
3292 | break; | ||
3293 | } | ||
3294 | } | ||
3295 | |||
3296 | dapm_power_widgets(&rtd->card->dapm, event); | ||
2980 | } | 3297 | } |
2981 | 3298 | ||
2982 | /** | 3299 | /** |
@@ -2990,15 +3307,14 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, | |||
2990 | * | 3307 | * |
2991 | * Returns 0 for success else error. | 3308 | * Returns 0 for success else error. |
2992 | */ | 3309 | */ |
2993 | int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | 3310 | void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, |
2994 | struct snd_soc_dai *dai, int event) | 3311 | int event) |
2995 | { | 3312 | { |
2996 | struct snd_soc_codec *codec = rtd->codec; | 3313 | struct snd_soc_card *card = rtd->card; |
2997 | 3314 | ||
2998 | mutex_lock(&codec->mutex); | 3315 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2999 | soc_dapm_stream_event(&codec->dapm, stream, dai, event); | 3316 | soc_dapm_stream_event(rtd, stream, event); |
3000 | mutex_unlock(&codec->mutex); | 3317 | mutex_unlock(&card->dapm_mutex); |
3001 | return 0; | ||
3002 | } | 3318 | } |
3003 | 3319 | ||
3004 | /** | 3320 | /** |