.. | .. |
---|
18 | 18 | // device reopen. |
---|
19 | 19 | |
---|
20 | 20 | #include <linux/module.h> |
---|
21 | | -#include <linux/moduleparam.h> |
---|
22 | 21 | #include <linux/init.h> |
---|
23 | 22 | #include <linux/async.h> |
---|
24 | 23 | #include <linux/delay.h> |
---|
.. | .. |
---|
63 | 62 | snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, |
---|
64 | 63 | const struct snd_soc_dapm_widget *widget); |
---|
65 | 64 | |
---|
| 65 | +static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg); |
---|
| 66 | + |
---|
66 | 67 | /* dapm power sequences - make this per codec in the future */ |
---|
67 | 68 | static int dapm_up_seq[] = { |
---|
68 | | - [snd_soc_dapm_pre] = 0, |
---|
69 | | - [snd_soc_dapm_regulator_supply] = 1, |
---|
70 | | - [snd_soc_dapm_pinctrl] = 1, |
---|
71 | | - [snd_soc_dapm_clock_supply] = 1, |
---|
72 | | - [snd_soc_dapm_supply] = 2, |
---|
73 | | - [snd_soc_dapm_micbias] = 3, |
---|
74 | | - [snd_soc_dapm_vmid] = 3, |
---|
75 | | - [snd_soc_dapm_dai_link] = 2, |
---|
76 | | - [snd_soc_dapm_dai_in] = 4, |
---|
77 | | - [snd_soc_dapm_dai_out] = 4, |
---|
78 | | - [snd_soc_dapm_aif_in] = 4, |
---|
79 | | - [snd_soc_dapm_aif_out] = 4, |
---|
80 | | - [snd_soc_dapm_mic] = 5, |
---|
81 | | - [snd_soc_dapm_siggen] = 5, |
---|
82 | | - [snd_soc_dapm_input] = 5, |
---|
83 | | - [snd_soc_dapm_output] = 5, |
---|
84 | | - [snd_soc_dapm_mux] = 6, |
---|
85 | | - [snd_soc_dapm_demux] = 6, |
---|
86 | | - [snd_soc_dapm_dac] = 7, |
---|
87 | | - [snd_soc_dapm_switch] = 8, |
---|
88 | | - [snd_soc_dapm_mixer] = 8, |
---|
89 | | - [snd_soc_dapm_mixer_named_ctl] = 8, |
---|
90 | | - [snd_soc_dapm_pga] = 9, |
---|
91 | | - [snd_soc_dapm_buffer] = 9, |
---|
92 | | - [snd_soc_dapm_scheduler] = 9, |
---|
93 | | - [snd_soc_dapm_effect] = 9, |
---|
94 | | - [snd_soc_dapm_src] = 9, |
---|
95 | | - [snd_soc_dapm_asrc] = 9, |
---|
96 | | - [snd_soc_dapm_encoder] = 9, |
---|
97 | | - [snd_soc_dapm_decoder] = 9, |
---|
98 | | - [snd_soc_dapm_adc] = 10, |
---|
99 | | - [snd_soc_dapm_out_drv] = 11, |
---|
100 | | - [snd_soc_dapm_hp] = 11, |
---|
101 | | - [snd_soc_dapm_spk] = 11, |
---|
102 | | - [snd_soc_dapm_line] = 11, |
---|
103 | | - [snd_soc_dapm_sink] = 11, |
---|
104 | | - [snd_soc_dapm_kcontrol] = 12, |
---|
105 | | - [snd_soc_dapm_post] = 13, |
---|
| 69 | + [snd_soc_dapm_pre] = 1, |
---|
| 70 | + [snd_soc_dapm_regulator_supply] = 2, |
---|
| 71 | + [snd_soc_dapm_pinctrl] = 2, |
---|
| 72 | + [snd_soc_dapm_clock_supply] = 2, |
---|
| 73 | + [snd_soc_dapm_supply] = 3, |
---|
| 74 | + [snd_soc_dapm_micbias] = 4, |
---|
| 75 | + [snd_soc_dapm_vmid] = 4, |
---|
| 76 | + [snd_soc_dapm_dai_link] = 3, |
---|
| 77 | + [snd_soc_dapm_dai_in] = 5, |
---|
| 78 | + [snd_soc_dapm_dai_out] = 5, |
---|
| 79 | + [snd_soc_dapm_aif_in] = 5, |
---|
| 80 | + [snd_soc_dapm_aif_out] = 5, |
---|
| 81 | + [snd_soc_dapm_mic] = 6, |
---|
| 82 | + [snd_soc_dapm_siggen] = 6, |
---|
| 83 | + [snd_soc_dapm_input] = 6, |
---|
| 84 | + [snd_soc_dapm_output] = 6, |
---|
| 85 | + [snd_soc_dapm_mux] = 7, |
---|
| 86 | + [snd_soc_dapm_demux] = 7, |
---|
| 87 | + [snd_soc_dapm_dac] = 8, |
---|
| 88 | + [snd_soc_dapm_switch] = 9, |
---|
| 89 | + [snd_soc_dapm_mixer] = 9, |
---|
| 90 | + [snd_soc_dapm_mixer_named_ctl] = 9, |
---|
| 91 | + [snd_soc_dapm_pga] = 10, |
---|
| 92 | + [snd_soc_dapm_buffer] = 10, |
---|
| 93 | + [snd_soc_dapm_scheduler] = 10, |
---|
| 94 | + [snd_soc_dapm_effect] = 10, |
---|
| 95 | + [snd_soc_dapm_src] = 10, |
---|
| 96 | + [snd_soc_dapm_asrc] = 10, |
---|
| 97 | + [snd_soc_dapm_encoder] = 10, |
---|
| 98 | + [snd_soc_dapm_decoder] = 10, |
---|
| 99 | + [snd_soc_dapm_adc] = 11, |
---|
| 100 | + [snd_soc_dapm_out_drv] = 12, |
---|
| 101 | + [snd_soc_dapm_hp] = 12, |
---|
| 102 | + [snd_soc_dapm_spk] = 12, |
---|
| 103 | + [snd_soc_dapm_line] = 12, |
---|
| 104 | + [snd_soc_dapm_sink] = 12, |
---|
| 105 | + [snd_soc_dapm_kcontrol] = 13, |
---|
| 106 | + [snd_soc_dapm_post] = 14, |
---|
106 | 107 | }; |
---|
107 | 108 | |
---|
108 | 109 | static int dapm_down_seq[] = { |
---|
109 | | - [snd_soc_dapm_pre] = 0, |
---|
110 | | - [snd_soc_dapm_kcontrol] = 1, |
---|
111 | | - [snd_soc_dapm_adc] = 2, |
---|
112 | | - [snd_soc_dapm_hp] = 3, |
---|
113 | | - [snd_soc_dapm_spk] = 3, |
---|
114 | | - [snd_soc_dapm_line] = 3, |
---|
115 | | - [snd_soc_dapm_out_drv] = 3, |
---|
116 | | - [snd_soc_dapm_sink] = 3, |
---|
117 | | - [snd_soc_dapm_pga] = 4, |
---|
118 | | - [snd_soc_dapm_buffer] = 4, |
---|
119 | | - [snd_soc_dapm_scheduler] = 4, |
---|
120 | | - [snd_soc_dapm_effect] = 4, |
---|
121 | | - [snd_soc_dapm_src] = 4, |
---|
122 | | - [snd_soc_dapm_asrc] = 4, |
---|
123 | | - [snd_soc_dapm_encoder] = 4, |
---|
124 | | - [snd_soc_dapm_decoder] = 4, |
---|
125 | | - [snd_soc_dapm_switch] = 5, |
---|
126 | | - [snd_soc_dapm_mixer_named_ctl] = 5, |
---|
127 | | - [snd_soc_dapm_mixer] = 5, |
---|
128 | | - [snd_soc_dapm_dac] = 6, |
---|
129 | | - [snd_soc_dapm_mic] = 7, |
---|
130 | | - [snd_soc_dapm_siggen] = 7, |
---|
131 | | - [snd_soc_dapm_input] = 7, |
---|
132 | | - [snd_soc_dapm_output] = 7, |
---|
133 | | - [snd_soc_dapm_micbias] = 8, |
---|
134 | | - [snd_soc_dapm_vmid] = 8, |
---|
135 | | - [snd_soc_dapm_mux] = 9, |
---|
136 | | - [snd_soc_dapm_demux] = 9, |
---|
137 | | - [snd_soc_dapm_aif_in] = 10, |
---|
138 | | - [snd_soc_dapm_aif_out] = 10, |
---|
139 | | - [snd_soc_dapm_dai_in] = 10, |
---|
140 | | - [snd_soc_dapm_dai_out] = 10, |
---|
141 | | - [snd_soc_dapm_dai_link] = 11, |
---|
142 | | - [snd_soc_dapm_supply] = 12, |
---|
143 | | - [snd_soc_dapm_clock_supply] = 13, |
---|
144 | | - [snd_soc_dapm_pinctrl] = 13, |
---|
145 | | - [snd_soc_dapm_regulator_supply] = 13, |
---|
146 | | - [snd_soc_dapm_post] = 14, |
---|
| 110 | + [snd_soc_dapm_pre] = 1, |
---|
| 111 | + [snd_soc_dapm_kcontrol] = 2, |
---|
| 112 | + [snd_soc_dapm_adc] = 3, |
---|
| 113 | + [snd_soc_dapm_hp] = 4, |
---|
| 114 | + [snd_soc_dapm_spk] = 4, |
---|
| 115 | + [snd_soc_dapm_line] = 4, |
---|
| 116 | + [snd_soc_dapm_out_drv] = 4, |
---|
| 117 | + [snd_soc_dapm_sink] = 4, |
---|
| 118 | + [snd_soc_dapm_pga] = 5, |
---|
| 119 | + [snd_soc_dapm_buffer] = 5, |
---|
| 120 | + [snd_soc_dapm_scheduler] = 5, |
---|
| 121 | + [snd_soc_dapm_effect] = 5, |
---|
| 122 | + [snd_soc_dapm_src] = 5, |
---|
| 123 | + [snd_soc_dapm_asrc] = 5, |
---|
| 124 | + [snd_soc_dapm_encoder] = 5, |
---|
| 125 | + [snd_soc_dapm_decoder] = 5, |
---|
| 126 | + [snd_soc_dapm_switch] = 6, |
---|
| 127 | + [snd_soc_dapm_mixer_named_ctl] = 6, |
---|
| 128 | + [snd_soc_dapm_mixer] = 6, |
---|
| 129 | + [snd_soc_dapm_dac] = 7, |
---|
| 130 | + [snd_soc_dapm_mic] = 8, |
---|
| 131 | + [snd_soc_dapm_siggen] = 8, |
---|
| 132 | + [snd_soc_dapm_input] = 8, |
---|
| 133 | + [snd_soc_dapm_output] = 8, |
---|
| 134 | + [snd_soc_dapm_micbias] = 9, |
---|
| 135 | + [snd_soc_dapm_vmid] = 9, |
---|
| 136 | + [snd_soc_dapm_mux] = 10, |
---|
| 137 | + [snd_soc_dapm_demux] = 10, |
---|
| 138 | + [snd_soc_dapm_aif_in] = 11, |
---|
| 139 | + [snd_soc_dapm_aif_out] = 11, |
---|
| 140 | + [snd_soc_dapm_dai_in] = 11, |
---|
| 141 | + [snd_soc_dapm_dai_out] = 11, |
---|
| 142 | + [snd_soc_dapm_dai_link] = 12, |
---|
| 143 | + [snd_soc_dapm_supply] = 13, |
---|
| 144 | + [snd_soc_dapm_clock_supply] = 14, |
---|
| 145 | + [snd_soc_dapm_pinctrl] = 14, |
---|
| 146 | + [snd_soc_dapm_regulator_supply] = 14, |
---|
| 147 | + [snd_soc_dapm_post] = 15, |
---|
147 | 148 | }; |
---|
148 | 149 | |
---|
149 | 150 | static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) |
---|
.. | .. |
---|
158 | 159 | schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); |
---|
159 | 160 | } |
---|
160 | 161 | |
---|
| 162 | +__printf(3, 4) |
---|
161 | 163 | static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...) |
---|
162 | 164 | { |
---|
163 | 165 | va_list args; |
---|
.. | .. |
---|
302 | 304 | |
---|
303 | 305 | mutex_lock(&card->dapm_mutex); |
---|
304 | 306 | |
---|
305 | | - list_for_each_entry(w, &card->widgets, list) { |
---|
| 307 | + for_each_card_widgets(card, w) { |
---|
306 | 308 | if (w->is_ep) { |
---|
307 | 309 | dapm_mark_dirty(w, "Rechecking endpoints"); |
---|
308 | 310 | if (w->is_ep & SND_SOC_DAPM_EP_SINK) |
---|
.. | .. |
---|
320 | 322 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( |
---|
321 | 323 | const struct snd_soc_dapm_widget *_widget) |
---|
322 | 324 | { |
---|
323 | | - return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); |
---|
| 325 | + struct snd_soc_dapm_widget *w; |
---|
| 326 | + |
---|
| 327 | + w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); |
---|
| 328 | + if (!w) |
---|
| 329 | + return NULL; |
---|
| 330 | + |
---|
| 331 | + /* |
---|
| 332 | + * w->name is duplicated in caller, but w->sname isn't. |
---|
| 333 | + * Duplicate it here if defined |
---|
| 334 | + */ |
---|
| 335 | + if (_widget->sname) { |
---|
| 336 | + w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); |
---|
| 337 | + if (!w->sname) { |
---|
| 338 | + kfree(w); |
---|
| 339 | + return NULL; |
---|
| 340 | + } |
---|
| 341 | + } |
---|
| 342 | + return w; |
---|
324 | 343 | } |
---|
325 | 344 | |
---|
326 | 345 | struct dapm_kcontrol_data { |
---|
.. | .. |
---|
388 | 407 | ret = PTR_ERR(data->widget); |
---|
389 | 408 | goto err_data; |
---|
390 | 409 | } |
---|
391 | | - if (!data->widget) { |
---|
392 | | - ret = -ENOMEM; |
---|
393 | | - goto err_data; |
---|
394 | | - } |
---|
395 | 410 | } |
---|
396 | 411 | break; |
---|
397 | 412 | case snd_soc_dapm_demux: |
---|
.. | .. |
---|
426 | 441 | ret = PTR_ERR(data->widget); |
---|
427 | 442 | goto err_data; |
---|
428 | 443 | } |
---|
429 | | - if (!data->widget) { |
---|
430 | | - ret = -ENOMEM; |
---|
431 | | - goto err_data; |
---|
432 | | - } |
---|
433 | 444 | |
---|
434 | 445 | snd_soc_dapm_add_path(widget->dapm, data->widget, |
---|
435 | 446 | widget, NULL, NULL); |
---|
| 447 | + } else if (e->reg != SND_SOC_NOPM) { |
---|
| 448 | + data->value = soc_dapm_read(widget->dapm, e->reg) & |
---|
| 449 | + (e->mask << e->shift_l); |
---|
436 | 450 | } |
---|
437 | 451 | break; |
---|
438 | 452 | default: |
---|
.. | .. |
---|
478 | 492 | n = 1; |
---|
479 | 493 | |
---|
480 | 494 | new_wlist = krealloc(data->wlist, |
---|
481 | | - sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL); |
---|
| 495 | + struct_size(new_wlist, widgets, n), |
---|
| 496 | + GFP_KERNEL); |
---|
482 | 497 | if (!new_wlist) |
---|
483 | 498 | return -ENOMEM; |
---|
484 | 499 | |
---|
.. | .. |
---|
593 | 608 | |
---|
594 | 609 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); |
---|
595 | 610 | |
---|
596 | | - list_for_each_entry(w, &card->widgets, list) { |
---|
| 611 | + for_each_card_widgets(card, w) { |
---|
597 | 612 | w->new_power = w->power; |
---|
598 | 613 | w->power_checked = false; |
---|
599 | 614 | } |
---|
.. | .. |
---|
606 | 621 | return dapm->component->name_prefix; |
---|
607 | 622 | } |
---|
608 | 623 | |
---|
609 | | -static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg, |
---|
610 | | - unsigned int *value) |
---|
| 624 | +static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg) |
---|
611 | 625 | { |
---|
612 | 626 | if (!dapm->component) |
---|
613 | 627 | return -EIO; |
---|
614 | | - return snd_soc_component_read(dapm->component, reg, value); |
---|
| 628 | + return snd_soc_component_read(dapm->component, reg); |
---|
615 | 629 | } |
---|
616 | 630 | |
---|
617 | 631 | static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm, |
---|
.. | .. |
---|
688 | 702 | { |
---|
689 | 703 | int ret = 0; |
---|
690 | 704 | |
---|
691 | | - if (dapm->set_bias_level) |
---|
692 | | - ret = dapm->set_bias_level(dapm, level); |
---|
| 705 | + if (dapm->component) |
---|
| 706 | + ret = snd_soc_component_set_bias_level(dapm->component, level); |
---|
693 | 707 | |
---|
694 | 708 | if (ret == 0) |
---|
695 | 709 | dapm->bias_level = level; |
---|
.. | .. |
---|
715 | 729 | |
---|
716 | 730 | trace_snd_soc_bias_level_start(card, level); |
---|
717 | 731 | |
---|
718 | | - if (card && card->set_bias_level) |
---|
719 | | - ret = card->set_bias_level(card, dapm, level); |
---|
| 732 | + ret = snd_soc_card_set_bias_level(card, dapm, level); |
---|
720 | 733 | if (ret != 0) |
---|
721 | 734 | goto out; |
---|
722 | 735 | |
---|
.. | .. |
---|
726 | 739 | if (ret != 0) |
---|
727 | 740 | goto out; |
---|
728 | 741 | |
---|
729 | | - if (card && card->set_bias_level_post) |
---|
730 | | - ret = card->set_bias_level_post(card, dapm, level); |
---|
| 742 | + ret = snd_soc_card_set_bias_level_post(card, dapm, level); |
---|
731 | 743 | out: |
---|
732 | 744 | trace_snd_soc_bias_level_done(card, level); |
---|
733 | 745 | |
---|
.. | .. |
---|
745 | 757 | int i; |
---|
746 | 758 | |
---|
747 | 759 | if (e->reg != SND_SOC_NOPM) { |
---|
748 | | - soc_dapm_read(dapm, e->reg, &val); |
---|
| 760 | + val = soc_dapm_read(dapm, e->reg); |
---|
749 | 761 | val = (val >> e->shift_l) & e->mask; |
---|
750 | 762 | item = snd_soc_enum_val_to_item(e, val); |
---|
751 | 763 | } else { |
---|
.. | .. |
---|
782 | 794 | unsigned int val; |
---|
783 | 795 | |
---|
784 | 796 | if (reg != SND_SOC_NOPM) { |
---|
785 | | - soc_dapm_read(p->sink->dapm, reg, &val); |
---|
| 797 | + val = soc_dapm_read(p->sink->dapm, reg); |
---|
786 | 798 | /* |
---|
787 | 799 | * The nth_path argument allows this function to know |
---|
788 | 800 | * which path of a kcontrol it is setting the initial |
---|
.. | .. |
---|
797 | 809 | */ |
---|
798 | 810 | if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) { |
---|
799 | 811 | if (reg != mc->rreg) |
---|
800 | | - soc_dapm_read(p->sink->dapm, mc->rreg, &val); |
---|
| 812 | + val = soc_dapm_read(p->sink->dapm, mc->rreg); |
---|
801 | 813 | val = (val >> mc->rshift) & mask; |
---|
802 | 814 | } else { |
---|
803 | 815 | val = (val >> shift) & mask; |
---|
.. | .. |
---|
843 | 855 | |
---|
844 | 856 | *kcontrol = NULL; |
---|
845 | 857 | |
---|
846 | | - list_for_each_entry(w, &dapm->card->widgets, list) { |
---|
| 858 | + for_each_card_widgets(dapm->card, w) { |
---|
847 | 859 | if (w == kcontrolw || w->dapm != kcontrolw->dapm) |
---|
848 | 860 | continue; |
---|
849 | 861 | for (i = 0; i < w->num_kcontrols; i++) { |
---|
.. | .. |
---|
894 | 906 | case snd_soc_dapm_switch: |
---|
895 | 907 | case snd_soc_dapm_mixer: |
---|
896 | 908 | case snd_soc_dapm_pga: |
---|
| 909 | + case snd_soc_dapm_effect: |
---|
897 | 910 | case snd_soc_dapm_out_drv: |
---|
898 | 911 | wname_in_long_name = true; |
---|
899 | 912 | kcname_in_long_name = true; |
---|
.. | .. |
---|
1070 | 1083 | struct snd_kcontrol *kcontrol; |
---|
1071 | 1084 | struct snd_soc_dapm_context *dapm = w->dapm; |
---|
1072 | 1085 | struct snd_card *card = dapm->card->snd_card; |
---|
| 1086 | + struct snd_soc_pcm_runtime *rtd = w->priv; |
---|
1073 | 1087 | |
---|
1074 | 1088 | /* create control for links with > 1 config */ |
---|
1075 | | - if (w->num_params <= 1) |
---|
| 1089 | + if (rtd->dai_link->num_params <= 1) |
---|
1076 | 1090 | return 0; |
---|
1077 | 1091 | |
---|
1078 | 1092 | /* add kcontrol */ |
---|
.. | .. |
---|
1113 | 1127 | } |
---|
1114 | 1128 | } |
---|
1115 | 1129 | |
---|
| 1130 | +static void dapm_widget_list_free(struct snd_soc_dapm_widget_list **list) |
---|
| 1131 | +{ |
---|
| 1132 | + kfree(*list); |
---|
| 1133 | +} |
---|
| 1134 | + |
---|
1116 | 1135 | static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, |
---|
1117 | 1136 | struct list_head *widgets) |
---|
1118 | 1137 | { |
---|
.. | .. |
---|
1134 | 1153 | (*list)->num_widgets = i; |
---|
1135 | 1154 | |
---|
1136 | 1155 | return 0; |
---|
| 1156 | +} |
---|
| 1157 | + |
---|
| 1158 | +/* |
---|
| 1159 | + * Recursively reset the cached number of inputs or outputs for the specified |
---|
| 1160 | + * widget and all widgets that can be reached via incoming or outcoming paths |
---|
| 1161 | + * from the widget. |
---|
| 1162 | + */ |
---|
| 1163 | +static void invalidate_paths_ep(struct snd_soc_dapm_widget *widget, |
---|
| 1164 | + enum snd_soc_dapm_direction dir) |
---|
| 1165 | +{ |
---|
| 1166 | + enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir); |
---|
| 1167 | + struct snd_soc_dapm_path *path; |
---|
| 1168 | + |
---|
| 1169 | + widget->endpoints[dir] = -1; |
---|
| 1170 | + |
---|
| 1171 | + snd_soc_dapm_widget_for_each_path(widget, rdir, path) { |
---|
| 1172 | + if (path->weak || path->is_supply) |
---|
| 1173 | + continue; |
---|
| 1174 | + |
---|
| 1175 | + if (path->walking) |
---|
| 1176 | + return; |
---|
| 1177 | + |
---|
| 1178 | + if (path->connect) { |
---|
| 1179 | + path->walking = 1; |
---|
| 1180 | + invalidate_paths_ep(path->node[dir], dir); |
---|
| 1181 | + path->walking = 0; |
---|
| 1182 | + } |
---|
| 1183 | + } |
---|
1137 | 1184 | } |
---|
1138 | 1185 | |
---|
1139 | 1186 | /* |
---|
.. | .. |
---|
1234 | 1281 | } |
---|
1235 | 1282 | |
---|
1236 | 1283 | /** |
---|
1237 | | - * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets. |
---|
| 1284 | + * snd_soc_dapm_dai_get_connected_widgets - query audio path and it's widgets. |
---|
1238 | 1285 | * @dai: the soc DAI. |
---|
1239 | 1286 | * @stream: stream direction. |
---|
1240 | 1287 | * @list: list of active widgets for this stream. |
---|
.. | .. |
---|
1265 | 1312 | |
---|
1266 | 1313 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
---|
1267 | 1314 | |
---|
1268 | | - /* |
---|
1269 | | - * For is_connected_{output,input}_ep fully discover the graph we need |
---|
1270 | | - * to reset the cached number of inputs and outputs. |
---|
1271 | | - */ |
---|
1272 | | - list_for_each_entry(w, &card->widgets, list) { |
---|
1273 | | - w->endpoints[SND_SOC_DAPM_DIR_IN] = -1; |
---|
1274 | | - w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1; |
---|
| 1315 | + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
| 1316 | + w = dai->playback_widget; |
---|
| 1317 | + invalidate_paths_ep(w, SND_SOC_DAPM_DIR_OUT); |
---|
| 1318 | + paths = is_connected_output_ep(w, &widgets, |
---|
| 1319 | + custom_stop_condition); |
---|
| 1320 | + } else { |
---|
| 1321 | + w = dai->capture_widget; |
---|
| 1322 | + invalidate_paths_ep(w, SND_SOC_DAPM_DIR_IN); |
---|
| 1323 | + paths = is_connected_input_ep(w, &widgets, |
---|
| 1324 | + custom_stop_condition); |
---|
1275 | 1325 | } |
---|
1276 | | - |
---|
1277 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
1278 | | - paths = is_connected_output_ep(dai->playback_widget, &widgets, |
---|
1279 | | - custom_stop_condition); |
---|
1280 | | - else |
---|
1281 | | - paths = is_connected_input_ep(dai->capture_widget, &widgets, |
---|
1282 | | - custom_stop_condition); |
---|
1283 | 1326 | |
---|
1284 | 1327 | /* Drop starting point */ |
---|
1285 | 1328 | list_del(widgets.next); |
---|
.. | .. |
---|
1292 | 1335 | mutex_unlock(&card->dapm_mutex); |
---|
1293 | 1336 | |
---|
1294 | 1337 | return paths; |
---|
| 1338 | +} |
---|
| 1339 | + |
---|
| 1340 | +void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list) |
---|
| 1341 | +{ |
---|
| 1342 | + dapm_widget_list_free(list); |
---|
1295 | 1343 | } |
---|
1296 | 1344 | |
---|
1297 | 1345 | /* |
---|
.. | .. |
---|
1364 | 1412 | |
---|
1365 | 1413 | soc_dapm_async_complete(w->dapm); |
---|
1366 | 1414 | |
---|
1367 | | -#ifdef CONFIG_HAVE_CLK |
---|
1368 | 1415 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
---|
1369 | 1416 | return clk_prepare_enable(w->clk); |
---|
1370 | 1417 | } else { |
---|
1371 | 1418 | clk_disable_unprepare(w->clk); |
---|
1372 | 1419 | return 0; |
---|
1373 | 1420 | } |
---|
1374 | | -#endif |
---|
| 1421 | + |
---|
1375 | 1422 | return 0; |
---|
1376 | 1423 | } |
---|
1377 | 1424 | EXPORT_SYMBOL_GPL(dapm_clock_event); |
---|
.. | .. |
---|
1439 | 1486 | { |
---|
1440 | 1487 | int *sort; |
---|
1441 | 1488 | |
---|
| 1489 | + BUILD_BUG_ON(ARRAY_SIZE(dapm_up_seq) != SND_SOC_DAPM_TYPE_COUNT); |
---|
| 1490 | + BUILD_BUG_ON(ARRAY_SIZE(dapm_down_seq) != SND_SOC_DAPM_TYPE_COUNT); |
---|
| 1491 | + |
---|
1442 | 1492 | if (power_up) |
---|
1443 | 1493 | sort = dapm_up_seq; |
---|
1444 | 1494 | else |
---|
1445 | 1495 | sort = dapm_down_seq; |
---|
| 1496 | + |
---|
| 1497 | + WARN_ONCE(sort[a->id] == 0, "offset a->id %d not initialized\n", a->id); |
---|
| 1498 | + WARN_ONCE(sort[b->id] == 0, "offset b->id %d not initialized\n", b->id); |
---|
1446 | 1499 | |
---|
1447 | 1500 | if (sort[a->id] != sort[b->id]) |
---|
1448 | 1501 | return sort[a->id] - sort[b->id]; |
---|
.. | .. |
---|
1611 | 1664 | /* Do we need to apply any queued changes? */ |
---|
1612 | 1665 | if (sort[w->id] != cur_sort || w->reg != cur_reg || |
---|
1613 | 1666 | w->dapm != cur_dapm || w->subseq != cur_subseq) { |
---|
1614 | | - if (cur_dapm && !list_empty(&pending)) |
---|
| 1667 | + if (!list_empty(&pending)) |
---|
1615 | 1668 | dapm_seq_run_coalesced(card, &pending); |
---|
1616 | 1669 | |
---|
1617 | | - if (cur_dapm && cur_dapm->seq_notifier) { |
---|
| 1670 | + if (cur_dapm && cur_dapm->component) { |
---|
1618 | 1671 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) |
---|
1619 | 1672 | if (sort[i] == cur_sort) |
---|
1620 | | - cur_dapm->seq_notifier(cur_dapm, |
---|
1621 | | - i, |
---|
1622 | | - cur_subseq); |
---|
| 1673 | + snd_soc_component_seq_notifier( |
---|
| 1674 | + cur_dapm->component, |
---|
| 1675 | + i, cur_subseq); |
---|
1623 | 1676 | } |
---|
1624 | 1677 | |
---|
1625 | 1678 | if (cur_dapm && w->dapm != cur_dapm) |
---|
.. | .. |
---|
1635 | 1688 | switch (w->id) { |
---|
1636 | 1689 | case snd_soc_dapm_pre: |
---|
1637 | 1690 | if (!w->event) |
---|
1638 | | - list_for_each_entry_safe_continue(w, n, list, |
---|
1639 | | - power_list); |
---|
| 1691 | + continue; |
---|
1640 | 1692 | |
---|
1641 | 1693 | if (event == SND_SOC_DAPM_STREAM_START) |
---|
1642 | 1694 | ret = w->event(w, |
---|
.. | .. |
---|
1648 | 1700 | |
---|
1649 | 1701 | case snd_soc_dapm_post: |
---|
1650 | 1702 | if (!w->event) |
---|
1651 | | - list_for_each_entry_safe_continue(w, n, list, |
---|
1652 | | - power_list); |
---|
| 1703 | + continue; |
---|
1653 | 1704 | |
---|
1654 | 1705 | if (event == SND_SOC_DAPM_STREAM_START) |
---|
1655 | 1706 | ret = w->event(w, |
---|
.. | .. |
---|
1674 | 1725 | "ASoC: Failed to apply widget power: %d\n", ret); |
---|
1675 | 1726 | } |
---|
1676 | 1727 | |
---|
1677 | | - if (cur_dapm && !list_empty(&pending)) |
---|
| 1728 | + if (!list_empty(&pending)) |
---|
1678 | 1729 | dapm_seq_run_coalesced(card, &pending); |
---|
1679 | 1730 | |
---|
1680 | | - if (cur_dapm && cur_dapm->seq_notifier) { |
---|
| 1731 | + if (cur_dapm && cur_dapm->component) { |
---|
1681 | 1732 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) |
---|
1682 | 1733 | if (sort[i] == cur_sort) |
---|
1683 | | - cur_dapm->seq_notifier(cur_dapm, |
---|
1684 | | - i, cur_subseq); |
---|
| 1734 | + snd_soc_component_seq_notifier( |
---|
| 1735 | + cur_dapm->component, |
---|
| 1736 | + i, cur_subseq); |
---|
1685 | 1737 | } |
---|
1686 | 1738 | |
---|
1687 | | - list_for_each_entry(d, &card->dapm_list, list) { |
---|
| 1739 | + for_each_card_dapms(card, d) |
---|
1688 | 1740 | soc_dapm_async_complete(d); |
---|
1689 | | - } |
---|
1690 | 1741 | } |
---|
1691 | 1742 | |
---|
1692 | 1743 | static void dapm_widget_update(struct snd_soc_card *card) |
---|
.. | .. |
---|
1702 | 1753 | |
---|
1703 | 1754 | wlist = dapm_kcontrol_get_wlist(update->kcontrol); |
---|
1704 | 1755 | |
---|
1705 | | - for (wi = 0; wi < wlist->num_widgets; wi++) { |
---|
1706 | | - w = wlist->widgets[wi]; |
---|
1707 | | - |
---|
| 1756 | + for_each_dapm_widgets(wlist, wi, w) { |
---|
1708 | 1757 | if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) { |
---|
1709 | 1758 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); |
---|
1710 | 1759 | if (ret != 0) |
---|
.. | .. |
---|
1731 | 1780 | w->name, ret); |
---|
1732 | 1781 | } |
---|
1733 | 1782 | |
---|
1734 | | - for (wi = 0; wi < wlist->num_widgets; wi++) { |
---|
1735 | | - w = wlist->widgets[wi]; |
---|
1736 | | - |
---|
| 1783 | + for_each_dapm_widgets(wlist, wi, w) { |
---|
1737 | 1784 | if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) { |
---|
1738 | 1785 | ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); |
---|
1739 | 1786 | if (ret != 0) |
---|
.. | .. |
---|
1754 | 1801 | /* If we're off and we're not supposed to go into STANDBY */ |
---|
1755 | 1802 | if (d->bias_level == SND_SOC_BIAS_OFF && |
---|
1756 | 1803 | d->target_bias_level != SND_SOC_BIAS_OFF) { |
---|
1757 | | - if (d->dev) |
---|
| 1804 | + if (d->dev && cookie) |
---|
1758 | 1805 | pm_runtime_get_sync(d->dev); |
---|
1759 | 1806 | |
---|
1760 | 1807 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); |
---|
.. | .. |
---|
1801 | 1848 | dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n", |
---|
1802 | 1849 | ret); |
---|
1803 | 1850 | |
---|
1804 | | - if (d->dev) |
---|
| 1851 | + if (d->dev && cookie) |
---|
1805 | 1852 | pm_runtime_put(d->dev); |
---|
1806 | 1853 | } |
---|
1807 | 1854 | |
---|
.. | .. |
---|
1915 | 1962 | LIST_HEAD(down_list); |
---|
1916 | 1963 | ASYNC_DOMAIN_EXCLUSIVE(async_domain); |
---|
1917 | 1964 | enum snd_soc_bias_level bias; |
---|
| 1965 | + int ret; |
---|
1918 | 1966 | |
---|
1919 | 1967 | lockdep_assert_held(&card->dapm_mutex); |
---|
1920 | 1968 | |
---|
1921 | 1969 | trace_snd_soc_dapm_start(card); |
---|
1922 | | - mutex_lock(&card->dapm_power_mutex); |
---|
1923 | 1970 | |
---|
1924 | | - list_for_each_entry(d, &card->dapm_list, list) { |
---|
| 1971 | + for_each_card_dapms(card, d) { |
---|
1925 | 1972 | if (dapm_idle_bias_off(d)) |
---|
1926 | 1973 | d->target_bias_level = SND_SOC_BIAS_OFF; |
---|
1927 | 1974 | else |
---|
.. | .. |
---|
1940 | 1987 | dapm_power_one_widget(w, &up_list, &down_list); |
---|
1941 | 1988 | } |
---|
1942 | 1989 | |
---|
1943 | | - list_for_each_entry(w, &card->widgets, list) { |
---|
| 1990 | + for_each_card_widgets(card, w) { |
---|
1944 | 1991 | switch (w->id) { |
---|
1945 | 1992 | case snd_soc_dapm_pre: |
---|
1946 | 1993 | case snd_soc_dapm_post: |
---|
.. | .. |
---|
1985 | 2032 | * they're not ground referenced. |
---|
1986 | 2033 | */ |
---|
1987 | 2034 | bias = SND_SOC_BIAS_OFF; |
---|
1988 | | - list_for_each_entry(d, &card->dapm_list, list) |
---|
| 2035 | + for_each_card_dapms(card, d) |
---|
1989 | 2036 | if (d->target_bias_level > bias) |
---|
1990 | 2037 | bias = d->target_bias_level; |
---|
1991 | | - list_for_each_entry(d, &card->dapm_list, list) |
---|
| 2038 | + for_each_card_dapms(card, d) |
---|
1992 | 2039 | if (!dapm_idle_bias_off(d)) |
---|
1993 | 2040 | d->target_bias_level = bias; |
---|
1994 | 2041 | |
---|
.. | .. |
---|
1997 | 2044 | /* Run card bias changes at first */ |
---|
1998 | 2045 | dapm_pre_sequence_async(&card->dapm, 0); |
---|
1999 | 2046 | /* Run other bias changes in parallel */ |
---|
2000 | | - list_for_each_entry(d, &card->dapm_list, list) { |
---|
2001 | | - if (d != &card->dapm) |
---|
| 2047 | + for_each_card_dapms(card, d) { |
---|
| 2048 | + if (d != &card->dapm && d->bias_level != d->target_bias_level) |
---|
2002 | 2049 | async_schedule_domain(dapm_pre_sequence_async, d, |
---|
2003 | 2050 | &async_domain); |
---|
2004 | 2051 | } |
---|
.. | .. |
---|
2021 | 2068 | dapm_seq_run(card, &up_list, event, true); |
---|
2022 | 2069 | |
---|
2023 | 2070 | /* Run all the bias changes in parallel */ |
---|
2024 | | - list_for_each_entry(d, &card->dapm_list, list) { |
---|
2025 | | - if (d != &card->dapm) |
---|
| 2071 | + for_each_card_dapms(card, d) { |
---|
| 2072 | + if (d != &card->dapm && d->bias_level != d->target_bias_level) |
---|
2026 | 2073 | async_schedule_domain(dapm_post_sequence_async, d, |
---|
2027 | 2074 | &async_domain); |
---|
2028 | 2075 | } |
---|
.. | .. |
---|
2031 | 2078 | dapm_post_sequence_async(&card->dapm, 0); |
---|
2032 | 2079 | |
---|
2033 | 2080 | /* do we need to notify any clients that DAPM event is complete */ |
---|
2034 | | - list_for_each_entry(d, &card->dapm_list, list) { |
---|
2035 | | - if (d->stream_event) |
---|
2036 | | - d->stream_event(d, event); |
---|
| 2081 | + for_each_card_dapms(card, d) { |
---|
| 2082 | + if (!d->component) |
---|
| 2083 | + continue; |
---|
| 2084 | + |
---|
| 2085 | + ret = snd_soc_component_stream_event(d->component, event); |
---|
| 2086 | + if (ret < 0) |
---|
| 2087 | + return ret; |
---|
2037 | 2088 | } |
---|
2038 | 2089 | |
---|
2039 | 2090 | pop_dbg(card->dev, card->pop_time, |
---|
2040 | 2091 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); |
---|
2041 | 2092 | pop_wait(card->pop_time); |
---|
2042 | | - mutex_unlock(&card->dapm_power_mutex); |
---|
2043 | 2093 | |
---|
2044 | 2094 | trace_snd_soc_dapm_done(card); |
---|
2045 | 2095 | |
---|
.. | .. |
---|
2159 | 2209 | void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, |
---|
2160 | 2210 | struct dentry *parent) |
---|
2161 | 2211 | { |
---|
2162 | | - struct dentry *d; |
---|
2163 | | - |
---|
2164 | 2212 | if (!parent || IS_ERR(parent)) |
---|
2165 | 2213 | return; |
---|
2166 | 2214 | |
---|
2167 | 2215 | dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); |
---|
2168 | 2216 | |
---|
2169 | | - if (IS_ERR(dapm->debugfs_dapm)) { |
---|
2170 | | - dev_warn(dapm->dev, |
---|
2171 | | - "ASoC: Failed to create DAPM debugfs directory %ld\n", |
---|
2172 | | - PTR_ERR(dapm->debugfs_dapm)); |
---|
2173 | | - return; |
---|
2174 | | - } |
---|
2175 | | - |
---|
2176 | | - d = debugfs_create_file("bias_level", 0444, |
---|
2177 | | - dapm->debugfs_dapm, dapm, |
---|
2178 | | - &dapm_bias_fops); |
---|
2179 | | - if (IS_ERR(d)) |
---|
2180 | | - dev_warn(dapm->dev, |
---|
2181 | | - "ASoC: Failed to create bias level debugfs file: %ld\n", |
---|
2182 | | - PTR_ERR(d)); |
---|
| 2217 | + debugfs_create_file("bias_level", 0444, dapm->debugfs_dapm, dapm, |
---|
| 2218 | + &dapm_bias_fops); |
---|
2183 | 2219 | } |
---|
2184 | 2220 | |
---|
2185 | 2221 | static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w) |
---|
2186 | 2222 | { |
---|
2187 | 2223 | struct snd_soc_dapm_context *dapm = w->dapm; |
---|
2188 | | - struct dentry *d; |
---|
2189 | 2224 | |
---|
2190 | 2225 | if (!dapm->debugfs_dapm || !w->name) |
---|
2191 | 2226 | return; |
---|
2192 | 2227 | |
---|
2193 | | - d = debugfs_create_file(w->name, 0444, |
---|
2194 | | - dapm->debugfs_dapm, w, |
---|
2195 | | - &dapm_widget_power_fops); |
---|
2196 | | - if (IS_ERR(d)) |
---|
2197 | | - dev_warn(w->dapm->dev, |
---|
2198 | | - "ASoC: Failed to create %s debugfs file: %ld\n", |
---|
2199 | | - w->name, PTR_ERR(d)); |
---|
| 2228 | + debugfs_create_file(w->name, 0444, dapm->debugfs_dapm, w, |
---|
| 2229 | + &dapm_widget_power_fops); |
---|
2200 | 2230 | } |
---|
2201 | 2231 | |
---|
2202 | 2232 | static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) |
---|
2203 | 2233 | { |
---|
2204 | 2234 | debugfs_remove_recursive(dapm->debugfs_dapm); |
---|
| 2235 | + dapm->debugfs_dapm = NULL; |
---|
2205 | 2236 | } |
---|
2206 | 2237 | |
---|
2207 | 2238 | #else |
---|
.. | .. |
---|
2253 | 2284 | dapm_kcontrol_for_each_path(path, kcontrol) { |
---|
2254 | 2285 | found = 1; |
---|
2255 | 2286 | /* we now need to match the string in the enum to the path */ |
---|
2256 | | - if (!(strcmp(path->name, e->texts[mux]))) |
---|
| 2287 | + if (e && !(strcmp(path->name, e->texts[mux]))) |
---|
2257 | 2288 | connect = true; |
---|
2258 | 2289 | else |
---|
2259 | 2290 | connect = false; |
---|
.. | .. |
---|
2280 | 2311 | card->update = NULL; |
---|
2281 | 2312 | mutex_unlock(&card->dapm_mutex); |
---|
2282 | 2313 | if (ret > 0) |
---|
2283 | | - soc_dpcm_runtime_update(card); |
---|
| 2314 | + snd_soc_dpcm_runtime_update(card); |
---|
2284 | 2315 | return ret; |
---|
2285 | 2316 | } |
---|
2286 | 2317 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); |
---|
.. | .. |
---|
2345 | 2376 | card->update = NULL; |
---|
2346 | 2377 | mutex_unlock(&card->dapm_mutex); |
---|
2347 | 2378 | if (ret > 0) |
---|
2348 | | - soc_dpcm_runtime_update(card); |
---|
| 2379 | + snd_soc_dpcm_runtime_update(card); |
---|
2349 | 2380 | return ret; |
---|
2350 | 2381 | } |
---|
2351 | 2382 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); |
---|
.. | .. |
---|
2365 | 2396 | if (!cmpnt->card) |
---|
2366 | 2397 | return 0; |
---|
2367 | 2398 | |
---|
2368 | | - list_for_each_entry(w, &cmpnt->card->widgets, list) { |
---|
| 2399 | + for_each_card_widgets(cmpnt->card, w) { |
---|
2369 | 2400 | if (w->dapm != dapm) |
---|
2370 | 2401 | continue; |
---|
2371 | 2402 | |
---|
.. | .. |
---|
2379 | 2410 | case snd_soc_dapm_dac: |
---|
2380 | 2411 | case snd_soc_dapm_adc: |
---|
2381 | 2412 | case snd_soc_dapm_pga: |
---|
| 2413 | + case snd_soc_dapm_effect: |
---|
2382 | 2414 | case snd_soc_dapm_out_drv: |
---|
2383 | 2415 | case snd_soc_dapm_mixer: |
---|
2384 | 2416 | case snd_soc_dapm_mixer_named_ctl: |
---|
.. | .. |
---|
2419 | 2451 | struct device_attribute *attr, char *buf) |
---|
2420 | 2452 | { |
---|
2421 | 2453 | struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); |
---|
| 2454 | + struct snd_soc_dai *codec_dai; |
---|
2422 | 2455 | int i, count = 0; |
---|
2423 | 2456 | |
---|
2424 | 2457 | mutex_lock(&rtd->card->dapm_mutex); |
---|
2425 | 2458 | |
---|
2426 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
2427 | | - struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component; |
---|
| 2459 | + for_each_rtd_codec_dais(rtd, i, codec_dai) { |
---|
| 2460 | + struct snd_soc_component *cmpnt = codec_dai->component; |
---|
2428 | 2461 | |
---|
2429 | 2462 | count += dapm_widget_show_component(cmpnt, buf + count); |
---|
2430 | 2463 | } |
---|
.. | .. |
---|
2469 | 2502 | |
---|
2470 | 2503 | kfree(w->kcontrols); |
---|
2471 | 2504 | kfree_const(w->name); |
---|
| 2505 | + kfree_const(w->sname); |
---|
2472 | 2506 | kfree(w); |
---|
2473 | 2507 | } |
---|
2474 | 2508 | |
---|
.. | .. |
---|
2483 | 2517 | { |
---|
2484 | 2518 | struct snd_soc_dapm_widget *w, *next_w; |
---|
2485 | 2519 | |
---|
2486 | | - list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) { |
---|
| 2520 | + for_each_card_widgets_safe(dapm->card, w, next_w) { |
---|
2487 | 2521 | if (w->dapm != dapm) |
---|
2488 | 2522 | continue; |
---|
2489 | 2523 | snd_soc_dapm_free_widget(w); |
---|
.. | .. |
---|
2497 | 2531 | { |
---|
2498 | 2532 | struct snd_soc_dapm_widget *w; |
---|
2499 | 2533 | struct snd_soc_dapm_widget *fallback = NULL; |
---|
| 2534 | + char prefixed_pin[80]; |
---|
| 2535 | + const char *pin_name; |
---|
| 2536 | + const char *prefix = soc_dapm_prefix(dapm); |
---|
2500 | 2537 | |
---|
2501 | | - list_for_each_entry(w, &dapm->card->widgets, list) { |
---|
2502 | | - if (!strcmp(w->name, pin)) { |
---|
| 2538 | + if (prefix) { |
---|
| 2539 | + snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s", |
---|
| 2540 | + prefix, pin); |
---|
| 2541 | + pin_name = prefixed_pin; |
---|
| 2542 | + } else { |
---|
| 2543 | + pin_name = pin; |
---|
| 2544 | + } |
---|
| 2545 | + |
---|
| 2546 | + for_each_card_widgets(dapm->card, w) { |
---|
| 2547 | + if (!strcmp(w->name, pin_name)) { |
---|
2503 | 2548 | if (w->dapm == dapm) |
---|
2504 | 2549 | return w; |
---|
2505 | 2550 | else |
---|
.. | .. |
---|
2600 | 2645 | return ret; |
---|
2601 | 2646 | } |
---|
2602 | 2647 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
---|
| 2648 | + |
---|
| 2649 | +static int dapm_update_dai_chan(struct snd_soc_dapm_path *p, |
---|
| 2650 | + struct snd_soc_dapm_widget *w, |
---|
| 2651 | + int channels) |
---|
| 2652 | +{ |
---|
| 2653 | + switch (w->id) { |
---|
| 2654 | + case snd_soc_dapm_aif_out: |
---|
| 2655 | + case snd_soc_dapm_aif_in: |
---|
| 2656 | + break; |
---|
| 2657 | + default: |
---|
| 2658 | + return 0; |
---|
| 2659 | + } |
---|
| 2660 | + |
---|
| 2661 | + dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n", |
---|
| 2662 | + w->channel < channels ? "Connecting" : "Disconnecting", |
---|
| 2663 | + p->source->name, p->sink->name); |
---|
| 2664 | + |
---|
| 2665 | + if (w->channel < channels) |
---|
| 2666 | + soc_dapm_connect_path(p, true, "dai update"); |
---|
| 2667 | + else |
---|
| 2668 | + soc_dapm_connect_path(p, false, "dai update"); |
---|
| 2669 | + |
---|
| 2670 | + return 0; |
---|
| 2671 | +} |
---|
| 2672 | + |
---|
| 2673 | +static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, |
---|
| 2674 | + struct snd_pcm_hw_params *params, |
---|
| 2675 | + struct snd_soc_dai *dai) |
---|
| 2676 | +{ |
---|
| 2677 | + int dir = substream->stream; |
---|
| 2678 | + int channels = params_channels(params); |
---|
| 2679 | + struct snd_soc_dapm_path *p; |
---|
| 2680 | + struct snd_soc_dapm_widget *w; |
---|
| 2681 | + int ret; |
---|
| 2682 | + |
---|
| 2683 | + w = snd_soc_dai_get_widget(dai, dir); |
---|
| 2684 | + |
---|
| 2685 | + if (!w) |
---|
| 2686 | + return 0; |
---|
| 2687 | + |
---|
| 2688 | + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, |
---|
| 2689 | + dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); |
---|
| 2690 | + |
---|
| 2691 | + snd_soc_dapm_widget_for_each_sink_path(w, p) { |
---|
| 2692 | + ret = dapm_update_dai_chan(p, p->sink, channels); |
---|
| 2693 | + if (ret < 0) |
---|
| 2694 | + return ret; |
---|
| 2695 | + } |
---|
| 2696 | + |
---|
| 2697 | + snd_soc_dapm_widget_for_each_source_path(w, p) { |
---|
| 2698 | + ret = dapm_update_dai_chan(p, p->source, channels); |
---|
| 2699 | + if (ret < 0) |
---|
| 2700 | + return ret; |
---|
| 2701 | + } |
---|
| 2702 | + |
---|
| 2703 | + return 0; |
---|
| 2704 | +} |
---|
| 2705 | + |
---|
| 2706 | +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, |
---|
| 2707 | + struct snd_pcm_hw_params *params, |
---|
| 2708 | + struct snd_soc_dai *dai) |
---|
| 2709 | +{ |
---|
| 2710 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
| 2711 | + int ret; |
---|
| 2712 | + |
---|
| 2713 | + mutex_lock_nested(&rtd->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
---|
| 2714 | + ret = dapm_update_dai_unlocked(substream, params, dai); |
---|
| 2715 | + mutex_unlock(&rtd->card->dapm_mutex); |
---|
| 2716 | + |
---|
| 2717 | + return ret; |
---|
| 2718 | +} |
---|
| 2719 | +EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai); |
---|
2603 | 2720 | |
---|
2604 | 2721 | /* |
---|
2605 | 2722 | * dapm_update_widget_flags() - Re-compute widget sink and source flags |
---|
.. | .. |
---|
2817 | 2934 | char prefixed_sink[80]; |
---|
2818 | 2935 | char prefixed_source[80]; |
---|
2819 | 2936 | const char *prefix; |
---|
| 2937 | + unsigned int sink_ref = 0; |
---|
| 2938 | + unsigned int source_ref = 0; |
---|
2820 | 2939 | int ret; |
---|
2821 | 2940 | |
---|
2822 | 2941 | prefix = soc_dapm_prefix(dapm); |
---|
.. | .. |
---|
2842 | 2961 | * find src and dest widgets over all widgets but favor a widget from |
---|
2843 | 2962 | * current DAPM context |
---|
2844 | 2963 | */ |
---|
2845 | | - list_for_each_entry(w, &dapm->card->widgets, list) { |
---|
| 2964 | + for_each_card_widgets(dapm->card, w) { |
---|
2846 | 2965 | if (!wsink && !(strcmp(w->name, sink))) { |
---|
2847 | 2966 | wtsink = w; |
---|
2848 | 2967 | if (w->dapm == dapm) { |
---|
.. | .. |
---|
2850 | 2969 | if (wsource) |
---|
2851 | 2970 | break; |
---|
2852 | 2971 | } |
---|
| 2972 | + sink_ref++; |
---|
| 2973 | + if (sink_ref > 1) |
---|
| 2974 | + dev_warn(dapm->dev, |
---|
| 2975 | + "ASoC: sink widget %s overwritten\n", |
---|
| 2976 | + w->name); |
---|
2853 | 2977 | continue; |
---|
2854 | 2978 | } |
---|
2855 | 2979 | if (!wsource && !(strcmp(w->name, source))) { |
---|
.. | .. |
---|
2859 | 2983 | if (wsink) |
---|
2860 | 2984 | break; |
---|
2861 | 2985 | } |
---|
| 2986 | + source_ref++; |
---|
| 2987 | + if (source_ref > 1) |
---|
| 2988 | + dev_warn(dapm->dev, |
---|
| 2989 | + "ASoC: source widget %s overwritten\n", |
---|
| 2990 | + w->name); |
---|
2862 | 2991 | } |
---|
2863 | 2992 | } |
---|
2864 | 2993 | /* use widget from another DAPM context if not found from this */ |
---|
.. | .. |
---|
3111 | 3240 | |
---|
3112 | 3241 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); |
---|
3113 | 3242 | |
---|
3114 | | - list_for_each_entry(w, &card->widgets, list) |
---|
| 3243 | + for_each_card_widgets(card, w) |
---|
3115 | 3244 | { |
---|
3116 | 3245 | if (w->new) |
---|
3117 | 3246 | continue; |
---|
.. | .. |
---|
3137 | 3266 | dapm_new_mux(w); |
---|
3138 | 3267 | break; |
---|
3139 | 3268 | case snd_soc_dapm_pga: |
---|
| 3269 | + case snd_soc_dapm_effect: |
---|
3140 | 3270 | case snd_soc_dapm_out_drv: |
---|
3141 | 3271 | dapm_new_pga(w); |
---|
3142 | 3272 | break; |
---|
.. | .. |
---|
3149 | 3279 | |
---|
3150 | 3280 | /* Read the initial power state from the device */ |
---|
3151 | 3281 | if (w->reg >= 0) { |
---|
3152 | | - soc_dapm_read(w->dapm, w->reg, &val); |
---|
| 3282 | + val = soc_dapm_read(w->dapm, w->reg); |
---|
3153 | 3283 | val = val >> w->shift; |
---|
3154 | 3284 | val &= w->mask; |
---|
3155 | 3285 | if (val == w->on_val) |
---|
.. | .. |
---|
3191 | 3321 | unsigned int mask = (1 << fls(max)) - 1; |
---|
3192 | 3322 | unsigned int invert = mc->invert; |
---|
3193 | 3323 | unsigned int reg_val, val, rval = 0; |
---|
3194 | | - int ret = 0; |
---|
3195 | 3324 | |
---|
3196 | 3325 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
---|
3197 | 3326 | if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) { |
---|
3198 | | - ret = soc_dapm_read(dapm, reg, ®_val); |
---|
| 3327 | + reg_val = soc_dapm_read(dapm, reg); |
---|
3199 | 3328 | val = (reg_val >> shift) & mask; |
---|
3200 | 3329 | |
---|
3201 | | - if (ret == 0 && reg != mc->rreg) |
---|
3202 | | - ret = soc_dapm_read(dapm, mc->rreg, ®_val); |
---|
| 3330 | + if (reg != mc->rreg) |
---|
| 3331 | + reg_val = soc_dapm_read(dapm, mc->rreg); |
---|
3203 | 3332 | |
---|
3204 | 3333 | if (snd_soc_volsw_is_stereo(mc)) |
---|
3205 | 3334 | rval = (reg_val >> mc->rshift) & mask; |
---|
.. | .. |
---|
3211 | 3340 | rval = (reg_val >> width) & mask; |
---|
3212 | 3341 | } |
---|
3213 | 3342 | mutex_unlock(&card->dapm_mutex); |
---|
3214 | | - |
---|
3215 | | - if (ret) |
---|
3216 | | - return ret; |
---|
3217 | 3343 | |
---|
3218 | 3344 | if (invert) |
---|
3219 | 3345 | ucontrol->value.integer.value[0] = max - val; |
---|
.. | .. |
---|
3227 | 3353 | ucontrol->value.integer.value[1] = rval; |
---|
3228 | 3354 | } |
---|
3229 | 3355 | |
---|
3230 | | - return ret; |
---|
| 3356 | + return 0; |
---|
3231 | 3357 | } |
---|
3232 | 3358 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); |
---|
3233 | 3359 | |
---|
.. | .. |
---|
3306 | 3432 | update.val = val; |
---|
3307 | 3433 | card->update = &update; |
---|
3308 | 3434 | } |
---|
3309 | | - change |= reg_change; |
---|
3310 | 3435 | |
---|
3311 | 3436 | ret = soc_dapm_mixer_update_power(card, kcontrol, connect, |
---|
3312 | 3437 | rconnect); |
---|
.. | .. |
---|
3317 | 3442 | mutex_unlock(&card->dapm_mutex); |
---|
3318 | 3443 | |
---|
3319 | 3444 | if (ret > 0) |
---|
3320 | | - soc_dpcm_runtime_update(card); |
---|
| 3445 | + snd_soc_dpcm_runtime_update(card); |
---|
3321 | 3446 | |
---|
3322 | 3447 | return change; |
---|
3323 | 3448 | } |
---|
.. | .. |
---|
3342 | 3467 | |
---|
3343 | 3468 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
---|
3344 | 3469 | if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) { |
---|
3345 | | - int ret = soc_dapm_read(dapm, e->reg, ®_val); |
---|
3346 | | - if (ret) { |
---|
3347 | | - mutex_unlock(&card->dapm_mutex); |
---|
3348 | | - return ret; |
---|
3349 | | - } |
---|
| 3470 | + reg_val = soc_dapm_read(dapm, e->reg); |
---|
3350 | 3471 | } else { |
---|
3351 | 3472 | reg_val = dapm_kcontrol_get_value(kcontrol); |
---|
3352 | 3473 | } |
---|
.. | .. |
---|
3412 | 3533 | update.val = val; |
---|
3413 | 3534 | card->update = &update; |
---|
3414 | 3535 | } |
---|
3415 | | - change |= reg_change; |
---|
3416 | 3536 | |
---|
3417 | 3537 | ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e); |
---|
3418 | 3538 | |
---|
.. | .. |
---|
3422 | 3542 | mutex_unlock(&card->dapm_mutex); |
---|
3423 | 3543 | |
---|
3424 | 3544 | if (ret > 0) |
---|
3425 | | - soc_dpcm_runtime_update(card); |
---|
| 3545 | + snd_soc_dpcm_runtime_update(card); |
---|
3426 | 3546 | |
---|
3427 | 3547 | return change; |
---|
3428 | 3548 | } |
---|
.. | .. |
---|
3495 | 3615 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); |
---|
3496 | 3616 | |
---|
3497 | 3617 | struct snd_soc_dapm_widget * |
---|
3498 | | -snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, |
---|
3499 | | - const struct snd_soc_dapm_widget *widget) |
---|
3500 | | -{ |
---|
3501 | | - struct snd_soc_dapm_widget *w; |
---|
3502 | | - |
---|
3503 | | - mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
---|
3504 | | - w = snd_soc_dapm_new_control_unlocked(dapm, widget); |
---|
3505 | | - /* Do not nag about probe deferrals */ |
---|
3506 | | - if (IS_ERR(w)) { |
---|
3507 | | - int ret = PTR_ERR(w); |
---|
3508 | | - |
---|
3509 | | - if (ret != -EPROBE_DEFER) |
---|
3510 | | - dev_err(dapm->dev, |
---|
3511 | | - "ASoC: Failed to create DAPM control %s (%d)\n", |
---|
3512 | | - widget->name, ret); |
---|
3513 | | - goto out_unlock; |
---|
3514 | | - } |
---|
3515 | | - if (!w) |
---|
3516 | | - dev_err(dapm->dev, |
---|
3517 | | - "ASoC: Failed to create DAPM control %s\n", |
---|
3518 | | - widget->name); |
---|
3519 | | - |
---|
3520 | | -out_unlock: |
---|
3521 | | - mutex_unlock(&dapm->card->dapm_mutex); |
---|
3522 | | - return w; |
---|
3523 | | -} |
---|
3524 | | -EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); |
---|
3525 | | - |
---|
3526 | | -struct snd_soc_dapm_widget * |
---|
3527 | 3618 | snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, |
---|
3528 | 3619 | const struct snd_soc_dapm_widget *widget) |
---|
3529 | 3620 | { |
---|
.. | .. |
---|
3533 | 3624 | int ret; |
---|
3534 | 3625 | |
---|
3535 | 3626 | if ((w = dapm_cnew_widget(widget)) == NULL) |
---|
3536 | | - return NULL; |
---|
| 3627 | + return ERR_PTR(-ENOMEM); |
---|
3537 | 3628 | |
---|
3538 | 3629 | switch (w->id) { |
---|
3539 | 3630 | case snd_soc_dapm_regulator_supply: |
---|
3540 | 3631 | w->regulator = devm_regulator_get(dapm->dev, w->name); |
---|
3541 | 3632 | if (IS_ERR(w->regulator)) { |
---|
3542 | 3633 | ret = PTR_ERR(w->regulator); |
---|
3543 | | - if (ret == -EPROBE_DEFER) |
---|
3544 | | - return ERR_PTR(ret); |
---|
3545 | | - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", |
---|
3546 | | - w->name, ret); |
---|
3547 | | - return NULL; |
---|
| 3634 | + goto request_failed; |
---|
3548 | 3635 | } |
---|
3549 | 3636 | |
---|
3550 | 3637 | if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { |
---|
3551 | 3638 | ret = regulator_allow_bypass(w->regulator, true); |
---|
3552 | 3639 | if (ret != 0) |
---|
3553 | | - dev_warn(w->dapm->dev, |
---|
| 3640 | + dev_warn(dapm->dev, |
---|
3554 | 3641 | "ASoC: Failed to bypass %s: %d\n", |
---|
3555 | 3642 | w->name, ret); |
---|
3556 | 3643 | } |
---|
.. | .. |
---|
3559 | 3646 | w->pinctrl = devm_pinctrl_get(dapm->dev); |
---|
3560 | 3647 | if (IS_ERR(w->pinctrl)) { |
---|
3561 | 3648 | ret = PTR_ERR(w->pinctrl); |
---|
3562 | | - if (ret == -EPROBE_DEFER) |
---|
3563 | | - return ERR_PTR(ret); |
---|
3564 | | - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", |
---|
3565 | | - w->name, ret); |
---|
3566 | | - return NULL; |
---|
| 3649 | + goto request_failed; |
---|
3567 | 3650 | } |
---|
| 3651 | + |
---|
| 3652 | + /* set to sleep_state when initializing */ |
---|
| 3653 | + dapm_pinctrl_event(w, NULL, SND_SOC_DAPM_POST_PMD); |
---|
3568 | 3654 | break; |
---|
3569 | 3655 | case snd_soc_dapm_clock_supply: |
---|
3570 | | -#ifdef CONFIG_CLKDEV_LOOKUP |
---|
3571 | 3656 | w->clk = devm_clk_get(dapm->dev, w->name); |
---|
3572 | 3657 | if (IS_ERR(w->clk)) { |
---|
3573 | 3658 | ret = PTR_ERR(w->clk); |
---|
3574 | | - if (ret == -EPROBE_DEFER) |
---|
3575 | | - return ERR_PTR(ret); |
---|
3576 | | - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", |
---|
3577 | | - w->name, ret); |
---|
3578 | | - return NULL; |
---|
| 3659 | + goto request_failed; |
---|
3579 | 3660 | } |
---|
3580 | | -#else |
---|
3581 | | - return NULL; |
---|
3582 | | -#endif |
---|
3583 | 3661 | break; |
---|
3584 | 3662 | default: |
---|
3585 | 3663 | break; |
---|
.. | .. |
---|
3591 | 3669 | else |
---|
3592 | 3670 | w->name = kstrdup_const(widget->name, GFP_KERNEL); |
---|
3593 | 3671 | if (w->name == NULL) { |
---|
| 3672 | + kfree_const(w->sname); |
---|
3594 | 3673 | kfree(w); |
---|
3595 | | - return NULL; |
---|
| 3674 | + return ERR_PTR(-ENOMEM); |
---|
3596 | 3675 | } |
---|
3597 | 3676 | |
---|
3598 | 3677 | switch (w->id) { |
---|
.. | .. |
---|
3635 | 3714 | case snd_soc_dapm_dac: |
---|
3636 | 3715 | case snd_soc_dapm_aif_in: |
---|
3637 | 3716 | case snd_soc_dapm_pga: |
---|
| 3717 | + case snd_soc_dapm_buffer: |
---|
| 3718 | + case snd_soc_dapm_scheduler: |
---|
| 3719 | + case snd_soc_dapm_effect: |
---|
| 3720 | + case snd_soc_dapm_src: |
---|
| 3721 | + case snd_soc_dapm_asrc: |
---|
| 3722 | + case snd_soc_dapm_encoder: |
---|
| 3723 | + case snd_soc_dapm_decoder: |
---|
3638 | 3724 | case snd_soc_dapm_out_drv: |
---|
3639 | 3725 | case snd_soc_dapm_micbias: |
---|
3640 | 3726 | case snd_soc_dapm_line: |
---|
.. | .. |
---|
3659 | 3745 | w->dapm = dapm; |
---|
3660 | 3746 | INIT_LIST_HEAD(&w->list); |
---|
3661 | 3747 | INIT_LIST_HEAD(&w->dirty); |
---|
| 3748 | + /* see for_each_card_widgets */ |
---|
3662 | 3749 | list_add_tail(&w->list, &dapm->card->widgets); |
---|
3663 | 3750 | |
---|
3664 | 3751 | snd_soc_dapm_for_each_direction(dir) { |
---|
.. | .. |
---|
3669 | 3756 | /* machine layer sets up unconnected pins and insertions */ |
---|
3670 | 3757 | w->connected = 1; |
---|
3671 | 3758 | return w; |
---|
| 3759 | + |
---|
| 3760 | +request_failed: |
---|
| 3761 | + if (ret != -EPROBE_DEFER) |
---|
| 3762 | + dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", |
---|
| 3763 | + w->name, ret); |
---|
| 3764 | + |
---|
| 3765 | + kfree_const(w->sname); |
---|
| 3766 | + kfree(w); |
---|
| 3767 | + return ERR_PTR(ret); |
---|
3672 | 3768 | } |
---|
| 3769 | + |
---|
| 3770 | +/** |
---|
| 3771 | + * snd_soc_dapm_new_control - create new dapm control |
---|
| 3772 | + * @dapm: DAPM context |
---|
| 3773 | + * @widget: widget template |
---|
| 3774 | + * |
---|
| 3775 | + * Creates new DAPM control based upon a template. |
---|
| 3776 | + * |
---|
| 3777 | + * Returns a widget pointer on success or an error pointer on failure |
---|
| 3778 | + */ |
---|
| 3779 | +struct snd_soc_dapm_widget * |
---|
| 3780 | +snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, |
---|
| 3781 | + const struct snd_soc_dapm_widget *widget) |
---|
| 3782 | +{ |
---|
| 3783 | + struct snd_soc_dapm_widget *w; |
---|
| 3784 | + |
---|
| 3785 | + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
---|
| 3786 | + w = snd_soc_dapm_new_control_unlocked(dapm, widget); |
---|
| 3787 | + mutex_unlock(&dapm->card->dapm_mutex); |
---|
| 3788 | + |
---|
| 3789 | + return w; |
---|
| 3790 | +} |
---|
| 3791 | +EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); |
---|
3673 | 3792 | |
---|
3674 | 3793 | /** |
---|
3675 | 3794 | * snd_soc_dapm_new_controls - create new dapm controls |
---|
.. | .. |
---|
3694 | 3813 | w = snd_soc_dapm_new_control_unlocked(dapm, widget); |
---|
3695 | 3814 | if (IS_ERR(w)) { |
---|
3696 | 3815 | ret = PTR_ERR(w); |
---|
3697 | | - /* Do not nag about probe deferrals */ |
---|
3698 | | - if (ret == -EPROBE_DEFER) |
---|
3699 | | - break; |
---|
3700 | | - dev_err(dapm->dev, |
---|
3701 | | - "ASoC: Failed to create DAPM control %s (%d)\n", |
---|
3702 | | - widget->name, ret); |
---|
3703 | | - break; |
---|
3704 | | - } |
---|
3705 | | - if (!w) { |
---|
3706 | | - dev_err(dapm->dev, |
---|
3707 | | - "ASoC: Failed to create DAPM control %s\n", |
---|
3708 | | - widget->name); |
---|
3709 | | - ret = -ENOMEM; |
---|
3710 | 3816 | break; |
---|
3711 | 3817 | } |
---|
3712 | 3818 | widget++; |
---|
.. | .. |
---|
3716 | 3822 | } |
---|
3717 | 3823 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); |
---|
3718 | 3824 | |
---|
3719 | | -static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, |
---|
3720 | | - struct snd_kcontrol *kcontrol, int event) |
---|
| 3825 | +static int |
---|
| 3826 | +snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, |
---|
| 3827 | + struct snd_pcm_substream *substream) |
---|
3721 | 3828 | { |
---|
3722 | | - struct snd_soc_dapm_path *source_p, *sink_p; |
---|
| 3829 | + struct snd_soc_dapm_path *path; |
---|
3723 | 3830 | struct snd_soc_dai *source, *sink; |
---|
3724 | | - struct snd_soc_pcm_runtime *rtd = w->priv; |
---|
3725 | | - const struct snd_soc_pcm_stream *config = w->params + w->params_select; |
---|
3726 | | - struct snd_pcm_substream substream; |
---|
| 3831 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
3727 | 3832 | struct snd_pcm_hw_params *params = NULL; |
---|
| 3833 | + const struct snd_soc_pcm_stream *config = NULL; |
---|
3728 | 3834 | struct snd_pcm_runtime *runtime = NULL; |
---|
3729 | 3835 | unsigned int fmt; |
---|
3730 | 3836 | int ret = 0; |
---|
3731 | 3837 | |
---|
3732 | | - if (WARN_ON(!config) || |
---|
3733 | | - WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || |
---|
3734 | | - list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) |
---|
3735 | | - return -EINVAL; |
---|
| 3838 | + params = kzalloc(sizeof(*params), GFP_KERNEL); |
---|
| 3839 | + if (!params) |
---|
| 3840 | + return -ENOMEM; |
---|
3736 | 3841 | |
---|
3737 | | - /* We only support a single source and sink, pick the first */ |
---|
3738 | | - source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT], |
---|
3739 | | - struct snd_soc_dapm_path, |
---|
3740 | | - list_node[SND_SOC_DAPM_DIR_OUT]); |
---|
3741 | | - sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN], |
---|
3742 | | - struct snd_soc_dapm_path, |
---|
3743 | | - list_node[SND_SOC_DAPM_DIR_IN]); |
---|
| 3842 | + runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); |
---|
| 3843 | + if (!runtime) { |
---|
| 3844 | + ret = -ENOMEM; |
---|
| 3845 | + goto out; |
---|
| 3846 | + } |
---|
3744 | 3847 | |
---|
3745 | | - source = source_p->source->priv; |
---|
3746 | | - sink = sink_p->sink->priv; |
---|
| 3848 | + substream->runtime = runtime; |
---|
| 3849 | + |
---|
| 3850 | + substream->stream = SNDRV_PCM_STREAM_CAPTURE; |
---|
| 3851 | + snd_soc_dapm_widget_for_each_source_path(w, path) { |
---|
| 3852 | + source = path->source->priv; |
---|
| 3853 | + |
---|
| 3854 | + ret = snd_soc_dai_startup(source, substream); |
---|
| 3855 | + if (ret < 0) { |
---|
| 3856 | + dev_err(source->dev, |
---|
| 3857 | + "ASoC: startup() failed: %d\n", ret); |
---|
| 3858 | + goto out; |
---|
| 3859 | + } |
---|
| 3860 | + snd_soc_dai_activate(source, substream->stream); |
---|
| 3861 | + } |
---|
| 3862 | + |
---|
| 3863 | + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; |
---|
| 3864 | + snd_soc_dapm_widget_for_each_sink_path(w, path) { |
---|
| 3865 | + sink = path->sink->priv; |
---|
| 3866 | + |
---|
| 3867 | + ret = snd_soc_dai_startup(sink, substream); |
---|
| 3868 | + if (ret < 0) { |
---|
| 3869 | + dev_err(sink->dev, |
---|
| 3870 | + "ASoC: startup() failed: %d\n", ret); |
---|
| 3871 | + goto out; |
---|
| 3872 | + } |
---|
| 3873 | + snd_soc_dai_activate(sink, substream->stream); |
---|
| 3874 | + } |
---|
| 3875 | + |
---|
| 3876 | + substream->hw_opened = 1; |
---|
| 3877 | + |
---|
| 3878 | + /* |
---|
| 3879 | + * Note: getting the config after .startup() gives a chance to |
---|
| 3880 | + * either party on the link to alter the configuration if |
---|
| 3881 | + * necessary |
---|
| 3882 | + */ |
---|
| 3883 | + config = rtd->dai_link->params + rtd->params_select; |
---|
| 3884 | + if (WARN_ON(!config)) { |
---|
| 3885 | + dev_err(w->dapm->dev, "ASoC: link config missing\n"); |
---|
| 3886 | + ret = -EINVAL; |
---|
| 3887 | + goto out; |
---|
| 3888 | + } |
---|
3747 | 3889 | |
---|
3748 | 3890 | /* Be a little careful as we don't want to overflow the mask array */ |
---|
3749 | 3891 | if (config->formats) { |
---|
.. | .. |
---|
3751 | 3893 | } else { |
---|
3752 | 3894 | dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", |
---|
3753 | 3895 | config->formats); |
---|
3754 | | - fmt = 0; |
---|
3755 | | - } |
---|
3756 | 3896 | |
---|
3757 | | - /* Currently very limited parameter selection */ |
---|
3758 | | - params = kzalloc(sizeof(*params), GFP_KERNEL); |
---|
3759 | | - if (!params) { |
---|
3760 | | - ret = -ENOMEM; |
---|
| 3897 | + ret = -EINVAL; |
---|
3761 | 3898 | goto out; |
---|
3762 | 3899 | } |
---|
3763 | | - snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); |
---|
3764 | 3900 | |
---|
| 3901 | + snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); |
---|
3765 | 3902 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = |
---|
3766 | 3903 | config->rate_min; |
---|
3767 | 3904 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = |
---|
3768 | 3905 | config->rate_max; |
---|
3769 | | - |
---|
3770 | 3906 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min |
---|
3771 | 3907 | = config->channels_min; |
---|
3772 | 3908 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max |
---|
3773 | 3909 | = config->channels_max; |
---|
3774 | 3910 | |
---|
3775 | | - memset(&substream, 0, sizeof(substream)); |
---|
| 3911 | + substream->stream = SNDRV_PCM_STREAM_CAPTURE; |
---|
| 3912 | + snd_soc_dapm_widget_for_each_source_path(w, path) { |
---|
| 3913 | + source = path->source->priv; |
---|
3776 | 3914 | |
---|
3777 | | - /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */ |
---|
3778 | | - runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); |
---|
3779 | | - if (!runtime) { |
---|
3780 | | - ret = -ENOMEM; |
---|
3781 | | - goto out; |
---|
| 3915 | + ret = snd_soc_dai_hw_params(source, substream, params); |
---|
| 3916 | + if (ret < 0) |
---|
| 3917 | + goto out; |
---|
| 3918 | + |
---|
| 3919 | + dapm_update_dai_unlocked(substream, params, source); |
---|
3782 | 3920 | } |
---|
3783 | | - substream.runtime = runtime; |
---|
3784 | | - substream.private_data = rtd; |
---|
| 3921 | + |
---|
| 3922 | + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; |
---|
| 3923 | + snd_soc_dapm_widget_for_each_sink_path(w, path) { |
---|
| 3924 | + sink = path->sink->priv; |
---|
| 3925 | + |
---|
| 3926 | + ret = snd_soc_dai_hw_params(sink, substream, params); |
---|
| 3927 | + if (ret < 0) |
---|
| 3928 | + goto out; |
---|
| 3929 | + |
---|
| 3930 | + dapm_update_dai_unlocked(substream, params, sink); |
---|
| 3931 | + } |
---|
| 3932 | + |
---|
| 3933 | + runtime->format = params_format(params); |
---|
| 3934 | + runtime->subformat = params_subformat(params); |
---|
| 3935 | + runtime->channels = params_channels(params); |
---|
| 3936 | + runtime->rate = params_rate(params); |
---|
| 3937 | + |
---|
| 3938 | +out: |
---|
| 3939 | + kfree(params); |
---|
| 3940 | + return ret; |
---|
| 3941 | +} |
---|
| 3942 | + |
---|
| 3943 | +static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, |
---|
| 3944 | + struct snd_kcontrol *kcontrol, int event) |
---|
| 3945 | +{ |
---|
| 3946 | + struct snd_soc_dapm_path *path; |
---|
| 3947 | + struct snd_soc_dai *source, *sink; |
---|
| 3948 | + struct snd_pcm_substream *substream = w->priv; |
---|
| 3949 | + int ret = 0, saved_stream = substream->stream; |
---|
| 3950 | + |
---|
| 3951 | + if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || |
---|
| 3952 | + list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) |
---|
| 3953 | + return -EINVAL; |
---|
3785 | 3954 | |
---|
3786 | 3955 | switch (event) { |
---|
3787 | 3956 | case SND_SOC_DAPM_PRE_PMU: |
---|
3788 | | - substream.stream = SNDRV_PCM_STREAM_CAPTURE; |
---|
3789 | | - if (source->driver->ops->startup) { |
---|
3790 | | - ret = source->driver->ops->startup(&substream, source); |
---|
3791 | | - if (ret < 0) { |
---|
3792 | | - dev_err(source->dev, |
---|
3793 | | - "ASoC: startup() failed: %d\n", ret); |
---|
3794 | | - goto out; |
---|
3795 | | - } |
---|
3796 | | - source->active++; |
---|
3797 | | - } |
---|
3798 | | - ret = soc_dai_hw_params(&substream, params, source); |
---|
| 3957 | + ret = snd_soc_dai_link_event_pre_pmu(w, substream); |
---|
3799 | 3958 | if (ret < 0) |
---|
3800 | 3959 | goto out; |
---|
3801 | 3960 | |
---|
3802 | | - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; |
---|
3803 | | - if (sink->driver->ops->startup) { |
---|
3804 | | - ret = sink->driver->ops->startup(&substream, sink); |
---|
3805 | | - if (ret < 0) { |
---|
3806 | | - dev_err(sink->dev, |
---|
3807 | | - "ASoC: startup() failed: %d\n", ret); |
---|
3808 | | - goto out; |
---|
3809 | | - } |
---|
3810 | | - sink->active++; |
---|
3811 | | - } |
---|
3812 | | - ret = soc_dai_hw_params(&substream, params, sink); |
---|
3813 | | - if (ret < 0) |
---|
3814 | | - goto out; |
---|
3815 | 3961 | break; |
---|
3816 | 3962 | |
---|
3817 | 3963 | case SND_SOC_DAPM_POST_PMU: |
---|
3818 | | - ret = snd_soc_dai_digital_mute(sink, 0, |
---|
3819 | | - SNDRV_PCM_STREAM_PLAYBACK); |
---|
3820 | | - if (ret != 0 && ret != -ENOTSUPP) |
---|
3821 | | - dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret); |
---|
3822 | | - ret = 0; |
---|
| 3964 | + snd_soc_dapm_widget_for_each_sink_path(w, path) { |
---|
| 3965 | + sink = path->sink->priv; |
---|
| 3966 | + |
---|
| 3967 | + ret = snd_soc_dai_digital_mute(sink, 0, |
---|
| 3968 | + SNDRV_PCM_STREAM_PLAYBACK); |
---|
| 3969 | + if (ret != 0 && ret != -ENOTSUPP) |
---|
| 3970 | + dev_warn(sink->dev, |
---|
| 3971 | + "ASoC: Failed to unmute: %d\n", ret); |
---|
| 3972 | + ret = 0; |
---|
| 3973 | + } |
---|
3823 | 3974 | break; |
---|
3824 | 3975 | |
---|
3825 | 3976 | case SND_SOC_DAPM_PRE_PMD: |
---|
3826 | | - ret = snd_soc_dai_digital_mute(sink, 1, |
---|
3827 | | - SNDRV_PCM_STREAM_PLAYBACK); |
---|
3828 | | - if (ret != 0 && ret != -ENOTSUPP) |
---|
3829 | | - dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret); |
---|
3830 | | - ret = 0; |
---|
| 3977 | + snd_soc_dapm_widget_for_each_sink_path(w, path) { |
---|
| 3978 | + sink = path->sink->priv; |
---|
3831 | 3979 | |
---|
3832 | | - source->active--; |
---|
3833 | | - if (source->driver->ops->shutdown) { |
---|
3834 | | - substream.stream = SNDRV_PCM_STREAM_CAPTURE; |
---|
3835 | | - source->driver->ops->shutdown(&substream, source); |
---|
| 3980 | + ret = snd_soc_dai_digital_mute(sink, 1, |
---|
| 3981 | + SNDRV_PCM_STREAM_PLAYBACK); |
---|
| 3982 | + if (ret != 0 && ret != -ENOTSUPP) |
---|
| 3983 | + dev_warn(sink->dev, |
---|
| 3984 | + "ASoC: Failed to mute: %d\n", ret); |
---|
| 3985 | + ret = 0; |
---|
3836 | 3986 | } |
---|
3837 | 3987 | |
---|
3838 | | - sink->active--; |
---|
3839 | | - if (sink->driver->ops->shutdown) { |
---|
3840 | | - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; |
---|
3841 | | - sink->driver->ops->shutdown(&substream, sink); |
---|
| 3988 | + substream->stream = SNDRV_PCM_STREAM_CAPTURE; |
---|
| 3989 | + snd_soc_dapm_widget_for_each_source_path(w, path) { |
---|
| 3990 | + source = path->source->priv; |
---|
| 3991 | + snd_soc_dai_hw_free(source, substream); |
---|
3842 | 3992 | } |
---|
| 3993 | + |
---|
| 3994 | + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; |
---|
| 3995 | + snd_soc_dapm_widget_for_each_sink_path(w, path) { |
---|
| 3996 | + sink = path->sink->priv; |
---|
| 3997 | + snd_soc_dai_hw_free(sink, substream); |
---|
| 3998 | + } |
---|
| 3999 | + |
---|
| 4000 | + substream->stream = SNDRV_PCM_STREAM_CAPTURE; |
---|
| 4001 | + snd_soc_dapm_widget_for_each_source_path(w, path) { |
---|
| 4002 | + source = path->source->priv; |
---|
| 4003 | + snd_soc_dai_deactivate(source, substream->stream); |
---|
| 4004 | + snd_soc_dai_shutdown(source, substream, 0); |
---|
| 4005 | + } |
---|
| 4006 | + |
---|
| 4007 | + substream->stream = SNDRV_PCM_STREAM_PLAYBACK; |
---|
| 4008 | + snd_soc_dapm_widget_for_each_sink_path(w, path) { |
---|
| 4009 | + sink = path->sink->priv; |
---|
| 4010 | + snd_soc_dai_deactivate(sink, substream->stream); |
---|
| 4011 | + snd_soc_dai_shutdown(sink, substream, 0); |
---|
| 4012 | + } |
---|
| 4013 | + break; |
---|
| 4014 | + |
---|
| 4015 | + case SND_SOC_DAPM_POST_PMD: |
---|
| 4016 | + kfree(substream->runtime); |
---|
3843 | 4017 | break; |
---|
3844 | 4018 | |
---|
3845 | 4019 | default: |
---|
.. | .. |
---|
3848 | 4022 | } |
---|
3849 | 4023 | |
---|
3850 | 4024 | out: |
---|
3851 | | - kfree(runtime); |
---|
3852 | | - kfree(params); |
---|
| 4025 | + /* Restore the substream direction */ |
---|
| 4026 | + substream->stream = saved_stream; |
---|
3853 | 4027 | return ret; |
---|
3854 | 4028 | } |
---|
3855 | 4029 | |
---|
.. | .. |
---|
3857 | 4031 | struct snd_ctl_elem_value *ucontrol) |
---|
3858 | 4032 | { |
---|
3859 | 4033 | struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); |
---|
| 4034 | + struct snd_soc_pcm_runtime *rtd = w->priv; |
---|
3860 | 4035 | |
---|
3861 | | - ucontrol->value.enumerated.item[0] = w->params_select; |
---|
| 4036 | + ucontrol->value.enumerated.item[0] = rtd->params_select; |
---|
3862 | 4037 | |
---|
3863 | 4038 | return 0; |
---|
3864 | 4039 | } |
---|
.. | .. |
---|
3867 | 4042 | struct snd_ctl_elem_value *ucontrol) |
---|
3868 | 4043 | { |
---|
3869 | 4044 | struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); |
---|
| 4045 | + struct snd_soc_pcm_runtime *rtd = w->priv; |
---|
3870 | 4046 | |
---|
3871 | 4047 | /* Can't change the config when widget is already powered */ |
---|
3872 | 4048 | if (w->power) |
---|
3873 | 4049 | return -EBUSY; |
---|
3874 | 4050 | |
---|
3875 | | - if (ucontrol->value.enumerated.item[0] == w->params_select) |
---|
| 4051 | + if (ucontrol->value.enumerated.item[0] == rtd->params_select) |
---|
3876 | 4052 | return 0; |
---|
3877 | 4053 | |
---|
3878 | | - if (ucontrol->value.enumerated.item[0] >= w->num_params) |
---|
| 4054 | + if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_params) |
---|
3879 | 4055 | return -EINVAL; |
---|
3880 | 4056 | |
---|
3881 | | - w->params_select = ucontrol->value.enumerated.item[0]; |
---|
| 4057 | + rtd->params_select = ucontrol->value.enumerated.item[0]; |
---|
3882 | 4058 | |
---|
3883 | 4059 | return 1; |
---|
3884 | 4060 | } |
---|
.. | .. |
---|
3969 | 4145 | return NULL; |
---|
3970 | 4146 | } |
---|
3971 | 4147 | |
---|
3972 | | -int snd_soc_dapm_new_pcm(struct snd_soc_card *card, |
---|
3973 | | - struct snd_soc_pcm_runtime *rtd, |
---|
3974 | | - const struct snd_soc_pcm_stream *params, |
---|
3975 | | - unsigned int num_params, |
---|
3976 | | - struct snd_soc_dapm_widget *source, |
---|
3977 | | - struct snd_soc_dapm_widget *sink) |
---|
| 4148 | +static struct snd_soc_dapm_widget * |
---|
| 4149 | +snd_soc_dapm_new_dai(struct snd_soc_card *card, |
---|
| 4150 | + struct snd_pcm_substream *substream, |
---|
| 4151 | + char *id) |
---|
3978 | 4152 | { |
---|
| 4153 | + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
---|
3979 | 4154 | struct snd_soc_dapm_widget template; |
---|
3980 | 4155 | struct snd_soc_dapm_widget *w; |
---|
3981 | 4156 | const char **w_param_text; |
---|
3982 | | - unsigned long private_value; |
---|
| 4157 | + unsigned long private_value = 0; |
---|
3983 | 4158 | char *link_name; |
---|
3984 | 4159 | int ret; |
---|
3985 | 4160 | |
---|
3986 | 4161 | link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s", |
---|
3987 | | - source->name, sink->name); |
---|
| 4162 | + rtd->dai_link->name, id); |
---|
3988 | 4163 | if (!link_name) |
---|
3989 | | - return -ENOMEM; |
---|
| 4164 | + return ERR_PTR(-ENOMEM); |
---|
3990 | 4165 | |
---|
3991 | 4166 | memset(&template, 0, sizeof(template)); |
---|
3992 | 4167 | template.reg = SND_SOC_NOPM; |
---|
.. | .. |
---|
3994 | 4169 | template.name = link_name; |
---|
3995 | 4170 | template.event = snd_soc_dai_link_event; |
---|
3996 | 4171 | template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | |
---|
3997 | | - SND_SOC_DAPM_PRE_PMD; |
---|
| 4172 | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD; |
---|
3998 | 4173 | template.kcontrol_news = NULL; |
---|
3999 | 4174 | |
---|
4000 | 4175 | /* allocate memory for control, only in case of multiple configs */ |
---|
4001 | | - if (num_params > 1) { |
---|
4002 | | - w_param_text = devm_kcalloc(card->dev, num_params, |
---|
4003 | | - sizeof(char *), GFP_KERNEL); |
---|
| 4176 | + if (rtd->dai_link->num_params > 1) { |
---|
| 4177 | + w_param_text = devm_kcalloc(card->dev, |
---|
| 4178 | + rtd->dai_link->num_params, |
---|
| 4179 | + sizeof(char *), GFP_KERNEL); |
---|
4004 | 4180 | if (!w_param_text) { |
---|
4005 | 4181 | ret = -ENOMEM; |
---|
4006 | 4182 | goto param_fail; |
---|
.. | .. |
---|
4009 | 4185 | template.num_kcontrols = 1; |
---|
4010 | 4186 | template.kcontrol_news = |
---|
4011 | 4187 | snd_soc_dapm_alloc_kcontrol(card, |
---|
4012 | | - link_name, params, num_params, |
---|
| 4188 | + link_name, |
---|
| 4189 | + rtd->dai_link->params, |
---|
| 4190 | + rtd->dai_link->num_params, |
---|
4013 | 4191 | w_param_text, &private_value); |
---|
4014 | 4192 | if (!template.kcontrol_news) { |
---|
4015 | 4193 | ret = -ENOMEM; |
---|
.. | .. |
---|
4023 | 4201 | w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template); |
---|
4024 | 4202 | if (IS_ERR(w)) { |
---|
4025 | 4203 | ret = PTR_ERR(w); |
---|
4026 | | - /* Do not nag about probe deferrals */ |
---|
4027 | | - if (ret != -EPROBE_DEFER) |
---|
4028 | | - dev_err(card->dev, |
---|
4029 | | - "ASoC: Failed to create %s widget (%d)\n", |
---|
4030 | | - link_name, ret); |
---|
4031 | | - goto outfree_kcontrol_news; |
---|
4032 | | - } |
---|
4033 | | - if (!w) { |
---|
4034 | | - dev_err(card->dev, "ASoC: Failed to create %s widget\n", |
---|
4035 | | - link_name); |
---|
4036 | | - ret = -ENOMEM; |
---|
| 4204 | + dev_err(rtd->dev, "ASoC: Failed to create %s widget: %d\n", |
---|
| 4205 | + link_name, ret); |
---|
4037 | 4206 | goto outfree_kcontrol_news; |
---|
4038 | 4207 | } |
---|
4039 | 4208 | |
---|
4040 | | - w->params = params; |
---|
4041 | | - w->num_params = num_params; |
---|
4042 | | - w->priv = rtd; |
---|
| 4209 | + w->priv = substream; |
---|
4043 | 4210 | |
---|
4044 | | - ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL); |
---|
4045 | | - if (ret) |
---|
4046 | | - goto outfree_w; |
---|
4047 | | - return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL); |
---|
| 4211 | + return w; |
---|
4048 | 4212 | |
---|
4049 | | -outfree_w: |
---|
4050 | | - devm_kfree(card->dev, w); |
---|
4051 | 4213 | outfree_kcontrol_news: |
---|
4052 | 4214 | devm_kfree(card->dev, (void *)template.kcontrol_news); |
---|
4053 | | - snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text); |
---|
| 4215 | + snd_soc_dapm_free_kcontrol(card, &private_value, |
---|
| 4216 | + rtd->dai_link->num_params, w_param_text); |
---|
4054 | 4217 | param_fail: |
---|
4055 | 4218 | devm_kfree(card->dev, link_name); |
---|
4056 | | - return ret; |
---|
| 4219 | + return ERR_PTR(ret); |
---|
4057 | 4220 | } |
---|
4058 | 4221 | |
---|
4059 | 4222 | int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, |
---|
.. | .. |
---|
4076 | 4239 | template.name); |
---|
4077 | 4240 | |
---|
4078 | 4241 | w = snd_soc_dapm_new_control_unlocked(dapm, &template); |
---|
4079 | | - if (IS_ERR(w)) { |
---|
4080 | | - int ret = PTR_ERR(w); |
---|
4081 | | - |
---|
4082 | | - /* Do not nag about probe deferrals */ |
---|
4083 | | - if (ret != -EPROBE_DEFER) |
---|
4084 | | - dev_err(dapm->dev, |
---|
4085 | | - "ASoC: Failed to create %s widget (%d)\n", |
---|
4086 | | - dai->driver->playback.stream_name, ret); |
---|
4087 | | - return ret; |
---|
4088 | | - } |
---|
4089 | | - if (!w) { |
---|
4090 | | - dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", |
---|
4091 | | - dai->driver->playback.stream_name); |
---|
4092 | | - return -ENOMEM; |
---|
4093 | | - } |
---|
| 4242 | + if (IS_ERR(w)) |
---|
| 4243 | + return PTR_ERR(w); |
---|
4094 | 4244 | |
---|
4095 | 4245 | w->priv = dai; |
---|
4096 | 4246 | dai->playback_widget = w; |
---|
.. | .. |
---|
4105 | 4255 | template.name); |
---|
4106 | 4256 | |
---|
4107 | 4257 | w = snd_soc_dapm_new_control_unlocked(dapm, &template); |
---|
4108 | | - if (IS_ERR(w)) { |
---|
4109 | | - int ret = PTR_ERR(w); |
---|
4110 | | - |
---|
4111 | | - /* Do not nag about probe deferrals */ |
---|
4112 | | - if (ret != -EPROBE_DEFER) |
---|
4113 | | - dev_err(dapm->dev, |
---|
4114 | | - "ASoC: Failed to create %s widget (%d)\n", |
---|
4115 | | - dai->driver->playback.stream_name, ret); |
---|
4116 | | - return ret; |
---|
4117 | | - } |
---|
4118 | | - if (!w) { |
---|
4119 | | - dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", |
---|
4120 | | - dai->driver->capture.stream_name); |
---|
4121 | | - return -ENOMEM; |
---|
4122 | | - } |
---|
| 4258 | + if (IS_ERR(w)) |
---|
| 4259 | + return PTR_ERR(w); |
---|
4123 | 4260 | |
---|
4124 | 4261 | w->priv = dai; |
---|
4125 | 4262 | dai->capture_widget = w; |
---|
.. | .. |
---|
4135 | 4272 | struct snd_soc_dai *dai; |
---|
4136 | 4273 | |
---|
4137 | 4274 | /* For each DAI widget... */ |
---|
4138 | | - list_for_each_entry(dai_w, &card->widgets, list) { |
---|
| 4275 | + for_each_card_widgets(card, dai_w) { |
---|
4139 | 4276 | switch (dai_w->id) { |
---|
4140 | 4277 | case snd_soc_dapm_dai_in: |
---|
4141 | 4278 | case snd_soc_dapm_dai_out: |
---|
.. | .. |
---|
4154 | 4291 | dai = dai_w->priv; |
---|
4155 | 4292 | |
---|
4156 | 4293 | /* ...find all widgets with the same stream and link them */ |
---|
4157 | | - list_for_each_entry(w, &card->widgets, list) { |
---|
| 4294 | + for_each_card_widgets(card, w) { |
---|
4158 | 4295 | if (w->dapm != dai_w->dapm) |
---|
4159 | 4296 | continue; |
---|
4160 | 4297 | |
---|
.. | .. |
---|
4184 | 4321 | return 0; |
---|
4185 | 4322 | } |
---|
4186 | 4323 | |
---|
4187 | | -static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, |
---|
4188 | | - struct snd_soc_pcm_runtime *rtd) |
---|
| 4324 | +static void dapm_connect_dai_routes(struct snd_soc_dapm_context *dapm, |
---|
| 4325 | + struct snd_soc_dai *src_dai, |
---|
| 4326 | + struct snd_soc_dapm_widget *src, |
---|
| 4327 | + struct snd_soc_dapm_widget *dai, |
---|
| 4328 | + struct snd_soc_dai *sink_dai, |
---|
| 4329 | + struct snd_soc_dapm_widget *sink) |
---|
4189 | 4330 | { |
---|
4190 | | - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
---|
4191 | | - struct snd_soc_dapm_widget *sink, *source; |
---|
4192 | | - int i; |
---|
| 4331 | + dev_dbg(dapm->dev, "connected DAI link %s:%s -> %s:%s\n", |
---|
| 4332 | + src_dai->component->name, src->name, |
---|
| 4333 | + sink_dai->component->name, sink->name); |
---|
4193 | 4334 | |
---|
4194 | | - for (i = 0; i < rtd->num_codecs; i++) { |
---|
4195 | | - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
---|
| 4335 | + if (dai) { |
---|
| 4336 | + snd_soc_dapm_add_path(dapm, src, dai, NULL, NULL); |
---|
| 4337 | + src = dai; |
---|
| 4338 | + } |
---|
4196 | 4339 | |
---|
4197 | | - /* connect BE DAI playback if widgets are valid */ |
---|
4198 | | - if (codec_dai->playback_widget && cpu_dai->playback_widget) { |
---|
4199 | | - source = cpu_dai->playback_widget; |
---|
4200 | | - sink = codec_dai->playback_widget; |
---|
4201 | | - dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", |
---|
4202 | | - cpu_dai->component->name, source->name, |
---|
4203 | | - codec_dai->component->name, sink->name); |
---|
| 4340 | + snd_soc_dapm_add_path(dapm, src, sink, NULL, NULL); |
---|
| 4341 | +} |
---|
4204 | 4342 | |
---|
4205 | | - snd_soc_dapm_add_path(&card->dapm, source, sink, |
---|
4206 | | - NULL, NULL); |
---|
| 4343 | +static void dapm_connect_dai_pair(struct snd_soc_card *card, |
---|
| 4344 | + struct snd_soc_pcm_runtime *rtd, |
---|
| 4345 | + struct snd_soc_dai *codec_dai, |
---|
| 4346 | + struct snd_soc_dai *cpu_dai) |
---|
| 4347 | +{ |
---|
| 4348 | + struct snd_soc_dai_link *dai_link = rtd->dai_link; |
---|
| 4349 | + struct snd_soc_dapm_widget *dai, *codec, *playback_cpu, *capture_cpu; |
---|
| 4350 | + struct snd_pcm_substream *substream; |
---|
| 4351 | + struct snd_pcm_str *streams = rtd->pcm->streams; |
---|
| 4352 | + |
---|
| 4353 | + if (dai_link->params) { |
---|
| 4354 | + playback_cpu = cpu_dai->capture_widget; |
---|
| 4355 | + capture_cpu = cpu_dai->playback_widget; |
---|
| 4356 | + } else { |
---|
| 4357 | + playback_cpu = cpu_dai->playback_widget; |
---|
| 4358 | + capture_cpu = cpu_dai->capture_widget; |
---|
| 4359 | + } |
---|
| 4360 | + |
---|
| 4361 | + /* connect BE DAI playback if widgets are valid */ |
---|
| 4362 | + codec = codec_dai->playback_widget; |
---|
| 4363 | + |
---|
| 4364 | + if (playback_cpu && codec) { |
---|
| 4365 | + if (dai_link->params && !rtd->playback_widget) { |
---|
| 4366 | + substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream; |
---|
| 4367 | + dai = snd_soc_dapm_new_dai(card, substream, "playback"); |
---|
| 4368 | + if (IS_ERR(dai)) |
---|
| 4369 | + goto capture; |
---|
| 4370 | + rtd->playback_widget = dai; |
---|
4207 | 4371 | } |
---|
4208 | 4372 | |
---|
4209 | | - /* connect BE DAI capture if widgets are valid */ |
---|
4210 | | - if (codec_dai->capture_widget && cpu_dai->capture_widget) { |
---|
4211 | | - source = codec_dai->capture_widget; |
---|
4212 | | - sink = cpu_dai->capture_widget; |
---|
4213 | | - dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", |
---|
4214 | | - codec_dai->component->name, source->name, |
---|
4215 | | - cpu_dai->component->name, sink->name); |
---|
| 4373 | + dapm_connect_dai_routes(&card->dapm, cpu_dai, playback_cpu, |
---|
| 4374 | + rtd->playback_widget, |
---|
| 4375 | + codec_dai, codec); |
---|
| 4376 | + } |
---|
4216 | 4377 | |
---|
4217 | | - snd_soc_dapm_add_path(&card->dapm, source, sink, |
---|
4218 | | - NULL, NULL); |
---|
| 4378 | +capture: |
---|
| 4379 | + /* connect BE DAI capture if widgets are valid */ |
---|
| 4380 | + codec = codec_dai->capture_widget; |
---|
| 4381 | + |
---|
| 4382 | + if (codec && capture_cpu) { |
---|
| 4383 | + if (dai_link->params && !rtd->capture_widget) { |
---|
| 4384 | + substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream; |
---|
| 4385 | + dai = snd_soc_dapm_new_dai(card, substream, "capture"); |
---|
| 4386 | + if (IS_ERR(dai)) |
---|
| 4387 | + return; |
---|
| 4388 | + rtd->capture_widget = dai; |
---|
4219 | 4389 | } |
---|
| 4390 | + |
---|
| 4391 | + dapm_connect_dai_routes(&card->dapm, codec_dai, codec, |
---|
| 4392 | + rtd->capture_widget, |
---|
| 4393 | + cpu_dai, capture_cpu); |
---|
4220 | 4394 | } |
---|
4221 | 4395 | } |
---|
4222 | 4396 | |
---|
.. | .. |
---|
4226 | 4400 | struct snd_soc_dapm_widget *w; |
---|
4227 | 4401 | unsigned int ep; |
---|
4228 | 4402 | |
---|
4229 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
4230 | | - w = dai->playback_widget; |
---|
4231 | | - else |
---|
4232 | | - w = dai->capture_widget; |
---|
| 4403 | + w = snd_soc_dai_get_widget(dai, stream); |
---|
4233 | 4404 | |
---|
4234 | 4405 | if (w) { |
---|
4235 | 4406 | dapm_mark_dirty(w, "stream event"); |
---|
.. | .. |
---|
4263 | 4434 | void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) |
---|
4264 | 4435 | { |
---|
4265 | 4436 | struct snd_soc_pcm_runtime *rtd; |
---|
| 4437 | + struct snd_soc_dai *codec_dai; |
---|
| 4438 | + int i; |
---|
4266 | 4439 | |
---|
4267 | 4440 | /* for each BE DAI link... */ |
---|
4268 | | - list_for_each_entry(rtd, &card->rtd_list, list) { |
---|
| 4441 | + for_each_card_rtds(card, rtd) { |
---|
4269 | 4442 | /* |
---|
4270 | 4443 | * dynamic FE links have no fixed DAI mapping. |
---|
4271 | 4444 | * CODEC<->CODEC links have no direct connection. |
---|
4272 | 4445 | */ |
---|
4273 | | - if (rtd->dai_link->dynamic || rtd->dai_link->params || |
---|
4274 | | - rtd->dai_link->dynamic_be) |
---|
| 4446 | + if (rtd->dai_link->dynamic) |
---|
4275 | 4447 | continue; |
---|
4276 | 4448 | |
---|
4277 | | - dapm_connect_dai_link_widgets(card, rtd); |
---|
| 4449 | + if (rtd->num_cpus == 1) { |
---|
| 4450 | + for_each_rtd_codec_dais(rtd, i, codec_dai) |
---|
| 4451 | + dapm_connect_dai_pair(card, rtd, codec_dai, |
---|
| 4452 | + asoc_rtd_to_cpu(rtd, 0)); |
---|
| 4453 | + } else if (rtd->num_codecs == rtd->num_cpus) { |
---|
| 4454 | + for_each_rtd_codec_dais(rtd, i, codec_dai) |
---|
| 4455 | + dapm_connect_dai_pair(card, rtd, codec_dai, |
---|
| 4456 | + asoc_rtd_to_cpu(rtd, i)); |
---|
| 4457 | + } else { |
---|
| 4458 | + dev_err(card->dev, |
---|
| 4459 | + "N cpus to M codecs link is not supported yet\n"); |
---|
| 4460 | + } |
---|
4278 | 4461 | } |
---|
4279 | 4462 | } |
---|
4280 | 4463 | |
---|
4281 | 4464 | static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, |
---|
4282 | 4465 | int event) |
---|
4283 | 4466 | { |
---|
| 4467 | + struct snd_soc_dai *dai; |
---|
4284 | 4468 | int i; |
---|
4285 | 4469 | |
---|
4286 | | - soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); |
---|
4287 | | - for (i = 0; i < rtd->num_codecs; i++) |
---|
4288 | | - soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event); |
---|
| 4470 | + for_each_rtd_dais(rtd, i, dai) |
---|
| 4471 | + soc_dapm_dai_stream_event(dai, stream, event); |
---|
4289 | 4472 | |
---|
4290 | 4473 | dapm_power_widgets(rtd->card, event); |
---|
4291 | 4474 | } |
---|
.. | .. |
---|
4310 | 4493 | soc_dapm_stream_event(rtd, stream, event); |
---|
4311 | 4494 | mutex_unlock(&card->dapm_mutex); |
---|
4312 | 4495 | } |
---|
| 4496 | + |
---|
| 4497 | +void snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream) |
---|
| 4498 | +{ |
---|
| 4499 | + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
| 4500 | + if (snd_soc_runtime_ignore_pmdown_time(rtd)) { |
---|
| 4501 | + /* powered down playback stream now */ |
---|
| 4502 | + snd_soc_dapm_stream_event(rtd, |
---|
| 4503 | + SNDRV_PCM_STREAM_PLAYBACK, |
---|
| 4504 | + SND_SOC_DAPM_STREAM_STOP); |
---|
| 4505 | + } else { |
---|
| 4506 | + /* start delayed pop wq here for playback streams */ |
---|
| 4507 | + rtd->pop_wait = 1; |
---|
| 4508 | + queue_delayed_work(system_power_efficient_wq, |
---|
| 4509 | + &rtd->delayed_work, |
---|
| 4510 | + msecs_to_jiffies(rtd->pmdown_time)); |
---|
| 4511 | + } |
---|
| 4512 | + } else { |
---|
| 4513 | + /* capture streams can be powered down now */ |
---|
| 4514 | + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, |
---|
| 4515 | + SND_SOC_DAPM_STREAM_STOP); |
---|
| 4516 | + } |
---|
| 4517 | +} |
---|
| 4518 | +EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_stop); |
---|
4313 | 4519 | |
---|
4314 | 4520 | /** |
---|
4315 | 4521 | * snd_soc_dapm_enable_pin_unlocked - enable pin. |
---|
.. | .. |
---|
4581 | 4787 | } |
---|
4582 | 4788 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); |
---|
4583 | 4789 | |
---|
| 4790 | +void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, |
---|
| 4791 | + struct snd_soc_card *card, |
---|
| 4792 | + struct snd_soc_component *component) |
---|
| 4793 | +{ |
---|
| 4794 | + dapm->card = card; |
---|
| 4795 | + dapm->component = component; |
---|
| 4796 | + dapm->bias_level = SND_SOC_BIAS_OFF; |
---|
| 4797 | + |
---|
| 4798 | + if (component) { |
---|
| 4799 | + dapm->dev = component->dev; |
---|
| 4800 | + dapm->idle_bias_off = !component->driver->idle_bias_on, |
---|
| 4801 | + dapm->suspend_bias_off = component->driver->suspend_bias_off; |
---|
| 4802 | + } else { |
---|
| 4803 | + dapm->dev = card->dev; |
---|
| 4804 | + } |
---|
| 4805 | + |
---|
| 4806 | + INIT_LIST_HEAD(&dapm->list); |
---|
| 4807 | + /* see for_each_card_dapms */ |
---|
| 4808 | + list_add(&dapm->list, &card->dapm_list); |
---|
| 4809 | +} |
---|
| 4810 | +EXPORT_SYMBOL_GPL(snd_soc_dapm_init); |
---|
| 4811 | + |
---|
4584 | 4812 | static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) |
---|
4585 | 4813 | { |
---|
4586 | 4814 | struct snd_soc_card *card = dapm->card; |
---|
.. | .. |
---|
4590 | 4818 | |
---|
4591 | 4819 | mutex_lock(&card->dapm_mutex); |
---|
4592 | 4820 | |
---|
4593 | | - list_for_each_entry(w, &dapm->card->widgets, list) { |
---|
| 4821 | + for_each_card_widgets(dapm->card, w) { |
---|
4594 | 4822 | if (w->dapm != dapm) |
---|
4595 | 4823 | continue; |
---|
4596 | 4824 | if (w->power) { |
---|
.. | .. |
---|
4623 | 4851 | { |
---|
4624 | 4852 | struct snd_soc_dapm_context *dapm; |
---|
4625 | 4853 | |
---|
4626 | | - list_for_each_entry(dapm, &card->dapm_list, list) { |
---|
| 4854 | + for_each_card_dapms(card, dapm) { |
---|
4627 | 4855 | if (dapm != &card->dapm) { |
---|
4628 | 4856 | soc_dapm_shutdown_dapm(dapm); |
---|
4629 | 4857 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) |
---|